我有一个有很多列的data.table。我需要遍历它们并使用某种条件创建新列。目前,我正在为每列写单独的条件行。让我用一个例子来解释。让我们考虑一个样本数据为-
set.seed(71)
DT <- data.table(town = rep(c('A','B'), each=10),
tc = rep(c('C','D'), 10),
one = rnorm(20,1,1),
two = rnorm(20,2,1),
three = rnorm(20,3,1),
four = rnorm(20,4,1),
five = rnorm(20,5,2),
six = rnorm(20,6,2),
seven = rnorm(20,7,2),
total = rnorm(20,28,3))
对于从一列到总数的每一列,我需要创建4个新列,即用于2 sigma离群值计算的均值,sd,上限,下限。我正在这样做-
DTnew <- DT[, as.list(unlist(lapply(.SD, function(x) list(mean = mean(x), sd = sd(x), uplimit = mean(x)+1.96*sd(x), lowlimit = mean(x)-1.96*sd(x))))), by = .(town,tc)]
然后将这个DTnew data.table与DT合并
DTmerge <- merge(DT, DTnew, by= c('town','tc'))
现在提出异常值,我为每个变量编写了单独的代码集-
DTAoutlier <- DTmerge[ ,one.Aoutlier := ifelse (one >= one.lowlimit & one <= one.uplimit,0,1)]
DTAoutlier <- DTmerge[ ,two.Aoutlier := ifelse (two >= two.lowlimit & two <= two.uplimit,0,1)]
DTAoutlier <- DTmerge[ ,three.Aoutlier := ifelse (three >= three.lowlimit & three <= three.uplimit,0,1)]
可以帮助简化这段代码,以便
我不必为异常值编写单独的代码行。在此示例中,我们只有8个变量,但是如果我们有100个变量,最终会写100行代码吗?可以使用for循环来完成此操作吗?如何?
通常,对于data.table,我们如何添加保留原始列的新列。因此,例如在下面的示例中,我记录第3到10列的日志。如果不创建新的DTlog,它将覆盖DT中的原始列。如何在DT中保留原始列并在DT中保留新列。
DTlog <- DT[,(lapply(.SD,log)),by = .(town,tc),.SDcols=3:10]
期待一些专家的建议。
我们可以使用来做到这一点:=
。我们对不是分组变量('nm')的列名进行子集化。vector
使用outer
('nm1')创建名称以分配给新列。然后,我们使用OP的代码,unlist
输出并将其分配(:=
)到'nm1'以创建新列。
nm <- names(DT)[-(1:2)]
nm1 <- c(t(outer(c("Mean", "SD", "uplimit", "lowlimit"), nm, paste, sep="_")))
DT[, (nm1):= unlist(lapply(.SD, function(x) { Mean = mean(x)
SD = sd(x)
uplimit = Mean + 1.96*SD
lowlimit = Mean - 1.96*SD
list(Mean, SD, uplimit, lowlimit) }), recursive=FALSE) ,
.(town, tc)]
问题的第二部分涉及在列之间进行逻辑比较。一种选择是分别对初始列,“ lowlimit”和“ uplimit”列进行子集并进行比较(因为它们具有相同的维),以获得可以用强制转换为二进制的逻辑输出+
。然后将其分配给原始数据集以创建异常值列。
m1 <- +(DT[, nm, with = FALSE] >= DT[, paste("lowlimit", nm, sep="_"),
with = FALSE] & DT[, nm, with = FALSE] <= DT[,
paste("uplimit", nm, sep="_"), with = FALSE])
DT[,paste(nm, "Aoutlier", sep=".") := as.data.frame(m1)]
或者,除了比较data.tables之外,我们还可以使用for
循环set
(这样会更有效)
nm2 <- paste(nm, "Aoutlier", sep=".")
DT[, (nm2) := NA_integer_]
for(j in nm){
set(DT, i = NULL, j = paste(j, "Aoutlier", sep="."),
value = as.integer(DT[[j]] >= DT[[paste("lowlimit", j, sep="_")]] &
DT[[j]] <= DT[[paste("uplimit", j, sep="_")]]))
}
“日志”列也可以使用 :=
DT[,paste(nm, "log", sep=".") := lapply(.SD,log),by = .(town,tc),.SDcols=nm]
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句