基于data.table,DT,带有m个字符串列,如何标记字符串中的行,比如说“BlaBla”出现在至少一列中?
我想要的是:
DT[, flag_BlaBLa:=(test if "BlaBLa" appears in any column except the first one)]
我不想明确引用列名。相反,我需要将第2列引用到DT中的最大列号(可能是:2:ncol(DT)
)。为什么不?实际上,我有一个data.frames列表,每个都有不同数量的列。我需要为列表中的所有data.frames创建标志,如上所示
Edit1:添加可重现的示例。 Edit2:将一些'BlaBLa'字符串更改为'BlaBLa + something'。这也应该被视为匹配,因为它们包括'BlaBLa'。
DT以cols a,b,c
开头,我想要一个脚本来创建flag_BlaBLa
。最终结果将是:
DT <- data.table(a=c("x","y","z",'w'),
b=c('BlaBLa','BLe','Bli','BlaBLaSometing'),
c=c('Bla','BLe','BlaBLa','Blo'),
flag_BlaBLa=c(T,F,T,T)
)
对于列表,最终结果应该是:
DT1 <- data.table(a=c("x","y","z",'w'),
b=c('BlaBLa','BLe','Bli','BlaBLaSomething'),
c=c('Bla','BLe','BlaBLa','Blo'),
flag_BlaBLa=c(T,F,T,T)
)
DT2 <- data.table(a=c("q","j","p"),
b=c('BLe','Bli','BlaBLa'),
flag_BlaBLa=c(F,F,T)
)
l <- list(DT1,DT2)
我们可以遍历列表,选择列并检查任何行中是否存在至少一个“BlaBLa”并标记行TRUE
/ FALSE
。
library(data.table)
lapply(l, function(x) x[, flag_BlaBLa := rowSums(x[,2:ncol(x)] == "BlaBLa") > 0])
l
#[[1]]
# a b c flag_BlaBLa
#1: x BlaBLa Bla TRUE
#2: y BLe BLe FALSE
#3: z Bli BlaBLa TRUE
#4: w BlaBLa Blo TRUE
#[[2]]
# a b flag_BlaBLa
#1: q BLe FALSE
#2: j Bli FALSE
#3: p BlaBLa TRUE
编辑
如果它不是完全匹配并且我们需要找到该字符串的模式,我们也需要在使用rowSums
之前循环遍历列(类似于@MichaelChirico)
lapply(l, function(x) x[, flag_BlaBLa := rowSums(sapply(x[, 2:ncol(x)],
grepl, pattern = 'BlaBLa', fixed = TRUE)) > 0])
#[[1]]
# a b c flag_BlaBLa
#1: x BlaBLa Bla TRUE
#2: y BLe BLe FALSE
#3: z Bli BlaBLa TRUE
#4: w BlaBLaSomething Blo TRUE
#[[2]]
# a b flag_BlaBLa
#1: q BLe FALSE
#2: j Bli FALSE
#3: p BlaBLa TRUE
我们可以在.SDcols
中指定感兴趣的列,循环遍历data.table(.SD
)的子集,检查它是否等于'BlaBLa',Reduce
它是单个逻辑vector
来创建列
library(data.table)
lapply(l, function(x) x[, flag_BlaBLa := Reduce(`|`, lapply(.SD, `==`,
"BlaBLa")), .SDcols = 2:ncol(x)][])
#[[1]]
# a b c flag_BlaBLa
#1: x BlaBLa Bla TRUE
#2: y BLe BLe FALSE
#3: z Bli BlaBLa TRUE
#4: w BlaBLa Blo TRUE
#[[2]]
# a b flag_BlaBLa
#1: q BLe FALSE
#2: j Bli FALSE
#3: p BlaBLa TRUE
这是与.SDcols
的方法
require(dplyr)
require(data.table)
require(stringr)
DT <- DT[, key_ := do.call(paste, c(.SD, sep = "_")), .SDcols = 2:ncol(DT)]
DT <- DT[, has_blabla := as.integer(str_detect(key_, "BlaBla"))]
第一个创建一个键,每行的所有列值用'_'分隔。然后下一个搜索它并标记为二进制。搜索返回TRUE
或FALSE
,强制转换为整数时为二进制。
我会在列表上使用for
循环,在列上使用sapply
,使用.SDcols
排除第一个:
for (ii in seq_along(l)) {
l[[ii]][ , .SDcols = -1L,
flag_BlaBLa := any(sapply(.SD, grepl, pattern = 'BlaBLa', fixed = TRUE))]
}
请注意,由于您实际上并未使用任何正则表达式,因此fixed = TRUE
是使用grepl
的更有效选项。如果您要检测的模式确实是正则表达式,请删除fixed = TRUE
。
如果不是所有的列都是字符串列,那么通过使.SDcols
更严格,例如,可以提高效率。
.SDcols = intersect(2:ncols(l[[ii]]), which(sapply(l[[ii]], is.character)))
(或可能使用is.character(x) || is.factor(x)
)