Smoothing a 2D matrix with rollmean, filter, rollapply or other R facilities by moving average sliding window method

百般思念 提交于 2019-12-07 19:05:09

问题


I am trying to find a function in R which smooths a 2D matrix which is already padded by zero around the matrix depending on the length of the window. If the window size is 3 then we pas 3 zeros from the top, bottom, right and left and then we do the averaging to smooth it. I found rollmean in SO and other tutorials but it doesn't exactly do what I want. I need (say if the window size is 3) we consider a window of 3*3 and take the average and replace it by the current elements of the current window and then move the window to the right by one unit (pixel). And for example when we reach the rightmost end, we start windowing by coming one unit down from the leftmost corner. This is what rollmean do which I don't want. I want all my 9 elements to be preserved.

> xm<-matrix(c(1,2,3,4,5,6,7,8,9),ncol=3)
> xm
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
> rollmean(xm,3)
     [,1] [,2] [,3]
[1,]    2    5    8

So here's the padding function as described above:

mat.pad<-function(X,k){
  dims<-dim(X)
  n<-dims[1]
  m<-dims[2]
  pad.X <- matrix(0, n + 2 * k, m + 2 * k)
  pad.X[(k + 1):(n + k), (k + 1):(m + k)] <- X
  return(pad.X)
}

So imagine that this is my X:

> X
      [,1] [,2] [,3]
 [1,]  0.5  0.3  0.2
 [2,]  0.5  0.4  0.1
 [3,]  0.4  0.4  0.3
 [4,]  0.4  0.3  0.3
 [5,]  0.3  0.2  0.2
 [6,]  0.5  0.2  0.2
 [7,]  0.5  0.4  0.1
 [8,]  0.4  0.4  0.5
 [9,]  0.3  0.3  0.5

and here's the padded version with k=3 (window =3*3)

> mat.pad(X,3)
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
 [1,]    0    0    0  0.0  0.0  0.0    0    0    0
 [2,]    0    0    0  0.0  0.0  0.0    0    0    0
 [3,]    0    0    0  0.0  0.0  0.0    0    0    0
 [4,]    0    0    0  0.5  0.3  0.2    0    0    0
 [5,]    0    0    0  0.5  0.4  0.1    0    0    0
 [6,]    0    0    0  0.4  0.4  0.3    0    0    0
 [7,]    0    0    0  0.4  0.3  0.3    0    0    0
 [8,]    0    0    0  0.3  0.2  0.2    0    0    0
 [9,]    0    0    0  0.5  0.2  0.2    0    0    0
[10,]    0    0    0  0.5  0.4  0.1    0    0    0
[11,]    0    0    0  0.4  0.4  0.5    0    0    0
[12,]    0    0    0  0.3  0.3  0.5    0    0    0
[13,]    0    0    0  0.0  0.0  0.0    0    0    0
[14,]    0    0    0  0.0  0.0  0.0    0    0    0
[15,]    0    0    0  0.0  0.0  0.0    0    0    0

How can I slide the window of averaging also?


回答1:


I'm not sure I got the idea but I think it could be approached with raster::focal?. See this post

library(raster)
x <- matrix(c(1,2,3,4,5,6,7,8,9),ncol=3)
x
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

r <- raster(x) # convert to rasterLayer
## sliding a 3x3 window
agg <- as.matrix(focal(r, matrix(1, 3, 3), mean, pad = T, padValue = 0))
agg

         [,1]     [,2]     [,3]
[1,] 1.333333 3.000000 2.666667
[2,] 2.333333 5.000000 4.333333
[3,] 1.777778 3.666667 3.111111

Running on your example

x2 <- mat.pad(X=x, 3)
r2 <- raster(x2)
as.matrix(focal(r2, matrix(1, 3, 3), mean, pad = T, padValue = 0))
      [,1] [,2]      [,3]      [,4]     [,5]     [,6]      [,7] [,8] [,9]
 [1,]    0    0 0.0000000 0.0000000 0.000000 0.000000 0.0000000    0    0
 [2,]    0    0 0.0000000 0.0000000 0.000000 0.000000 0.0000000    0    0
 [3,]    0    0 0.1111111 0.5555556 1.333333 1.222222 0.7777778    0    0
 [4,]    0    0 0.3333333 1.3333333 3.000000 2.666667 1.6666667    0    0
 [5,]    0    0 0.6666667 2.3333333 5.000000 4.333333 2.6666667    0    0
 [6,]    0    0 0.5555556 1.7777778 3.666667 3.111111 1.8888889    0    0
 [7,]    0    0 0.3333333 1.0000000 2.000000 1.666667 1.0000000    0    0
 [8,]    0    0 0.0000000 0.0000000 0.000000 0.000000 0.0000000    0    0
 [9,]    0    0 0.0000000 0.0000000 0.000000 0.000000 0.0000000    0    0


来源:https://stackoverflow.com/questions/23622379/smoothing-a-2d-matrix-with-rollmean-filter-rollapply-or-other-r-facilities-by

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!