Search code examples
rtidyverseigraph

Adding values to columns based on multiple conditions


I have 1 df as below

df <- data.frame(n1 = c(1,2,1,2,5,6,8,9,8,8),
                 n2 = c(100,1000,500,1,NA,NA,2,8,10,15),
                 n3 = c("a", "a", "a", NA, "b", "c",NA,NA,NA,NA),
                 n4 = c("red", "red", NA, NA, NA, NA,NA,NA,NA,NA))
df
  n1   n2   n3   n4
1  1  100    a  red
2  2 1000    a  red
3  1  500    a <NA>
4  2    1 <NA> <NA>
5  5   NA    b <NA>
6  6   NA    c <NA>
7  8    2 <NA> <NA>
8  9    8 <NA> <NA>
9  8   10 <NA> <NA>
9  8   15 <NA> <NA>

First, please see my desired output

df
  n1   n2   n3   n4
1  1  100    a  red
2  2 1000    a  red
3  1  500    a  red
4  2    1 <NA>  red
5  5   NA    b <NA>
6  6   NA    c <NA>
7  8    2 <NA>  red
8  9    8 <NA> red
9  8   10 <NA> red
9  8   15 <NA> red

I made this post before (Adding values to one columns based on conditions). However, I realized that I need to take one more column to solve my problem.

So, I would like to update/add the red in n4 by asking the conditions comming from n1, n2, n3. If n3 == "a", and values of n1 associated with a, then values of n4 that are the same row with values of n1 should be added with red (i.e. row 3,4th). At the same time, if values of n1 also match with that of n2 (i.e. 2), then this row th of n4 should also be added red. Further, 8 of column n1 is connected with the entire things like that. Then, if we have futher values of n2 or n1 is equal to 8 then, the step would be replicated as before. I hope it is clear, if not I would like to explain more. (It sounds like a Zig Zag thing).

-Note: tidyverse and baseR also welcomed to help me here.

Any suggestions for me please?


Solution

  • You can try the code below if you are using igraph

    res <- do.call(
      rbind,
      lapply(
        decompose(
          graph_from_data_frame(replace(df, is.na(df), "NA"))
        ),
        function(x) {
          n4 <- E(x)$n4
          if (!all(n4 == "NA")) {
            E(x)$n4 <- unique(n4[n4 != "NA"])
          }
          get.data.frame(x)
        }
      )
    )
    
    dfout <- type.convert(
      res[match(do.call(paste, df[1:2]), do.call(paste, res[1:2])), ],
      as.is = TRUE
    )
    

    which gives

    > dfout
       from   to   n3   n4
    1     1  100    a  red
    2     2 1000    a  red
    3     1  500    a  red
    4     2    1 <NA>  red
    9     5   NA    b <NA>
    10    6   NA    c <NA>
    5     8    2 <NA>  red
    6     9    8 <NA>  red
    7     8   10 <NA>  red
    8     8   15 <NA>  red