【问题标题】:Find a cumulative sum of one column until a conditional sum on another column is met求一列的累积总和,直到满足另一列的条件总和
【发布时间】:2017-07-01 19:12:12
【问题描述】:

我想为 B 列的那些行找到前面的 cumsum(即 cumsum 减去当前行),直到 A 列的前几行(包括当前行)的总和为

我能够使用传统的 for 循环找到答案。矢量化实现将非常有帮助,因为我需要在大型数据集上运行它。分享我的简单代码以防万一。

dt <- data.frame(A = c(0, 2, 3, 5, 8, 90, 8, 2, 4, 1, 2),
                 B = c(1, 0, 4, 2, 3, 4, 2, 1, 2, 3, 1),
                 Ans = c(0, 1, 1, 4, 0, 0, 0, 2, 3, 5, 6),
                 new=rep(0,11))



dt3 <- dt
for (i in 2:nrow(dt3)){
  set<-0
  count<-0
  k=i-1
  for (j in k:1){
    count=count+dt3$A[j+1]
    if(count<=7){ 
      set<-set+dt3$B[j]
      if(j==1){
        dt3$new[i]=set
      }
    }
    else{
      dt3$new[i]=set
    }
  }
}

以下是要满足的三个条件:

  1. 如果 A > 7,则 Ans 重置为 0
  2. 如果 cumsum(A)
  3. 如果 cumsum(A) > 7,则 Ans 是 lagB 的 cumsum(),用于 A 的先前行的范围,其总和为

这是数据的简化版本(A 列和 B 列),所需的输出是 Ans 列:

dt <- data.frame(A = c(0, 2, 3, 5, 8, 90, 8, 2, 4, 1, 2),
                 B = c(1, 0, 4, 2, 3, 4, 2, 1, 2, 3, 1),
                 Ans = c(0, 1, 1, 4, 0, 0, 0, 2, 3, 5, 6))

dt
    A B Ans   Reason for value in Ans:
1   0 1   0       There are no preceeding rows in B so Ans is 0
2   2 0   1       Sum of value of A from row 2 to 1 is 2 <=7. So Ans is the value of B from first row = 1
3   3 4   1       Sum of value of A from row 3,2 and 1 is 5 <=7. So Ans is the sum of value of B in row 1 and 2, which is 1. 
4   5 2   4       Value of A from row 4 is 5 which is <=7. So Ans is value of B from row 3, which is 4
5   8 3   0       Value of A in row 5 is 8 which is >7. So Ans is 0 (Value of Ans resets to 0 when A > 7).
6  90 4   0
7   8 2   0
8   2 1   2        Value of A in row 8 is 2 which <=7, so Ans is value of B in row 7 which is 2
9   4 2   3        Sum of value of A from row 9 and 8 is 6<=7, so Ans is sum of value of B in row 8 and 7 = 3
10  1 3   5        Sum of value of A from row 10,9 and 8 is 7<=7, so Ans is sum of value of B in row 9,8 and 7 =5.
11  2 1   6        Sum of value of A from row 11,10 and 9 is 7<=7, so Ans is sum of value of B in row 10,9 and 8 =6. 

任何关于如何在 R 中编码的帮助?

【问题讨论】:

  • 我已将您的 scrfeenshot 替换为生成数据框的代码。下次,请不要使用屏幕截图来显示您的数据。提供可重现的示例数据集。
  • 感谢您的信息!下次会记住的
  • 这些反对意见可能部分是由于早期的屏幕截图。我已经解决了。现在也许您可以进一步阐明预期输出的逻辑。我猜有些人无法理解您的逻辑,所以他们给了您反对票。如果你能逐行解释为什么 Ans 中的每个数字都是这样的,这将很有帮助,也许直到第 5 行。
  • 为什么第 9 行和第 10 行中的 Ans 等于 3,5
  • 我刚刚看到你更新的解释。这真的让我很困惑。为什么在第 4 行中只添加 A 列中的第 3 行和第 4 行。但是对于第 9 行和第 10 行,您从第 8 行开始使用cumsum

标签: r cumsum


【解决方案1】:

请参阅下面的编辑,该编辑试图回答更新后的问题。


如果我理解OP的意图正确,那么有3条规则:

  1. 如果 A 大于 7,则 Ans 为零并重新开始分组
  2. 如果组内cumsum(A)小于或等于7,则Ans是滞后Bcumsum()
  3. 如果组内cumsum(A) 大于7,则Ans 滞后B

下面的代码为给定的样本数据集产生了预期的结果:

# create sample data set
DF <- data.frame(A = c(0, 2, 3, 5, 8, 90, 8, 2, 4, 1),
                 B = c(1, 0, 4, 2, 3, 4, 2, 1, 2, 3),
                 Ans = c(0, 1, 1, 4, 0, 0, 0, 2, 3, 5))
# load data.table, CRAN version 1.10.4 used
library(data.table)
# coerce to data.table
DT <- data.table(DF)
# create helper column with lagged values of
DT[, lagB := shift(B, fill = 0)][]
# create new answer
DT[, new := (A <= 7) * ifelse(cumsum(A) <= 7, cumsum(lagB), lagB), by = rleid(A <= 7)][
  , lagB := NULL][]
     A B Ans new
 1:  0 1   0   0
 2:  2 0   1   1
 3:  3 4   1   1
 4:  5 2   4   4
 5:  8 3   0   0
 6: 90 4   0   0
 7:  8 2   0   0
 8:  2 1   2   2
 9:  4 2   3   3
10:  1 3   5   5

rleid(A &lt;= 7)A 值不大于或大于 7 的所有连续条纹分别创建唯一的组号。 ifelse() 子句在分组内实现规则 2 和 3。通过将结果与(A &lt;= 7) 相乘,实现了规则 1。从而使用了 as.numeric(TRUE) 为 1,as.numeric(FALSE) 为 0 的技巧。最后,删除了辅助列。


编辑

根据 OP 提供的附加信息,我相信只剩下一个规则了:

  • 为每一行找到一个向后延伸的窗口,其中包含的行数与sum(A) 不超过7 一样。答案是同一窗口中滞后B 的总和。
  • 为了澄清,如果窗口长度为零,因为初始行中的A 已超过 7,则答案为零。

滑动窗口的可变长度是这里比较棘手的部分:

# sample data set consists of 11 rows after OP's edit
DF <- data.frame(A = c(0, 2, 3, 5, 8, 90, 8, 2, 4, 1, 2),
                 B = c(1, 0, 4, 2, 3, 4, 2, 1, 2, 3, 1),
                 Ans = c(0, 1, 1, 4, 0, 0, 0, 2, 3, 5, 6))
DT <- data.table(DF) 
DT[, lagB := shift(B, fill = 0)][]

# find window lengths
DT[, wl := DT[, Reduce(`+`, shift(A, 0:6, fill = 0), accumulate = TRUE)][, rn := .I][
  , Position(function(x) x <= 7, right = TRUE, unlist(.SD)), by = rn]$V1][]

# sum lagged B in respective window
DT[, new := DT[, Reduce(`+`, shift(lagB, 0:6, fill = 0), accumulate = TRUE)][
  , rn := .I][, wl := DT$wl][, ifelse(is.na(wl), 0, unlist(.SD)[wl]), by = rn]$V1][]
     A B Ans lagB wl new
 1:  0 1   0    0  7   0
 2:  2 0   1    1  7   1
 3:  3 4   1    0  7   1
 4:  5 2   4    4  1   4
 5:  8 3   0    2 NA   0
 6: 90 4   0    3 NA   0
 7:  8 2   0    4 NA   0
 8:  2 1   2    2  1   2
 9:  4 2   3    1  2   3
10:  1 3   5    2  3   5
11:  2 1   6    3  3   6

【讨论】:

  • 谢谢 Uwe!条件 1 和 2 是正确的。对于条件 3,它是:如果组内的 cumsum(A) > 7,则对于总和为 的 A 的一组累积行,答案是滞后 B 的 cumsum()
  • 我从您对第 4 行答案的解释中得出了规则 3:第 4 行中 A 的值是 5,即
  • 是的,第 4 行确实如此。但它不应该适用于 cumsum(A) > 7 的第 9、10 行。
  • cumsum(A) 不是在每行后用A &gt; 7 重新启动,即在第 7 行后用A == 8 重新启动吗?所以,cumsum() 第 8 到 10 行是 2+4+1 == 7。
  • 呃,那么问题要复杂得多,因为有一种滚动窗口,只要总和不超过 7,它就会向后延伸尽可能多的行。这真的很棘手。
猜你喜欢
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-28
  • 2021-01-29
  • 1970-01-01
  • 2018-11-14
相关资源
最近更新 更多