gpt4 book ai didi

r - 循环遍历 data.table 并根据某些条件创建新列

转载 作者:行者123 更新时间:2023-12-02 11:12:23 26 4
gpt4 key购买 nike

我有一个包含相当多列的 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 离群值计算。我这样做是通过-

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)]

有人可以帮助简化这段代码,以便

  1. 我不必为异常值编写单独的代码行。在这个例子中,我们只有 8 个变量,但如果有 100 个变量,我们最终会编写 100 行代码吗?这可以使用 for 循环来完成吗?怎么办?

  2. 一般来说,对于 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)]

或者我们也可以使用for来代替比较data.tables循环 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]

关于r - 循环遍历 data.table 并根据某些条件创建新列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37339027/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com