根据多个列和条件更新data.table

时间:2019-03-02 09:38:49

标签: r data.table

这是Efficient way to subset data.table based on value in any of selected columns的后续问题。

样本数据
我有一个包含5个p列的data.table,表示一个类型(type1或type2或NA)。 我也有5个r栏,表示得分(1-10,或NA)。

library(data.table)
set.seed(123)
v  <- c( "type1", "type2", NA_character_ )
v2 <- c( 1:10, rep( NA_integer_, 10 ) )
DT <- data.table( id = 1:100,
                  p1 = sample(v, 100, replace = TRUE ),
                  p2 = sample(v, 100, replace = TRUE ),
                  p3 = sample(v, 100, replace = TRUE ),
                  p4 = sample(v, 100, replace = TRUE ),
                  p5 = sample(v, 100, replace = TRUE ),
                  r1 = sample(v2, 100, replace = TRUE ),
                  r2 = sample(v2, 100, replace = TRUE ),
                  r3 = sample(v2, 100, replace = TRUE ),
                  r4 = sample(v2, 100, replace = TRUE ),
                  r5 = sample(v2, 100, replace = TRUE ))

所需的输出
我想创建两个新列(一个用于type1,一个用于type2),在其中我逐行检查是否在一个或多个p列中出现了type1 / type2,并且是否至少有一个对应的r列(p1- >检查r1,p2->检查r2等)包含一个值。

“手动”解决方案
可以像下面这样使用很多AND和OR语句来完成此操作:

manual_solution <- DT[ ( p1 == "type1" & !is.na( r1 ) ) |
                         ( p2 == "type1" & !is.na( r2 ) ) |
                         ( p3 == "type1" & !is.na( r3 ) ) |
                         ( p4 == "type1" & !is.na( r4 ) ) |
                         ( p5 == "type1" & !is.na( r5 ) ), 
                       type1_present := "yes"]
manual_solution <- DT[ ( p1 == "type2" & !is.na( r1 ) ) |
                         ( p2 == "type2" & !is.na( r2 ) ) |
                         ( p3 == "type2" & !is.na( r3 ) ) |
                         ( p4 == "type2" & !is.na( r4 ) ) |
                         ( p5 == "type2" & !is.na( r5 ) ), 
                       type2_present := "yes"]
manual_solution[ is.na( type1_present ), type1_present := "no" ]
manual_solution[ is.na( type2_present ), type2_present := "no" ]

问题:数十个p和r列的自动化
但是,看看Efficient way to subset data.table based on value in any of selected columns的答案,我相信还有更好的方法。尤其是由于我的生产数据包含更多的p列和r列。

所以我开始玩耍,但是很快就卡住了...

#build vectors p-columns and r-columns
p_cols <- grep( "^p", names( DT ), value = TRUE )
r_cols <- grep( "^r", names( DT ), value = TRUE )

#create logical vectors to test for NA
logi_p <- as.data.table( sapply( DT[, ..p_cols ], function(x) !is.na(x) ) )
logi_r <- as.data.table( sapply( DT[, ..r_cols ], function(x) !is.na(x) ) )

#which non-NA p-values also have a non-NA r-value?
logi <- as.data.table( sapply( logi_p * logi_r, as.logical ) )

现在我对如何进行没有任何启发。
有任何想法/建议吗?

奖金
我的主要重点是上面的问题。但是我的生产数据还包含更多类型(在p列中)...因此,按类型添加列(或可以转换为该结果)的解决方案将“用一只石头杀死两只鸟”。

1 个答案:

答案 0 :(得分:0)

这里是一种解决方案,其中我将类型列转换为矩阵,并使用awk列中的信息对其进行更新,然后在其上应用搜索相关类型的次数为要查找的类型的次数。

awk

额外

使用r可以执行以下操作。管道只是为了提高可读性,其中一些步骤可能可以简化。

# Convert to a matrix
pMAT <- DT[, as.matrix(.SD), .SDcols = patterns("^p")]
# Subset a matrix with another matrix of the r columns
pMAT[] <- pMAT[DT[, as.logical(as.matrix(.SD)), .SDcols = patterns("^r")]]

types2check <- c("type1", "type2")
for (t in types2check) {
  set(
    x = DT, 
    j = paste0(t, "_present"), 
    value = ifelse(apply(pMAT, 1, function(x) any(x == t, na.rm = TRUE)), "yes", "no")
  )
}