【问题标题】:Get row.name after grouping with data.table与data.table分组后获取row.name
【发布时间】:2013-07-22 13:27:53
【问题描述】:

我是 data.table 的新手,但我设法将 60 万行数据集中的计算从数千秒(使用 *ply 循环)减少到 1.7 秒。基本上,我需要同一 groupstart 的组中 class 列中值最低的行。我正在使用

DT[, list(class=min(class)), by=list(group, start)]

但要做到这一点,我只使用来自具有更多列的 data.frame 中的这 3 列创建了 DT。因此,为了将我的结果与原始 data.frame 合并,我正在考虑使用 row.name,因此我使用 row.name=TRUE 创建了 DT,这是我所拥有的一个示例:

   group   start     class     rn
 1:  A      4943         4      1
 2:  A      5030         0      2
 3:  A      5030         4      3
 4:  A      5030         2      4
 5:  A      5083         4      5
 6:  A      5083         3      6
 7:  B      5041         0      7
 8:  B      5041         1      8
 9:  B      5083         4      9
 ...

我想要的结果只是 rn 对应于最小 class 值:

   group   start     class     rn
 1:  A      4943         4      1
 2:  A      5030         0      2
 3:  A      5083         3      6
 4:  B      5041         0      7
 5:  B      5083         4      9
 ...

但如果我使用:

DT[, list(class=min(class)), by=list(group, start, rn)]

DT[, list(class=min(class), rn), by=list(group, start)]

我得到了所有的行,而不仅仅是 class 最小值的行。

补充问题

我可以使用我的命令使用 data.table sintax 获得组中每个类类型的案例计数吗?

   group   start     class     rn    class0    class1    class2    class3    class4
 1:  A      4943         4      1         0         0         0         0         1
 2:  A      5030         0      2         1         0         1         0         1
 3:  A      5083         3      6         0         0         0         1         1
 4:  B      5041         0      7         1         1         0         0         0
 5:  B      5083         4      9         0         0         0         0         1
 ...

【问题讨论】:

  • 我不太明白“额外的问题”。您能否详细解释一下这些 1 和 0 的值是如何填充到这些列中的,以及为什么是 class0 - class4?
  • 嗨,我想这有点令人困惑,因为类号对应于原始 data.frame 中的因素,我将它们转换为仅获得最小值(或您方法中的第一个)。我尝试做的额外工作是计算每个班级的每个班级有多少人。例如对于 group=="A" 和 start==5030 有 1'zero'、1'two' 和 1'four'
  • 好的,知道了。让我试试看能不能找到办法。
  • 我认为dt[, list(class=class[1], rn=rn[1], class0=length(class[class==0])), by=list(group, start)] 解决了!谢谢!
  • 是的,您可以手动为每个课程执行此操作(或者)您可以查看编辑 2 直接执行此操作。

标签: r data.table


【解决方案1】:

对于您的第一个问题,您基本上是在每个组上调用min。这不是必需的。如果您也对列class 进行排序(通过设置key),那么您可以使用mult="first" 功能直接选择最小的元素。也就是说,

setkey(dt, group, start, class)
dt[CJ(unique(group), unique(start)), mult="first", nomatch=0]
   group start class rn
1:     A  4943     4  1
2:     A  5030     0  2
3:     A  5083     3  6
4:     B  5041     0  7
5:     B  5083     4  9

或者,如果您不想在这里使用CJ,那么您可以这样做:

setkey(dt, group, start, class)
dt[, list(class=class[1], rn=rn[1]), by=list(group, start)]

编辑 2:

这是一个完整的答案:

dt.out <- dt[, c(list(class = class[1], rn=rn[1]), 
       {tt <- rep(0,5); tt[class+1] <- 1; as.list(tt)}), by=list(group, start)]
setnames(dt.out, 5:9, paste0("Class", 0:4))

   group start class rn Class0 Class1 Class2 Class3 Class4
1:     A  4943     4  1      0      0      0      0      1
2:     A  5030     0  2      1      0      1      0      1
3:     A  5083     3  6      0      0      0      1      1
4:     B  5041     0  7      1      1      0      0      0
5:     B  5083     4  9      0      0      0      0      1

【讨论】:

  • 谢谢!两种方法都工作得很好。我想我更喜欢第二个,因为我更清楚如何添加更多列。
  • 就清晰度而言,我最喜欢这个版本 - dt[, .SD[which.min(class)], by = list(group, start)](然后使用 .SDcols 调整你想要的 .SD
  • @eddi,我同意 w.r.t.明晰。问题是调用min可能代价高昂,例如,如果你有1e7 行和1e5 组。基本上你调用了那么多which.min。根据我的测试,设置键和拉出第一行总是更快。而且我厌恶.SD :)(再次是性能原因)。我尽量避免它。这就是答案混乱的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-18
  • 2019-02-16
  • 1970-01-01
  • 2016-11-12
  • 2012-10-23
  • 2020-07-02
  • 2017-03-17
相关资源
最近更新 更多