使用聚合操作时如何避免在 data.table 中创建重复项

Posted

技术标签:

【中文标题】使用聚合操作时如何避免在 data.table 中创建重复项【英文标题】:How to avoid creation of duplicates in data.table when using aggregation operations 【发布时间】:2020-05-31 18:26:40 【问题描述】:

我正在使用data.table 对象来加快一些聚合操作。我的数据集的实际大小超过 1 亿行,因此我为这个问题包含了虚拟数据。我的data.table 对象是Sample3(我在最后一侧添加了dput() 版本),它由5 个变量组成:DateIdValueWeekDay。我想通过IdWeek 执行聚合任务,以计算Number:行数,Sum:值的总和,Avg:值的平均值和Diff:之间的差异Day 和最大 Date。我为该任务使用了下一个代码:

library(data.table)
#Compute
Summary <- Sample3[,.(Number=.N,Sum=sum(Value),Avg=mean(Value),
                                          Diff=Day-max(Date)),by = .(Id,Week)]  

计算是正确的,但是有一个问题,Summary 有重复的行,而根据IdWeek,所需的输出应该只有 1 个观察值。此外,Sample3 有 11 行,Summary 有相同的行数。我没有使用:= 运算符。这是我得到的输出:

       Id    Week Number       Sum      Avg   Diff
 1: 923996 48-2014      5 21.690579 4.338116 5 days
 2: 923996 48-2014      5 21.690579 4.338116 5 days
 3: 923996 48-2014      5 21.690579 4.338116 5 days
 4: 923996 48-2014      5 21.690579 4.338116 5 days
 5: 923996 48-2014      5 21.690579 4.338116 5 days
 6: 923996 49-2014      3 22.115795 7.371932 2 days
 7: 923996 49-2014      3 22.115795 7.371932 2 days
 8: 923996 49-2014      3 22.115795 7.371932 2 days
 9: 923996 50-2014      1  5.101146 5.101146 3 days
10: 923996 51-2014      2  6.086128 3.043064 1 days
11: 923996 51-2014      2  6.086128 3.043064 1 days

Summary 的正确输出应如下所示:

     Id    Week Number       Sum      Avg   Diff
1: 923996 48-2014      5 21.690579 4.338116 5 days
2: 923996 49-2014      3 22.115795 7.371932 2 days
3: 923996 50-2014      1  5.101146 5.101146 3 days
4: 923996 51-2014      2  6.086128 3.043064 1 days

我不知道为什么在这个单一操作中会发生这种行为,并且在大数据集中有重复的行可能会导致删除它们的任务需要更多时间。就像每一行都在更新。下一个是Sample3dput() 版本:

Sample3 <- structure(list(Date = structure(c(16405, 16405, 16406, 16406, 
16406, 16407, 16409, 16409, 16415, 16421, 16424), class = "Date"), 
    Id = c(923996L, 923996L, 923996L, 923996L, 923996L, 923996L, 
    923996L, 923996L, 923996L, 923996L, 923996L), Value = c(5.69822266467209, 
    3.11110428877822, 4.74334486914574, 2.17729208527479, 5.96061541361928, 
    7.60801375507644, 4.3689394081637, 10.1388420642027, 5.10114642099159, 
    0.022944125999933, 6.06318436387287), Week = c("48-2014", 
    "48-2014", "48-2014", "48-2014", "48-2014", "49-2014", "49-2014", 
    "49-2014", "50-2014", "51-2014", "51-2014"), Day = structure(c(16411, 
    16411, 16411, 16411, 16411, 16411, 16411, 16411, 16418, 16425, 
    16425), class = "Date")), row.names = c(NA, -11L), class = c("data.table", 
"data.frame"), .internal.selfref = <pointer: 0x0000000000311ef0>)

我是使用data.table 的新手,也许这是一个非常简单的解决方案,但我已经搜索了其他帖子,但没有找到修改这种情况的方法。感谢您的帮助。

【问题讨论】:

【参考方案1】:

您获得多行的原因是因为此代码生成一个向量而不是单个值:

Diff=Day-max(Date)

您只需要[1](或min

library(data.table)
Sample3[,.(Number=.N,Sum=sum(Value),Avg=mean(Value),
            Diff=Day[1]-max(Date)),by = .(Id,Week)] 
#       Id    Week Number       Sum      Avg   Diff
#1: 923996 48-2014      5 21.690579 4.338116 5 days
#2: 923996 49-2014      3 22.115795 7.371932 2 days
#3: 923996 50-2014      1  5.101146 5.101146 3 days
#4: 923996 51-2014      2  6.086128 3.043064 1 days

正如@Uwe 所说,data.table 中有一些函数可以帮助优化代码的速度,例如 firstlast 如果您的数据已经按日期排列。

【讨论】:

或许,您可以添加data.table 具有first()last() 功能?

以上是关于使用聚合操作时如何避免在 data.table 中创建重复项的主要内容,如果未能解决你的问题,请参考以下文章

使用 data.table 对列进行计数和聚合/汇总

使用dplyr汇总并保持相同的变量名称

r data.table 围绕 ad-hoc 连接的函数包装器(在链中聚合)

使用.BY,.GRP或其他方法添加data.table的多列聚合

使用空基类的聚合初始化时如何避免

根据data.table中列的最大值自定义dcast内部的聚合函数?