Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace each row based on the string match and column value

I have a dataset like this

dt <- data.table(Score = c(0.33,0.34,00.3, -0.22, 0.232), 
                 Id2 = c("0/0","0/1","1/0","0/0","0/0"), 
                 Kps = c("0/1","0/0","1/1","0/1","0/0"), 
                 Inr = c("0/0","0/1","1/1","0/0","0/1"))

I need to replace the values of each row based on the Score column as like this

  • If "0/0" or "1/1" then Score * 2
  • If "1/0" or "0/1" then Score

Usually, it can be done by using the base function like this

dt$Id2 <- dt$Score * 2

But here I have to consider each row and I have around 1000 columns so it can be only done with loop

The expected output

Score  Id2    Kps    Inr 
0.330  0.66   0.330  0.66
0.340  0.340  0.68  0.340
0.300  0.300  0.6   0.6
-0.220 -0.44 -0.22 -0.44
0.232  0.464 0.464  0.232

Any suggestions?

like image 695
ZenMac Avatar asked Sep 19 '25 07:09

ZenMac


2 Answers

As the input is data.table, here is one approach with data.table

library(data.table)
 dt[, (names(dt)[-1]) := lapply(.SD, \(x)
    fcase(x %chin% c("0/0", "1/1"), Score *2,
    x %chin% c("1/0", "0/1"), Score)), .SDcols = -1]

-output

> dt
    Score    Id2    Kps    Inr
1:  0.330  0.660  0.330  0.660
2:  0.340  0.340  0.680  0.340
3:  0.300  0.300  0.600  0.600
4: -0.220 -0.440 -0.220 -0.440
5:  0.232  0.464  0.464  0.232

Or another option is to make use of named vector

keyval <- setNames(c(2, 2, 1, 1), c("0/0", "1/1", "1/0", "0/1"))
dt[, (names(dt)[-1]) := lapply(.SD, \(x) Score *keyval[x]), .SDcols = -1]

-output

> dt
    Score    Id2    Kps    Inr
1:  0.330  0.660  0.330  0.660
2:  0.340  0.340  0.680  0.340
3:  0.300  0.300  0.600  0.600
4: -0.220 -0.440 -0.220 -0.440
5:  0.232  0.464  0.464  0.232

Or create a count of 1s and 0s to multiply

library(stringr)
dt[, (names(dt)[-1]) := lapply(.SD, \(x) Score * 1 + 
   (str_count(x, "0")!= 1)) , .SDcols = -1]
> dt
    Score   Id2    Kps   Inr
1:  0.330 1.330  0.330 1.330
2:  0.340 0.340  1.340 0.340
3:  0.300 0.300  1.300 1.300
4: -0.220 0.780 -0.220 0.780
5:  0.232 1.232  1.232 0.232
like image 75
akrun Avatar answered Sep 21 '25 23:09

akrun


Here is a tidyverse -way solution. It uses a data.frame and makes it longer in a first step. Then with case_when the different conditions were implemented.

pivot_wider brought it back to a wider format.

library(tidyverse)

dt<- data.frame(Score = c(0.33,0.34,00.3, -0.22, 0.232), 
                Id2=c("0/0","0/1","1/0","0/0","0/0"), 
                Kps=c("0/1","0/0","1/1","0/1","0/0"), 
                Inr=c("0/0","0/1","1/1","0/0","0/1"))


dt |> 
  pivot_longer(-Score) |> 
  mutate(value = case_when(
    value == '0/0' | value == "1/1" ~ Score *2,
    value == '1/0' | value == "0/1" ~ Score 
  )) |> 
  pivot_wider(names_from = name, values_from = value)
#> # A tibble: 5 × 4
#>    Score    Id2    Kps    Inr
#>    <dbl>  <dbl>  <dbl>  <dbl>
#> 1  0.33   0.66   0.33   0.66 
#> 2  0.34   0.34   0.68   0.34 
#> 3  0.3    0.3    0.6    0.6  
#> 4 -0.22  -0.44  -0.22  -0.44 
#> 5  0.232  0.464  0.464  0.232
like image 20
MarBlo Avatar answered Sep 21 '25 22:09

MarBlo