Home > Software design >  How to use a column of a matrix as index to change its values?
How to use a column of a matrix as index to change its values?

Time:08-08

Assume we have the following matrix :

M=structure(c(1, 2, 2, 2, 1, 3, 3, 4, 4, 6, 5, 5, 5, 6, 5, 5, 2, 
2, 4, 1, 3, 1, 6, 4, 2, 5, 1, 3, 4, 6, 0.849542987113752, 0.849542987113752, 
0.788371730579003, 0.788371730579003, 0.788371730579003, 0.788371730579003
), .Dim = c(6L, 6L), .Dimnames = list(NULL, c("", "", "", "", 
"index", "cum_detection")))

The matrix M is sorted according to its last row :

             index cum_detection
[1,] 1 3 5 4     2     0.8495430
[2,] 2 4 6 1     5     0.8495430
[3,] 2 4 5 3     1     0.7883717
[4,] 2 6 5 1     3     0.7883717
[5,] 1 5 2 6     4     0.7883717
[6,] 3 5 2 4     6     0.7883717

I'm searching to obtain this following output :

             index cum_detection
[1,] 1 3 5 4     2     0.8495430
[2,] 0 4 6 1     5     0.8495430
[3,] 0 4 0 3     1     0.7883717
[4,] 0 6 0 0     3     0.7883717
[5,] 0 0 0 6     4     0.7883717
[6,] 0 0 0 0     6     0.7883717

For each row , we search through columns from 1 to 4.

If we found a value that is equal to any of previous visited rows index values , we replace it by 0.

For example , consider the third row M[3,1:4] :

> M[3,1:4]
  2 4 5 3

The values 2 and 5 are already present in previous rows index column ( M[1:2,"index"]).

I believe the solution is something like :

 t(apply(M,1,function(x) replace(x,M[1:current_row-1,"index"],0))) 

Where current_row is the current row of apply loop. The problem here is that i don't know how to get apply current row index.

CodePudding user response:

We can loop over the sequence of rows from 'M' (starting from 2), then find if the columns 1:4 for that row is found %in% sequence of rows till the previous row (1:(i-1)) for 'index', then assign the values in those columns to 0

for(i in 2:nrow(M)) M[i, 1:4][M[i, 1:4] %in% M[1:(i-1), "index"]] <- 0

-output

> M
             index cum_detection
[1,] 1 3 5 4     2     0.8495430
[2,] 0 4 6 1     5     0.8495430
[3,] 0 4 0 3     1     0.7883717
[4,] 0 6 0 0     3     0.7883717
[5,] 0 0 0 6     4     0.7883717
[6,] 0 0 0 0     6     0.7883717

Or using dplyr

library(dplyr)
library(tibble)
 M %>%
   as_tibble %>%
   mutate(rn = row_number())  %>% 
   rowwise %>% 
   mutate(across(1:4, ~ replace(.x, .x %in% M[, "index"][
         seq_len(rn - 1)], 0)), rn = NULL) %>%
   ungroup
# A tibble: 6 × 6
     V1    V2    V3    V4 index cum_detection
  <dbl> <dbl> <dbl> <dbl> <dbl>         <dbl>
1     1     3     5     4     2         0.850
2     0     4     6     1     5         0.850
3     0     4     0     3     1         0.788
4     0     6     0     0     3         0.788
5     0     0     0     6     4         0.788
6     0     0     0     0     6         0.788
  • Related