data.table新增布尔列:判断指定列是否存在目标数值
解决data.table新增布尔列的问题
首先咱们先拆解下你的需求:要给data.table新增一列ac_12,逐行检查a列或者c列的当前行值是否等于12,只要其中一列满足就标记为TRUE,否则是FALSE。
你现有代码的问题
你写的这段代码:
val <- 12 cols <- c("a", "c") dt[, ac_12 := lapply(.SD, function(x) val %in% x), .SDcols = cols]
有两个核心问题:
- 判断逻辑错了:
val %in% x是检查val是否存在于整个列x中,不是逐行判断当前行的x值是否等于val。比如如果a列里有任何一个12,那整个a列对应的判断结果都会是TRUE,这和你要的逐行判断完全不符。 - 返回结构错了:
lapply(.SD, ...)会返回一个列表,每个元素对应.SDcols里的一列,所以这段代码会试图给dt添加两列(对应a和c的列判断),而不是合并成一个ac_12列,这就会导致赋值失败或者结果不符合预期。
正确的实现方式
这里有几种简单的写法,都能满足你的需求:
方法1:直接用逻辑或(最直观)
如果列数少,直接写逻辑判断最清晰:
val <- 12 dt[, ac_12 := (a == val) | (c == val)]
方法2:用.SD结合Reduce(适合列数多的情况)
如果以后要检查的列不止a和c,可以用.SD配合Reduce来合并逐行的判断结果:
val <- 12 cols <- c("a", "c") dt[, ac_12 := Reduce(`|`, lapply(.SD, function(x) x == val)), .SDcols = cols]
这里的逻辑是:
lapply(.SD, function(x) x == val):逐行检查每列是否等于val,得到一个包含两个布尔向量的列表(对应a和c列的逐行判断)Reduce(|, ...):把这两个布尔向量按行做“或”运算,合并成一个最终的布尔向量,赋值给ac_12
方法3:用rowSums(另一种简洁写法)
也可以用rowSums统计每行满足条件的列数,只要大于0就标记为TRUE:
val <- 12 cols <- c("a", "c") dt[, ac_12 := rowSums(.SD == val) > 0, .SDcols = cols]
.SD == val会生成一个布尔矩阵,rowSums统计每行的TRUE数量,只要有至少一个TRUE(数量>0)就返回TRUE。
验证结果
用你给的示例数据测试的话,这几种方法都能得到你期望的输出:
| a | b | c | ac_12 |
|---|---|---|---|
| 23 | 12 | 34 | FALSE |
| 12 | 56 | 43 | TRUE |
| 11 | 12 | 14 | FALSE |
| 13 | 23 | 6 | FALSE |
| 13 | 15 | 4 | FALSE |
| 12 | 23 | 56 | TRUE |
| 76 | 23 | 1 | FALSE |
| 2 | 9 | 22 | FALSE |
| 5 | 21 | 12 | TRUE |
| 12 | 65 | 31 | TRUE |
内容的提问来源于stack exchange,提问作者Wiktor Gustafsson
相关产品推荐
相关产品推荐

