【问题标题】:Select data.table columns based on condition, within by根据条件选择 data.table 列,在 by
【发布时间】:2019-10-15 01:53:31
【问题描述】:

如果 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 和 age)?我想要一个可以返回的函数调用

    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 和时间的任意组合内包含两个以上值 > 1000 的列...

谢谢!

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    我如何(有效地)选择在 id 内不变的列(在本例中为 id 和 age)?

    可能是这样的:

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

    【讨论】:

    • 非常感谢您,chinsoon12。我真的很喜欢你的解决方案,但不幸的是我的例子还不够好。我现在添加了一个仅针对一个主题变化的 wt 列(这意味着当我们查找在“id”内没有变化的列时应该删除它)。然后,您的建议失败并返回错误:“j 不会为每个组计算相同数量的列”。我希望您能帮助调整您原本出色的建议。
    • 您对新数据集的预期输出是什么?
    • 我添加了预期的输出。抱歉不清楚。
    • 请看我自己的回复。我想把功劳归功于 chinsoon12,因为你向我展示了原理。但我也希望引导其他用户获得完整的答案。 @chinsoon12,您能否通过复制我的代码或提供您自己的方式来更新您的答案?
    【解决方案2】:

    这也可能是一种选择:

    按 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
    

    【讨论】:

    • 谢谢温佩尔。不过,您的建议并不笼统。处理 id 的方式特定于此示例。该解决方案应该足够通用,以便 by 变量可以是多列并且可以位于数据中的任何位置(您的建议假定它是第一列)。
    【解决方案3】:

    根据 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
    

    【讨论】:

      猜你喜欢
      • 2019-01-15
      • 1970-01-01
      • 2017-01-18
      • 2011-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-01
      • 2020-11-19
      相关资源
      最近更新 更多