R data.table循环遍历列以有条件地替换行值

时间:2018-05-03 05:48:33

标签: r data.table

寻找一个非常简单的解决方案。如果满足给定条件(小于零),我想有条件地替换行中的值,并且我想对数百个(在示例中为20个)的列中执行此操作,每个列具有1.5亿行。我在第七小时尝试了我在堆栈中找到的每个解决方案,所以请不要将其标记为重复。 :-)

数据:

library(data.table)
library(dplyr)
dt <- data.table(id=c(1:1000), x=rnorm(1:1000,60,20))

使用直观的循环创建新列:

## Create new variables
for(i in 50:70) {
  dt[, paste0("y", i) := i-x]
}

对单个列进行简单命令,效果很好:

dt$y60[dt$y60<0 ] <- 0

将其置于循环内部并失败:

for(i in 50:70) {
  dt$y[i][dt$y[i]<0] <- 0
}

简单的DT方法应该是什么,没有运气:

for(i in 50:70) {
  dt[y[i]<0, y[i] := 0]
}

尝试ifelse()方法,没有运气:

for(i in 50:70) {
  dt$y[i] <- ifelse(dt$y[i] < 0, 0, dt$y[i])
}

首先尝试创建一个列表,然后使用set(),不要骰子:

list <- dt %>% dplyr:: select(starts_with("y"))
for(i in 50:70) {
  set(dt, i, list , 0)
}

我的生命在你手中,谢谢!!

2 个答案:

答案 0 :(得分:2)

选项1使用:=

dt[, (paste0("y", 50:70)) := lapply(.SD, function(x) {x[x<0] <- 0; x}), .SDcols=paste0("y", 50:70)]

选项2使用set

for (j in paste0("y", 50:70)) {
    set(dt, dt[,which(get(j) < 0)], j, 0)
}

数据:

library(data.table)
dt <- data.table(id=c(1:1000), x=rnorm(1:1000,60,20))
for(i in 50:70) {
    dt[, paste0("y", i) := i-x]
}

答案 1 :(得分:1)

如果您需要更改以y开头的列值,则解决方案可以是mutate_at仅对所选列执行检查:

library(dplyr)
dt %>% mutate_at(vars(starts_with("y")), funs(ifelse(.<0,0,.)))

如果你想对所有列进行检查,那么下面的行应该足够好了:

dt[dt<0] <- 0