1

I have a matrix, and some cells are equal to 0. What I want to do is giving to these cells the same value from the cell which stays in the same row, but in the column before that.

I solved this problem with two for-loops, but as you know my solution is too slow because of nested for-loops.

Here is my little matrix, I gave to some cells 0 to show how my matrix looks like.

 set.seed(1)
 df <- matrix(data = rnorm(n = 20, mean = 0, sd = 1), nrow = 5, ncol=4)
    df[1,2] <- 0
    df[1,3] <- 0
    df[2,3] <- 0
    df[3,4] <- 0

and it is the solution that I found,

for(i in (1 : nrow(df))){
  for(j in (2 : ncol(df))){

    if (df[i,j] == 0){
      df[i,j] <- df[i,j-1]
    }
  }
}  

I would be very thankful, if somebody can find a more effective solution than I found.

denis
  • 5,580
  • 1
  • 13
  • 40
plotly_user
  • 111
  • 1
  • 4
  • The values in the first column can stay 0, if they are equals 0. – plotly_user Jan 09 '18 at 19:58
  • 1
    Replace zero with `NA`: `df[df == 0] <- NA`; Then use the answer here: [Function / Loop to Replace NA with values in adjacent columns in R](https://stackoverflow.com/questions/38463511/function-loop-to-replace-na-with-values-in-adjacent-columns-in-r), i.e. `t(zoo::na.locf(t(df)))` – Henrik Jan 09 '18 at 20:47
  • It was exactly what I wanted, thanks – plotly_user Jan 10 '18 at 12:35

2 Answers2

0

you don't need the if nor the first loop

  for(j in (2 : ncol(df))){
      df[df[,j] == 0,j] <- df[df[,j] == 0,j-1]
}  

df[,j] == 0 gives you directly a boolean vector fulfilling the condition.

           [,1]       [,2]       [,3]        [,4]
[1,] -0.6264538 -0.6264538 -0.6264538 -0.04493361
[2,]  0.1836433  0.4874291  0.4874291 -0.01619026
[3,] -0.8356286  0.7383247 -0.6212406 -0.62124058
[4,]  1.5952808  0.5757814 -2.2146999  0.82122120
[5,]  0.3295078 -0.3053884  1.1249309  0.59390132

as for the data.table solution, a more appropriate solution would be

for( i in 2:length(DT)){DT[get(names(DT)[i])==0,names(DT)[i]:= names(DT)[i-1]]}
denis
  • 5,580
  • 1
  • 13
  • 40
0

You could convert your matrix to a vector, change 0s to NAs (except when they are in the first column), and then use zoo::na.locf to forward non-NA values, before converting back to a matrix.

Data:

set.seed(66)
df = matrix(data = rnorm(n = 20, mean = 0, sd = 1), nrow = 5, ncol=4)
df[1,2] = 0; df[1,3] = 0; df[2,3] = 0; df[3,4] = 0


          [,1]        [,2]       [,3]       [,4]
[1,]  2.3239747  0.00000000  0.0000000  0.1839216
[2,]  0.2169771 -0.75670339  0.0000000 -0.2920561
[3,]  0.4181927  1.22775750 -0.3114876  0.0000000
[4,] -0.1909928 -0.17795667 -1.2965404  0.1051630
[5,] -0.3148384  0.03127497 -0.9456910  0.5171277

Method:

library(zoo)
v = as.vector(t(df))
firstcol = seq(1,by=ncol(df),length.out=nrow(df))
v[-firstcol][v[-firstcol]==0] = NA
res = matrix(na.locf(v),ncol=ncol(df),byrow=T)

          [,1]        [,2]       [,3]       [,4]
[1,]  2.3239747  2.32397466  2.3239747  0.1839216
[2,]  0.2169771 -0.75670339 -0.7567034 -0.2920561
[3,]  0.4181927  1.22775750 -0.3114876 -0.3114876
[4,] -0.1909928 -0.17795667 -1.2965404  0.1051630
[5,] -0.3148384  0.03127497 -0.9456910  0.5171277
Lamia
  • 3,845
  • 1
  • 12
  • 19