Effectively create a displacement matrix

goal

I want to use a long vector of numbers to create a matrix where each column is a sequential offset (lag or start) of the original vector. If n is the maximum displacement, the matrix will have dimensions [length(vector), n * 2 + 1] (because we want displacements in both directions and turn on the displacement 0, that is, the Original vector).

Example

To illustrate, consider the following vector:

 test <- c(2, 8, 1, 10, 7, 5, 9, 3, 4, 6) [1] 2 8 1 10 7 5 9 3 4 6 

Expected Result

Now we create value offsets, say for n == 3 :

  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [1,] NA NA NA 2 8 1 10 [2,] NA NA 2 8 1 10 7 [3,] NA 2 8 1 10 7 5 [4,] 2 8 1 10 7 5 9 [5,] 8 1 10 7 5 9 3 [6,] 1 10 7 5 9 3 4 [7,] 10 7 5 9 3 4 6 [8,] 7 5 9 3 4 6 NA [9,] 5 9 3 4 6 NA NA [10,] 9 3 4 6 NA NA NA 

I am looking for an effective solution. data.table or tidyverse solutions are more than welcome.

Returning only rows that do not have NA (i.e. rows 4 through 7) is also fine.

Current solution

 lags <- lapply(3:1, function(x) dplyr::lag(test, x)) leads <- lapply(1:3, function(x) dplyr::lead(test, x)) l <- c(lags, test, leads) matrix(unlist(l), nrow = length(test)) 
+5
source share
3 answers

In the R base, you can use embed to get rows 4 through 7. However, you need to reverse the order of the columns.

 embed(test, 7)[, 7:1] [,1] [,2] [,3] [,4] [,5] [,6] [,7] [1,] 2 8 1 10 7 5 9 [2,] 8 1 10 7 5 9 3 [3,] 1 10 7 5 9 3 4 [4,] 10 7 5 9 3 4 6 

<strong> data

 test <- c(2, 8, 1, 10, 7, 5, 9, 3, 4, 6) 
+4
source

This will give you what you need ...

 n <- 3 t(embed(c(rep(NA,n), test, rep(NA,n)), length(test)))[length(test):1,] [,1] [,2] [,3] [,4] [,5] [,6] [,7] [1,] NA NA NA 2 8 1 10 [2,] NA NA 2 8 1 10 7 [3,] NA 2 8 1 10 7 5 [4,] 2 8 1 10 7 5 9 [5,] 8 1 10 7 5 9 3 [6,] 1 10 7 5 9 3 4 [7,] 10 7 5 9 3 4 6 [8,] 7 5 9 3 4 6 NA [9,] 5 9 3 4 6 NA NA [10,] 9 3 4 6 NA NA NA 
+3
source

This can be solved by constructing a matrix from a long vector and returning only the necessary columns and rows:

 test <- c(2, 8, 1, 10, 7, 5, 9, 3, 4, 6) n_offs <- 3L n_row <- length(test) + n_offs + 1L matrix(rep(c(rep(NA, n_offs), test), n_row), nrow = n_row)[1:length(test), 1:(n_offs * 2L + 1L)] 
  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [1,] NA NA NA 2 8 1 10 [2,] NA NA 2 8 1 10 7 [3,] NA 2 8 1 10 7 5 [4,] 2 8 1 10 7 5 9 [5,] 8 1 10 7 5 9 3 [6,] 1 10 7 5 9 3 4 [7,] 10 7 5 9 3 4 6 [8,] 7 5 9 3 4 6 NA [9,] 5 9 3 4 6 NA NA [10,] 9 3 4 6 NA NA NA 

A variant that returns only the same result as embed(test, 7)[, 7:1] :

 matrix(rep(test, length(test) + 1L), nrow = length(test) + 1L)[ seq_len(length(test) - 2L * n_offs), seq_len(n_offs * 2L + 1L)] 
  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [1,] 2 8 1 10 7 5 9 [2,] 8 1 10 7 5 9 3 [3,] 1 10 7 5 9 3 4 [4,] 10 7 5 9 3 4 6 
+1
source

Source: https://habr.com/ru/post/1269448/


All Articles