首页 > 解决方案 > 取数据子集在 data.table 中进行计算

问题描述

假设我有这个data.table:

df = data.table(date = c(20180101, 20180102, 20180103, 20180104, 20180105, 20180106, 20180107, 20180108, 20180109, 20180110, 20180111, 20180112, 20180113, 20180114, 20180115, 20180116, 20180117, 20180118), value = c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18))

我想做一些使用数据子集的计算(例如平均值)。例如:在 20180103 中,平均值将是(昨天)20180102 和(今天)20180103 值的总和((2+3)/2 = 2.5)。然后滚动到周期结束。

结果是这样的:

    date    mean
20180102     1.5
20180103     2.5
20180104     3.5
20180105     4.5
....

显然我可以编写一个 for 循环,为每次迭代对数据进行子集化,然后计算平均值,存储数据并输出结果。使用for循环被认为太慢了,使用foreach我不知道如何保存结果......


for 循环是这样的:

datelist = df[, .(date)] 

# initialize the object
data = NA
temp = 0
for (i in 2:nrow(datelist)) {
     today = as.numeric(datelist[i])
     yesterday = as.numeric(datelist[i-1])

     temp = df[date >= yesterday & date <= today]

     temp = temp[, .(mean(value))]

     temp = cbind(datelist[i], mean = temp$V1)


     if (is.na(data)[1]){
         data=temp

         } else {
          data=rbind(data,temp)

         }


}

您可以看到我首先对数据进行子集化并将其称为 temp 然后进行计算(平均,使用它来执行 lm,然后将其堆叠到数据对象中的任何函数)

这是缓慢且低效的,因为我有数百万个数据点


无论如何我可以在 data.table 语法中做到这一点:

result = df[, { data = .SD[date >= yesterday & date <= today]
                mean = mean(data$value)
                list(mean = mean)}, by=.(date)]

不知道怎么表达昨天和今天??因此,在 for 循环的情况下,昨天是 i-1,而今天是 i?

我在 by=.(date) 时的理解是 data.table 将查看每个日期并计算您提供的任何函数。如果我能得到 data.table 现在正在查看的日期的值(即 i) ,那么值 (i-1) 将是昨天...

谢谢

标签: rdata.table

解决方案


您可以在子句中使用shift运算符:data.table j

df[order(date),
   rollmean := (value + shift(value, n = 1, type = "lag"))/2][]

        date value rollmean
 1: 20180101     1       NA
 2: 20180102     2      1.5
 3: 20180103     3      2.5
 4: 20180104     4      3.5
 5: 20180105     5      4.5
 6: 20180106     6      5.5
 7: 20180107     7      6.5
 8: 20180108     8      7.5
 ...

推荐阅读