I'd like to create a multidimensional rolling window in r. Here is an example that I did in Python using xarray library and its rolling function, which is very intuitive and easy:
import xarray as xr
import numpy as np
data = xr.DataArray(np.arange(0,18).reshape(3,3,2))
print(data)
<xarray.DataArray (dim_0: 3, dim_1: 3, dim_2: 2)>
array([[[ 0, 1],
[ 2, 3],
[ 4, 5]],
[[ 6, 7],
[ 8, 9],
[10, 11]],
[[12, 13],
[14, 15],
[16, 17]]])
#Now the constructing the rolling window
win_size = 3 # Window size
data_roll = data.rolling(
dim_0=win_size, dim_1=win_size, center=True).construct(
dim_0="new_dim0", dim_1="newdim1")
print(data_roll)
<xarray.DataArray (dim_0: 3, dim_1: 3, dim_2: 2, new_dim0: 3, newdim1: 3)>
array([[[[[nan, nan, nan],
[nan, 0., 2.],
[nan, 6., 8.]],
[[nan, nan, nan],
[nan, 1., 3.],
[nan, 7., 9.]]],
[[[nan, nan, nan],
[ 0., 2., 4.],
[ 6., 8., 10.]],
[[nan, nan, nan],
[ 1., 3., 5.],
[ 7., 9., 11.]]],
[[[nan, nan, nan],
[ 2., 4., nan],
...
Note that this function pads the matrix in all dimensions with NAs before rolling. I looked up a couple of functions in R packages, such as rollapply. Most of these functions and suggested methods are either for applying a function on a 1d or, at best 2d array. However, all I need is the actual windows. I wonder how I can get the same results in R?
Thanks
CodePudding user response:
Have you tried using the package reticulate? If you want something specific in Python, it allows you to use anything in Python in R. Replace the period with the dollar sign, otherwise, it's nearly the same (other than package import).
library(reticulate)
np <- import("numpy", convert = F)
xr <- import("xarray", convert = F)
data = xr$DataArray(np$arange(0,18)$reshape(3L,3L,2L))
data
# <xarray.DataArray (dim_0: 3, dim_1: 3, dim_2: 2)>
# array([[[ 0., 1.],
# [ 2., 3.],
# [ 4., 5.]],
#
# [[ 6., 7.],
# [ 8., 9.],
# [10., 11.]],
#
# [[12., 13.],
# [14., 15.],
# [16., 17.]]])
# Dimensions without coordinates: dim_0, dim_1, dim_2
CodePudding user response:
Okay, so I just realized how simple this was to do with just base R. (I feel sheepish!)
(data2 <- array(1:18, dim = c(3, 2, 3)))
# , , 1
#
# [,1] [,2]
# [1,] 1 4
# [2,] 2 5
# [3,] 3 6
#
# , , 2
#
# [,1] [,2]
# [1,] 7 10
# [2,] 8 11
# [3,] 9 12
#
# , , 3
#
# [,1] [,2]
# [1,] 13 16
# [2,] 14 17
# [3,] 15 18
#
If you weren't aware, encapsulating the entire thing in () will cause it to create the object and print simultaneously.
CodePudding user response:
Ok, after spending some time I came up with an answer for my specific problem. The function I wrote is just good for a 3d matrix and I think there are better ways to improve it:
rolling_win <- function(v,win) {
# This function pad a 3d matrix and returns the overlapping windows in a list
# Inputs are:
#v: the original matrix
#win: the window size
mylist <- c()
padded_data <- array(numeric(),c(dim(v)[1] win*2,dim(v)[2] win*2,dim(v)[3])) # pad data
padded_data[(win 1):(dim(padded_data)[1]-win),(win 1):(dim(padded_data)[2]-win),]<-v
counter = 1
for (i in (1 win):(dim(padded_data)[1]-win)){
for (j in (1 win):(dim(padded_data)[2]-win)){
a <- padded_data[(i-win):(i win),(j-win):(j win),]
mylist[[counter]]<-a
counter = counter 1
}
}
return(mylist)
}
# lets test it on a simple 3*3*2 matrix
v = seq(1:18)
dim(v) = c(3,3,2)
win=1
print(v)
, , 1
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
, , 2
[,1] [,2] [,3]
[1,] 10 13 16
[2,] 11 14 17
[3,] 12 15 18
# Apply the function
windows <- rolling_win(v,win)
#Lets take a look at the first element
windows[1]
, , 1
[,1] [,2] [,3]
[1,] NA NA NA
[2,] NA 1 4
[3,] NA 2 5
, , 2
[,1] [,2] [,3]
[1,] NA NA NA
[2,] NA 10 13
[3,] NA 11 14
While this function works fine for my case but obviously it is not efficient. In case the matrix is big (millions of elements) then this simply would not work. Numpy in Python uses the stride concept which is way more efficient. I am new to R and am not sure if R can use same concept or not. Also, the generalizability is another problem here.
