查找每个类别滚动总和最高的时期

Finding the period with the highest rolling sum per category

事情是这样的。

我有相当大的数据集(150 万行),代表 40,000 个客户以及 40 多个月中每个月的一些关于他们的指标,所以数据看起来或多或少是这样的:

CLIENTID| MONTHID| VALUE
--------|--------|-------
client1 | month1 | value1
client1 | month2 | value2
client1 | month3 | value3
client2 | month1 | value4
client2 | month2 | value5
client3 | month1 | value6
client4 | month1 | value7
etc... 

并非每个 CLIENTID 都有所有 MONTHID,许多仅在某些月份出现。

所以这就是我要用它做的事情:

我需要为每个 CLIENTID 提取他们 "life" 的 X 个月期间,在所有 X 个月中总和最大的 VALUE数据集中可用的时间段。

从某种意义上说,这个 X 月份是连续的,即使对于给定 CLIENTID.[=31 的特定 MONTHID 没有行=]

以下是我如何在脑海中想象自己的过程的逻辑分解:

  1. 从数据集中提取第一个 X MONTHID 周期,并为每个 CLIENTID 求和 VALUE 以获得每个 CLIENTID 的一个数字在那段时间并将其与 CLIENTID、一些新的 PERIODID 和我的特征的 VALUE 相加。

  2. 通过将周期的开始 MONTHID 增加一个,遍历每个周期的所有周期 CLIENTID 并在给定 [=11= 的新值时替换存储集中的这些值]比之前存储的

所以这是我的问题:

  1. 首先:这种方法在逻辑上是否有效?我认为它应该可行,但也许有更简单的解决方案可用于这种情况

  2. 其次也是最重要的:如何在R中实现?我仍在学习 R 语言,我知道如何对数据进行子集化、汇总等……但我正在使用 apply/mapply/etcpply (:P) 等循环函数。

如果不知道你的数据是什么样子,测试这个有点困难,我不能说它有多快,但这是一个可能的解决方案。

创建示例数据框:

set.seed(123)

df <- data.frame(
    CLIENTID = rep(c("a", "b", "c", "d"), each=10), 
    MONTHID = as.vector(replicate(4, sample(1:40, 10))), 
    VALUE = sample(100:500, 40, replace = T))

根据您在问题中所说的,对于某些 CLIENTID,没有针对给定 MONTHID 的条目。我认为那意味着那个月的价值是0?在这种情况下,拥有一个表示这些零值的数据框是最简单的,我们可以使用 expand.gridmerge.

创建它
clientmonths <- expand.grid(
    CLIENTID = unique(df$CLIENTID), 
    MONTHID = seq(from=min(df$MONTHID), to=max(df$MONTHID)))

df2 <- merge(clientmonths, df, all = T)

df2$VALUE[is.na(df2$VALUE)] <- 0

接下来,我使用 base-R 中的 filter 函数创建滚动总和,还使用 ​​dplyr 包中完全不相关的 filter 函数...

library(dplyr)

getPeriodSum <- function(x, period) {
    x %>% 
    mutate(periodSUM = as.vector(stats::filter(VALUE, rep(1, period), sides=1))) %>%
    filter(periodSUM == max(periodSUM, na.rm = T)) %>%
    select(endMONTH = MONTHID, periodSUM)
}

df2 %>% arrange(MONTHID) %>% group_by(CLIENTID) %>% getPeriodSum(5)

此代码 returns 具有 CLIENTID 列的数据框、包含指定 x 个月期间 VALUE 的最大累积和的 periodSUM 列以及包含该月末的 MONTHID 的 endMONTH 列x 个月期间。如果有关系(即相同的最大值可以由多个月份序列产生),每个 CLIENTID 将有不止一行。

我使用值 5 来查找最大 5 个月的总数,但您可以将其更改为其他值。