假设我有此数据表。
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)将是昨天...
谢谢
答案 0 :(得分:2)
您可以在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
...
答案 1 :(得分:0)
这样的事情
(df$value[-nrow(df)]+df$value[-1] ) / 2
# yields
# [1] 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 10.5 11.5 12.5 13.5 14.5 15.5 16.5 17.5
在这里创建数据框
data.table::data.table(date = .subset2(df,1)[-1],
mean = (df$value[-nrow(df)]+df$value[-1] ) / 2)
# date mean
# 1 20180102 1.5
# 2 20180103 2.5
# 3 20180104 3.5
# 4 20180105 4.5
# 5 20180106 5.5
# ...
使用您提供的数据。
以下是一些基准数据:
# create a bigger data frame
dfLarge <- data.table::data.table(
date = seq(as.Date('1989-01-01'),as.Date('2019-01-01'),1),
value = 1:10958
)
microbenchmark::microbenchmark(sol = {
data.table::data.table(date = .subset2(dfLarge,1)[-1],
mean = (dfLarge$value[-nrow(dfLarge)]+dfLarge$value[-1] ) / 2)
})
# Unit: microseconds
# expr min lq mean median uq max neval
# sol 367.955 423.203 921.4908 530.781 788.969 22095.85 100
如果此处的主要主题不是任务本身而是有效的子集设置,请指定其确切目标为确切(子集本身是一个广泛的主题,因此请添加有关需要完成的任务)。这样一来,您更有可能找到您要寻找的内容,而其他用户不会浪费任何精力。
话虽这么说,here是一个链接,提供了有关R
中子集的一些重要信息。
答案 2 :(得分:0)
远离for循环,您可以使用如下purrr map函数:
nvals <- nrow(df) # get the number of rows
vals <- df$value # get the value vector
output <- map(1:nvals, function(x) mean(vals[c(x-1, x)])
output <- unlist(output)
df <- cbind(df, output)
输出向量为:
1.0 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 10.5 11.5 12.5 13.5 14.5 15.5 16.5 17.5
我想你想要什么?