【问题标题】:How to calculate the difference of a list of various by key?如何按键计算各种列表的差异?
【发布时间】:2015-12-01 10:56:12
【问题描述】:

我有一个带有 key 和大约 1000 行的 data.table,其中两个设置为 key。我想创建一个名为 difference 的新变量,其中包含按键分组的每个数字行的差异。

比如简单的数据是:ID和Act设置为key

    ID  ValueDate Act Volume
    1 2015-01-01 EUR     21
    1 2015-02-01 EUR     22
    1 2015-01-01 MAD     12
    1 2015-02-01 MAD     11
    2 2015-01-01 EUR      5
    2 2015-02-01 EUR      7
    3 2015-01-01 EUR      4
    3 2015-02-01 EUR      2
    3 2015-03-01 EUR      6

我想要的是:添加一个新列来计算每组两行之间的差异(按时间排序),注意对于每组的第一行,差异的值为0。

    ID  ValueDate Act Volume Difference
    1 2015-01-01 EUR     21    0
    1 2015-02-01 EUR     22    1
    1 2015-01-01 MAD     12    0
    1 2015-02-01 MAD     11   -1
    2 2015-01-01 EUR      5    0
    2 2015-02-01 EUR      7    2
    3 2015-01-01 EUR      4    0
    3 2015-02-01 EUR      2   -2
    3 2015-03-01 EUR      6    4

这是生成测试数据的代码:

    dd <- data.table(ID = c(1,1,1,1,2,2,3,3,3), 
                     ValueDate = c("2015-01-01", "2015-02-01", "2015-01-01","2015-02-01", "2015-01-01","2015-02-01","2015-01-01","2015-02-01","2015-03-01"),
                     Act = c("EUR","EUR","MAD","MAD","EUR","EUR","EUR","EUR","EUR"),
                     Volume=c(21,22,12,11,5,7,4,2,6))

为表格设置键:

    setkey(dd, ID, Act)

查看数据:

    > dd
       ID  ValueDate Act Volume
    1  1 2015-01-01 EUR     21
    2  1 2015-02-01 EUR     22
    3  1 2015-01-01 MAD     12
    4  1 2015-02-01 MAD     11
    5  2 2015-01-01 EUR      5
    6  2 2015-02-01 EUR      7
    7  3 2015-01-01 EUR      4
    8  3 2015-02-01 EUR      2
    9  3 2015-03-01 EUR      6

那么,我们可以使用聚合函数来计算差异吗?或 .SD 的“数据子集”的方法,但我不知道如何按组计算两行之间的差异,请注意,对于某些组,行数也可能不同,但我有之前尝试使用 for(i in 0:x) 重新计算差异,但我认为这不是一个好方法:(

【问题讨论】:

  • 是否总是正好有两条记录?如果他们不是,你希望发生什么?
  • 其实并不总是会有两条记录,这只是一个简单的例子,有些组有更多记录

标签: r data.table key grouping


【解决方案1】:

如果您想明确使用您的密钥,您可以将 keycall 传递给 by 参数

dd[, Difference := c(0L, diff(Volume)), by = key(dd)]
dd
#    ID  ValueDate Act Volume Difference
# 1:  1 2015-01-01 EUR     21          0
# 2:  1 2015-02-01 EUR     22          1
# 3:  1 2015-01-01 MAD     12          0
# 4:  1 2015-02-01 MAD     11         -1
# 5:  2 2015-01-01 EUR      5          0
# 6:  2 2015-02-01 EUR      7          2
# 7:  3 2015-01-01 EUR      4          0
# 8:  3 2015-02-01 EUR      2         -2
# 9:  3 2015-03-01 EUR      6          4

或者使用data.table v 1.9.6+,你也可以使用shift函数

dd[, Difference := Volume - shift(Volume, fill = Volume[1L]), by = key(dd)]

【讨论】:

  • 嗨,@David Arenburg,谢谢你的回答,我以前试过这个,但是有错误,说错误在[.data.frame(dd, , :=(Difference, c(0L, diff) (Volume))), by = key(dd)) : 未使用的参数 (by = key(dd))
  • 你说dd 已经是一个data.table。你之前没跑过setkey(setDT(dd), ID, Act)吗?
  • 哦!我发现了我的错误,你是对的,我只是生成了格式错误的数据,现在,它工作得很好!非常感谢!
【解决方案2】:

我们可以使用dplyr。在按“ID”、“Act”分组后,我们创建“Difference”列作为该列的“Volume”和lag 的差异。

library(dplyr)
dd %>%
  group_by(ID, Act) %>%
  mutate(Difference = Volume-lag(Volume))

编辑:正如@DavidArenburg 所述,将lag(Volume) 替换为lag(Volume, default = Volume[1L]) 将为每个组中的第一个元素给出0 而不是NA。


或者使用 base R 中的 ave,我们可以执行 diff 并与 0 连接,以使长度相同。 diff 返回一个长度比原始向量长度小一的向量。

with(dd, ave(Volume, ID, Act, FUN= function(x) c(0, diff(x)))

【讨论】:

  • 您可以使用lag(Volume, default = Volume[1L]) 来匹配 OP 输出。
  • @akrun,谢谢你的分享!!你说的方法我试过了,效果很好!!
  • @DavidArenburg 我很难在 Windows 7 中正确处理该问题。那是我首先尝试的。 Error: expecting a single value
  • 我也在使用 Windows 7。也许您需要更新软件包版本。
猜你喜欢
  • 2011-09-23
  • 2017-07-19
  • 1970-01-01
  • 2016-06-03
  • 1970-01-01
  • 2015-03-09
  • 1970-01-01
  • 1970-01-01
  • 2018-08-30
相关资源
最近更新 更多