1

I look for a R-code that transform the matrix as follows (a: the original matrix, b: the desired output), example:

a <- matrix(c(1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6), nrow = 6, ncol = 4)    
b <- matrix(c(1,2,3,4,5,6,2,3,4,5,6,0,3,4,5,6,0,0,4,5,6,0,0,0), nrow = 6, ncol = 4)

a
     [,1] [,2] [,3] [,4]
[1,]    1    1    1    1
[2,]    2    2    2    2
[3,]    3    3    3    3
[4,]    4    4    4    4
[5,]    5    5    5    5
[6,]    6    6    6    6

b
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    2    3    4    5
[3,]    3    4    5    6
[4,]    4    5    6    0
[5,]    5    6    0    0
[6,]    6    0    0    0 

Thus, the first column is not shifted, the second column is shifted up one step, the third column shifted up two steps, and so on. The shifted columns are padded with zeros.

The following links didn't help me (nor: double for-loop, a function with different variables, the codes diag or kronecker).

R: Shift values in single column of dataframe UP

r matrix individual shift operations of elements

Rotate a Matrix in R

Have you any ideas? Thanks.

Henrik
  • 65,555
  • 14
  • 143
  • 159
Olga
  • 25
  • 5
  • is there a common name for this operation? – IBrum Feb 24 '18 at 22:26
  • 1
    Looks a bit like this: [How to shift multiple cell values in a data.table](https://stackoverflow.com/questions/48955558/how-to-shift-multiple-cell-values-in-a-data-table) – Henrik Feb 24 '18 at 22:28

4 Answers4

0

I have a raw solution using sapply. You shift your column on each iteration of sapply, and then sapply concatenate all the output, that you can feed to matrix with the good size (the size of your initial matrix)

matrix(sapply(1:dim(a)[2], function(x){c(a[x:dim(a)[1], x], rep(0, (x - 1) ))}), ncol = dim(a)[2], nrow = dim(a)[1])

     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    2    3    4    5
[3,]    3    4    5    6
[4,]    4    5    6    0
[5,]    5    6    0    0
[6,]    6    0    0    0
Henrik
  • 65,555
  • 14
  • 143
  • 159
denis
  • 5,580
  • 1
  • 13
  • 40
0

This seems to work with data.table. Should perform well with a large matrix:

library(data.table)

# One way
dt[, shift(.SD, 0:3, 0, "lead", FALSE), .SDcols = 1]

# Alternatively
dt[, shift(dt, 0:3, 0, "lead", FALSE)][, 1:4]

Both return:

   V1 V2 V3 V4
1:  1  2  3  4
2:  2  3  4  5
3:  3  4  5  6
4:  4  5  6  0
5:  5  6  0  0
6:  6  0  0  0

Using the following data:

a <- matrix(c(1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6), nrow = 6, ncol = 4)

dt <- setDT(as.data.frame(a))
tyluRp
  • 4,678
  • 2
  • 17
  • 36
0

You can shift the columns by filling a matrix which have one row more than "a" with the values from "a" (a Warning is generated during the recycling). Select the original number of rows. Replace the lower right triangle with zeros.

nr <- nrow(a)
a2 <- matrix(a, ncol = ncol(a), nrow = nr + 1)[1:nr, ]

a2[col(a2) + row(a2) > nr + 1] <- 0
a2
#      [,1] [,2] [,3] [,4]
# [1,]    1    2    3    4
# [2,]    2    3    4    5
# [3,]    3    4    5    6
# [4,]    4    5    6    0
# [5,]    5    6    0    0
# [6,]    6    0    0    0
Henrik
  • 65,555
  • 14
  • 143
  • 159
0

Building on tyluRp's answer, which almost worked for me, I suggest to loop through all columns and call shift on each, individually. Let's start with a matrix of random numbers here:

a <- matrix(floor(10*runif(24)), ncol=4)

a
     [,1] [,2] [,3] [,4]
[1,]    8    4    8    3
[2,]    0    6    9    0
[3,]    1    6    0    7
[4,]    0    3    9    7
[5,]    2    4    2    9
[6,]    4    8    5    6

library(data.table)
dt <- setDT(as.data.frame(a))

Now the loop that does the job...

for (i in 2:length(dt)) dt[,i] <- shift(dt[,i,with=F],(i-1),0,"lead")

...by replacing columns with their shifted version.

The original answers replaced all columns by shifted copies of the first column, thus losing data. This is probably due to the group behaviour of data.table.

monomeric
  • 48
  • 5