【问题标题】:R: Moving sum of one column in a data frame based on values in other columnR:根据另一列中的值移动数据框中一列的总和
【发布时间】:2015-12-11 13:26:10
【问题描述】:

我想计算一列的移动总和(填充一和零),但仅当相应列(时间)中的值在值的(移动)范围内时。

我的数据如下所示:

values <- c(1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0)
seconds <- c(0.0, 1.0, 2.5, 3.0, 5.5, 6.0, 6.5, 7.0, 8.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.5, 16.0, 17.0, 18.0, 19.0, 20.0)
data <- data.frame(values, seconds)

假设我想对“值”列中每 5 秒的数据求和。 那么我的第一个 5 秒总和(秒 >=0 和秒

1(因为它对应一个'秒',0.0,在感兴趣的区间内)

+

0(对应于“秒”中的 1.0)

+

0 (2.5)

+

0 (3.0)

= 1

在此处停止,因为下一个值 (1) 对应于 5.5 秒,在间隔之外。

接下来的 5 秒间隔(秒 >= 1 和秒

0 + 0 + 0 + 1 + 1 = 2

第三个间隔:

(秒 >= 2.5 & 秒 3

等等。

我是 R 菜鸟,所以这是我用来计算它的方法(而且它超级慢,所以我知道一定有更好的方法):

for(i in 1:20){movsum[i] <- sum(subset(data, seconds >= (seconds[i] - 5.0) & seconds <= seconds[i])$values)}

感谢您的帮助。如果有什么需要澄清的,请告诉我。

【问题讨论】:

  • 哎呀。解决它。我应该提一下,底部的 movsum 循环与我手动计算的不匹配,这正是我通常的目标。

标签: r sum


【解决方案1】:

这是一个可能的data.table::foverlaps 解决方案。这里的想法是创建 5 秒间隔查找表,然后在 data 内查找每个间隔中的值。

选择一个区间

int <- 5 ## 5 seconds

加载包,向data 添加额外的(相同的)列以设置边界,创建一个新的数据集,该数据集将具有每行所需的边界,运行foverlaps,键data 以启用二元连接,在data$values 中找到相应的值,并按每个间隔对它们求和,类似下面的方法似乎可行

library(data.table)
setkey(setDT(data)[, seconds2 := seconds], seconds, seconds2)
lookup <- data[, .(seconds, seconds2 = seconds + int)]
res <- foverlaps(lookup, data, which = TRUE)[, values := data$values[yid]]
res[, .(SumValues = sum(values)), by = .(SecInterval = xid)]
#     SecInterval SumValues
#  1:           1         1
#  2:           2         2
#  3:           3         3
#  4:           4         3
#  5:           5         3
#  6:           6         2
#  7:           7         1
#  8:           8         2
#  9:           9         1
# 10:          10         2
# 11:          11         3
# 12:          12         3
# 13:          13         2
# 14:          14         2
# 15:          15         1
# 16:          16         0
# 17:          17         0
# 18:          18         0
# 19:          19         0
# 20:          20         0

【讨论】:

  • 不错 (+1),硬编码比我的尝试少得多。
  • @Henrik 谢谢。对于不同的间隔或更大的数据集,我们似乎没有得到相同的结果,不知道为什么。
  • @Colin 如您所见,我的回答和大卫的回答都与您在问题中显示的前三个值一致。但是,我们在后续时间步的答案之间存在一些差异。您能否使用您提供的示例数据的全部所需输出来更新您的问题。干杯。
  • 您好 Henrik 和 David,非常感谢您的帮助。不幸的是,我正在使用的(实际)数据具有非唯一的时间步长——通常有两个事件同时发生。所以@Henrik据我了解,它不会真正作为时间序列工作。但是 David 的方法适用于我的数据(耶!),你的两个答案都教会了我很多关于 R 的知识。我真的很感激,希望我能给你们两个开绿卡。
  • @Colin 关于“我正在使用的(实际)数据具有非唯一的时间步长”:您应该始终提供捕捉真实数据本质的玩具数据,并使您的示例尽可能小尽可能。如果例如time = 1, 2, 2, 2.5, 4 足以捕获所有“特殊情况”(不规则的时间步长,非唯一的时间步长),那么它...... eeeh......足够了。潜在帮助者更容易看到输入和所需输出之间的对应关系,更容易检查他们的代码是否正常工作。
【解决方案2】:

您可以尝试zoo 包中的一些功能:

library(zoo)

# convert your data to a zoo time series
z <- read.zoo(data, index = "seconds")

# create an empty, regular time series,
# which contains the full time range, in steps of 0.5 sec
z0 <-  zoo(, seq(from = start(z), to = end(z), by = 0.5))

# 'expand' the irregular, original data to a regular series, by merging it with z0 
z2 <- merge(z, z0)

# apply the desired function (sum) to a rolling window of width 11
# (number of observations in each window)
# move the time frame in steps of 2 (by = 2) which correspond to 1 sec 
# use partial = TRUE, to allow the window to pass outside the time range
rollapply(z2, width = 11, by = 2, FUN = sum, na.rm = TRUE,
          align = "left", partial = TRUE)

# 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 
# 1  2  3  3  3  3  2  2  1  2  2  3  3  2  2  1  0  0  0  0  0

【讨论】:

    猜你喜欢
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多