【问题标题】:Rolling sum with double indexing in RR中具有双索引的滚动总和
【发布时间】:2020-10-23 14:40:29
【问题描述】:

我想计算 R 中两个索引列的滚动总和或滚动计数。以下数据表有一个显示销售量的列和两个日期列。我想创建一个第 4 列,它给我列 index2 中小于列 index1 中的日期的日期数,我还希望有第 5 列,它给我与第四列相关的销售额总和列。

sales_vec <- c(2, 4, 3, 5)
index1_vec <- as.Date("2019-08-29") + c(0, 2, 5, 6)
index2_vec <- as.Date("2019-08-29") + c(-5, 2, 1, -3)
company <- tibble(
  sales = sales_vec,
  index1 = index1_vec ,
  index2 = index2_vec 
)

> print(company)
# A tibble: 4 x 3
  sales index1     index2    
  <dbl> <date>     <date>    
1     2 2019-08-29 2019-08-24
2     4 2019-08-31 2019-08-31
3     3 2019-09-03 2019-08-30
4     5 2019-09-04 2019-08-26

我的结果应该是这样的:

# A tibble: 4 x 5
  sales index1     index2     rollingCount rollingSum
  <dbl> <date>     <date>            <dbl>      <dbl>
1     2 2019-08-29 2019-08-24            2          7
2     4 2019-08-31 2019-08-31            3         10
3     3 2019-09-03 2019-08-30            4         14
4     5 2019-09-04 2019-08-26            4         14

rollingCount 的第一行是 2,因为 Column index2 中有两个日期小于 index1 的第一行,并且与这两行关联的销售额之和为 2 + 5 =7,显示在rollingSum 的第一行。 rollingCount 的第二行是 3,因为 Column index2 中有三个日期小于 index1 的第二行,并且与这三行关联的销售额之和为 2 + 5 + 3 = 10,显示在第二行rollingSum 的行。以此类推。

我熟悉用于滚动计算的“滑动”命令系列,但我正在努力完成这项任务,因为它有两个索引列。

【问题讨论】:

  • 你需要sapply(company$index1, function(x) {i1 &lt;- company$index2 &lt; x; sum(company$sales[i1]) })
  • @chinsoon12 是的,我更喜欢 tidyverse 解决方案。但是,如果有其他解决方案,它们也会有所帮助,因为它们可以提出有用的思维过程,可能会打开一扇 tidyverse 之门!
  • @Henrik 感谢您注意到这个错字。我会修复它。

标签: r conditional-statements tidyverse rolling-computation


【解决方案1】:

这里有几种方法:

使用rowwise

library(dplyr)
library(purrr)

company %>%
  rowwise() %>%
  mutate(rollingCount = sum(index1 > .$index2), 
         rollingSum = sum(.$sales[index1 > .$index2]))


#  sales index1     index2     rollingCount rollingSum
#  <dbl> <date>     <date>            <int>      <dbl>
#1     2 2019-08-29 2019-08-24            2          7
#2     4 2019-08-31 2019-08-31            3         10
#3     3 2019-09-03 2019-08-30            4         14
#4     5 2019-09-04 2019-08-26            4         14

并使用来自purrrmap_dbl

company %>%
   mutate(rollingCount = map_dbl(index1, ~{
                 vec <- .x > index2
                 sum(vec)
                 }),
          rollingSum = map_dbl(index1, ~sum(sales[.x > index2])))

【讨论】:

  • 谢谢!在您的第二种方法中,是否可以破坏~sum(sales[.x &gt; index2]) 内部的操作?我的意思是,定义一个函数,首先计算vec &lt;- (.x &gt; index2),然后计算sum(vec)。原因是我想对vec做更精细的计算。
【解决方案2】:

base R中,我们可以使用sapply遍历'index1'列,用index2列创建一个逻辑向量,用它得到逻辑向量的sum和逻辑向量的sum “销售”的子集

cbind(company, t(sapply(company$index1, function(x) {
        i1 <- company$index2  < x
    c(rollingCount = sum(i1), rollingSum = sum(company$sales[i1])) })))
#  sales     index1     index2 rollingCount rollingSum
#1     2 2019-08-29 2019-08-24            2          7
#2     4 2019-08-30 2019-08-31            3         10
#3     3 2019-09-03 2019-08-30            4         14
#4     5 2019-09-04 2019-08-26            4         14

或者另一个选项是tidyverse

library(dplyr)
library(purrr)
map_dfr(company$index1, ~ {
       i1 <- company$index2 < .x
       tibble(rollingCount = sum(i1), rollingSum = sum(company$sales[i1]))}) %>%
    bind_cols(company, .)
# A tibble: 4 x 5
#  sales index1     index2     rollingCount rollingSum
#  <dbl> <date>     <date>            <int>      <dbl>
#1     2 2019-08-29 2019-08-24            2          7
#2     4 2019-08-30 2019-08-31            3         10
#3     3 2019-09-03 2019-08-30            4         14
#4     5 2019-09-04 2019-08-26            4         14

【讨论】:

  • 感谢您分享您的答案。根据您的解决方案,我开发的正是我想要的。谢谢! company &lt;- company %&gt;% mutate( rollingCount = slide_dbl (.x = index1, ~{sum(index2 &lt; .x)}), rollingSales = slide_dbl (.x = index1, ~{sum(sales[index2 &lt; .x])}), )
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-20
  • 2015-07-21
  • 1970-01-01
  • 2013-11-10
  • 2021-04-21
  • 1970-01-01
  • 2020-07-10
相关资源
最近更新 更多