根据条件选择data.table列

时间:2019-10-15 01:53:31

标签: r data.table

如果它们的内容符合条件,我想提取data.table列。我需要一种可以通过by(或以其他方式在列组合中)使用的方法。我对data.table的经验不是很丰富,并且在.SDcol和我能想到的其他方面已经尽力了。

示例:我经常有多个数据集,其中包含多个主题在多个时间点的观察结果。它们还包含在主题内没有变化的协变量。

dt1 <- data.table(
    id=c(1,1,2,2,3,3),
    time=c(1,2,1,2,1,2),
    meas=c(452,23,555,33,322,32),
    age=c(30,30,54,54,20,20),
    bw=c(75,75,81,81,69,70)
)

如何(有效地)选择ID(在这种情况下,ID和年龄)内不变的列?我想要一个返回的函数调用

    id age
1:  1  30
2:  2  54
3:  3  20

以及如何选择ID范围内不同的列(因此删除期限)?函数调用应返回:

   id time meas bw
1:  1    1  452 75
2:  1    2   23 75
3:  2    1  555 81
4:  2    2   33 81
5:  3    1  322 69
6:  3    2   32 70

当然,如果您知道一个可以解决上述特定示例的函数,我会很感兴趣,但是对于通常如何执行此操作,我感到更加好奇。在by =。(id,time)或其他任何形式的id和time的组合中包含两个以上> 1000的值的列。

谢谢!

3 个答案:

答案 0 :(得分:1)

  

如何(有效地)选择ID(在这种情况下,ID和年龄)内不变的列?

也许像这样:

f <- function(DT, byChar) {
    cols <- Reduce(intersect, DT[, .(.(names(.SD)[sapply(.SD, uniqueN)==1])), byChar]$V1)
    unique(DT[, c(byChar, cols), with=FALSE])
}
f(dt1, "id")

输出:

   id age
1:  1  30
2:  2  54
3:  3  20

  

以及如何选择ID范围内不同的列(因此删除期限)?

类似地,

f2 <- function(DT, byChar, k) {
    cols <- Reduce(intersect, DT[, .(.(names(.SD)[sapply(.SD, uniqueN)>k])), byChar]$V1)
    unique(DT[, c(byChar, cols), with=FALSE])
}
f2(dt1, "id", 1)

输出:

   id time meas
1:  1    1  452
2:  1    2   23
3:  2    1  555
4:  2    2   33
5:  3    1  322
6:  3    2   32

数据:

library(data.table)
dt1 <- data.table(
    id=c(1,1,2,2,3,3),
    time=c(1,2,1,2,1,2),
    meas=c(452,23,555,33,322,32),
    age=c(30,30,54,54,20,20),
    bw=c(75,75,81,81,69,70)
)

答案 1 :(得分:0)

这也可以是一个选择:

按ID(使用data.table::uniqueN)对每列的唯一值进行计数
检查哪些列的唯一值之和(按组)等于唯一ID的数量(使用colSums
只保留(或删除)所需的列

library(data.table)
ids <- uniqueN(dt1$id)
#no variation
dt1[, c( TRUE, colSums( dt1[, lapply( .SD, uniqueN ), by = id ][,-1]) == ids ), with = FALSE]

   id age
1:  1  30
2:  1  30
3:  2  54
4:  2  54
5:  3  20
6:  3  20

#variation
dt1[, c( TRUE, !colSums( dt1[, lapply( .SD, uniqueN ), by = id ][,-1]) == ids ), with = FALSE]

   id time meas bw
1:  1    1  452 75
2:  1    2   23 75
3:  2    1  555 81
4:  2    2   33 81
5:  3    1  322 69
6:  3    2   32 70

答案 2 :(得分:0)

根据chinsoon12的建议,我设法将一些东西放在一起。我需要四个步骤,我不确定它的效率如何,但至少可以完成工作。回顾一下,这是数据集:

dt1
   id time meas age bw
1:  1    1  452  30 75
2:  1    2   23  30 75
3:  2    1  555  54 81
4:  2    2   33  54 81
5:  3    1  322  20 69
6:  3    2   32  20 70

我将它们放在一起以获得“ id”(仅年龄)内恒定的列:

cols.id <- "id"
dt2 <- dt1[, .SD[, lapply(.SD, function(x)uniqueN(x)==1)], by=cols.id]
ifkeep <- dt2[,sapply(.SD,all),.SDcols=!(cols.id)]
keep <- c(cols.id,setdiff(colnames(dt2),cols.id)[ifkeep])
unique(dt1[,keep,with=F])
   id age
1:  1  30
2:  2  54
3:  3  20

并获取在任何“ id”值(年龄下降)内变化的列:

cols.id <- "id"
## differenct from above: ==1 -> >1
dt2 <- dt1[, .SD[, lapply(.SD, function(x)uniqueN(x)>1)], by=cols.id]
## difference from above: all -> any
ifkeep <- dt2[,sapply(.SD,any),.SDcols=!(cols.id)]
keep <- c(cols.id,setdiff(colnames(dt2),cols.id)[ifkeep])
unique(dt1[,keep,with=F])

   id time meas bw
1:  1    1  452 75
2:  1    2   23 75
3:  2    1  555 81
4:  2    2   33 81
5:  3    1  322 69
6:  3    2   32 70