【问题标题】:Cumulative sum until maximum reached, then repeat from zero in the next row累积总和直到达到最大值,然后在下一行从零开始重复
【发布时间】:2013-03-06 04:51:36
【问题描述】:

我觉得这是一个相当简单的问题,但在我的一生中,我似乎找不到答案。我有一个相当标准的数据框,我想做的是对一列值求和,直到它们达到某个值(该值或大于该值),此时它将 1 放入一个新列(标记为keep) 并在 0 处重新开始求和。

我有一列分钟,分钟之间的差异,一个保留列和一个累积总和列(我使用的示例比实际的完整数据集干净得多)

 minutes     difference     keep     difference_sum
 1052991158       0          0            0
 1052991338      180         0            180
 1052991518      180         0            360
 1052991698      180         0            540
 1052991878      180         0            720
 1052992058      180         0            900
 1052992238      180         0            1080
 1052992418      180         0            1260
 1052992598      180         0            1440
 1052992778      180         0            1620
 1052992958      180         0            1800

差和列是用代码计算出来的

caribou.sub$difference_sum<-cumsum(difference)

我想要做的是运行上面的代码,条件是,当总和值达到 1470 或任何大于它的数字时,它会在保持列中放置一个 1,然后重新开始求和,并继续运行数据集。

提前致谢,如果您需要更多信息,请告诉我。

艾登

【问题讨论】:

  • 当达到 1470 时,difference_sum 是否重置为 0?一个稍长的示例集(包括 difference_sum 何时超过阈值)会有所帮助。
  • 不,这就是我想要做的,差异总和列当前是使用 caribou.sub$difference_sum
  • 好的,但是当你越过阈值后,你如何计算下一个阈值?你是用1470以上的盈余,还是从下一行从0开始?
  • 哦,明白了。下一行将在每个点重置为 0(至少,这就是我想要它做的,会有盈余但必须被扔掉)。 Henrik 在下面找到了它。感谢您帮助解决问题。
  • 但我想我会按照你的要求扩展它,以防其他人在这里偶然发现。

标签: r loops if-statement cumsum


【解决方案1】:

我认为这最好用 for 循环来完成,想不出一个开箱即用的函数。以下应该做你想做的(如果我理解正确的话)。

current.sum <- 0
for (c in 1:nrow(caribou.sub)) {
    current.sum <- current.sum + caribou.sub[c, "difference"]
    carribou.sub[c, "difference_sum"] <- current.sum
    if (current.sum >= 1470) {
        caribou.sub[c, "keep"] <- 1
        current.sum <- 0
    }
}

如果不完全符合您的要求,请随时发表评论。但是正如 alexwhan 所指出的,您的描述并不完全清楚。

【讨论】:

    【解决方案2】:

    假设您的data.framedf

    df$difference_sum <- c(0, head(cumsum(df$difference), -1))
    # get length of 0's (first keep value gives the actual length)
    len <- sum(df$difference_sum %/% 1470 == 0)
    df$keep <- (seq_len(nrow(df))-1) %/% len
    df <- transform(df, difference_sum = ave(difference, keep, 
              FUN=function(x) c(0, head(cumsum(x), -1))))
    
    #       minutes difference keep difference_sum
    # 1  1052991158        180    0              0
    # 2  1052991338        180    0            180
    # 3  1052991518        180    0            360
    # 4  1052991698        180    0            540
    # 5  1052991878        180    0            720
    # 6  1052992058        180    0            900
    # 7  1052992238        180    0           1080
    # 8  1052992418        180    0           1260
    # 9  1052992598        180    0           1440
    # 10 1052992778        180    1              0
    # 11 1052992958        180    1            180
    

    【讨论】:

    • 这正是我要去的地方。 @heidelbergslide - 这将明显比循环快
    • 这里没有“从零开始重复”。它会与其他答案不同。
    • @MatthewLundberg,您的意思是操作员也对正确的 cumsum 值感兴趣?我以为只是计算keep?
    • 无论如何,应该这样做,以防 OP 也想要正确的 cumsum 值。
    • 是的,这是 GPS 定位点列表。我想选择距离 A 点大于 24.5 小时的第一个点(B 点),忽略之前的所有点,然后选择距离 B 点 24.5 小时的下一个点,忽略所有其他点,然后等等。
    【解决方案3】:

    我仍然不明白什么时候应该重新开始总和以及是否应该为零。理想的结果会大有帮助。

    尽管如此,我还是忍不住认为,简单的索引和减法将是一种直接的方法。下面的代码给出了与@Henrik 的解决方案相同的结果。

    df$difference_sum <- cumsum(df$difference)
    step <- (df$difference_sum %/% 1470) + 1
    k <- which(diff(step) > 0) + 1
    df$keep <- 0
    df$keep[k] <- 1
    step[k] <- step[k] - 1
    df$difference_sum <- df$difference_sum - c(0, df$difference_sum[k])[step]
    

    【讨论】:

    • 这真的很接近,但是因为(据我了解,我可能非常错误)您使用的是整个差异列的 cumsum,上一个选择的多余部分被合并到下一个选择中,所以它发生得太快了(第一个选择的值是在 1620 分钟,但剩下的 150 分钟应该被忽略但用于下一个选择,所以下一个选择发生在 1440 分钟(因为 cumsum 表示它的 150 分钟)比实际更多))。那有意义吗?感谢您的帮助!
    • 哦,我明白了。是的,我认为这是正确的(意思是我的回答不太正确)。同样,具有所需输出的更大示例将非常有帮助,尽管听起来您的问题已解决,因此此时可能不值得费心。
    猜你喜欢
    • 2021-02-28
    • 1970-01-01
    • 2019-10-31
    • 1970-01-01
    • 2020-11-03
    • 1970-01-01
    • 2019-05-08
    • 2021-03-26
    • 1970-01-01
    相关资源
    最近更新 更多