在一列中使用 cumsum() 迭代

Use of cumsum() iterativley in one column

是否可以在一列中迭代地使用 cumsum() 并以另一列为开始 - 停止条件:

  1. 假设数据框 df 有一列 X,其中值是升序的。
  2. cumsum() 应该在达到 10 或十的倍数时停止(例如 20,30,40,...)。
  3. 然后在达到这一点后 (10,20,30,40,..) cumsum() 应该开始新...等等。
  4. 如果出现平局(20,20 或 30,30)cumsum 应在最后一次出现 10、20、30、40 时停止,... 这是数据框:
df <- structure(list(X = c(55L, 95L, 39L, 52L, 22L, 93L, 76L, 82L, 
77L, 58L, 60L, 19L, 31L, 43L, 65L, 56L, 18L, 66L, 21L, 49L, 13L, 
37L, 36L, 51L, 41L, 7L, 91L, 3L, 11L, 65L, 51L, 32L, 25L, 10L, 
5L, 7L, 8L, 3L, 72L, 66L, 93L, 24L, 48L, 44L, 91L, 60L, 62L, 
89L, 100L, 69L, 5L, 89L, 54L, 19L, 39L, 93L, 60L, 64L, 89L, 81L, 
24L, 9L, 51L, 9L, 7L, 69L, 19L, 51L, 39L, 100L, 83L, 67L, 33L, 
84L, 66L, 25L, 20L, 87L, 55L, 56L, 83L, 52L, 96L, 42L, 16L, 64L, 
45L, 30L, 55L, 29L, 16L, 73L, 40L, 29L, 92L, 6L, 38L, 12L, 38L, 
89L)), class = "data.frame", row.names = c(NA, -100L))

非常感谢!!!

期望的输出最多为 30 个。

我们可以arrange通过'X',用%/%创建一个分组列,得到'X'[=16的累计和(cumsum) =]

library(dplyr)
df %>% 
    arrange(X) %>%
    group_by(grp = lag(X  %/% 10, default = 0)) %>%
    mutate(new = cumsum(X))

-输出

# A tibble: 100 x 3
# Groups:   grp [11]
#       X   grp   new
#   <int> <dbl> <int>
# 1     3     0     3
# 2     3     0     6
# 3     5     0    11
# 4     5     0    16
# 5     6     0    22
# 6     7     0    29
# 7     7     0    36
# 8     7     0    43
# 9     8     0    51
#10     9     0    60
# … with 90 more rows

如果需要在 10、20 开始,

df %>% 
    arrange(X) %>%
    group_by(grp = X  %/% 10) %>%
    mutate(new = cumsum(X))

更新

案例 1:有效处理关系(OP 的条件 4)。让我们举一个不同的例子,其中有联系以及两个连续的值可以被 10 整除。(我认为其他策略可能会失败)
df1 <- data.frame(X = c(3, 4, 10, 10, 10, 13, 20, 30, 31, 40, 45))

df1 %>% arrange(X) %>% group_by(X) %>%
  mutate(d = n(),
         d2 = row_number(),
         d2 = d2 == max(d2)) %>% ungroup() %>% 
  group_by(Y = cumsum( X %% 10 == 0 & d2)) %>%
  mutate(Y = cumsum(X)) %>% ungroup() %>%
  select(-d, -d2)

# A tibble: 11 x 2
       X     Y
   <dbl> <dbl>
 1     3     3
 2     4     7
 3    10    17
 4    10    27
 5    10    10
 6    13    23
 7    20    20
 8    30    30
 9    31    61
10    40    40
11    45    85
这也可以通过 accumulate 完成。

案例 2:当组开始下一个值时,关系也得到妥善处理

df1 %>% arrange(X) %>% group_by(X) %>%
  mutate(d = n(),
         d2 = row_number(),
         d2 = d2 == max(d2)) %>% ungroup() %>% 
  group_by(Y = lag(cumsum( X %% 10 == 0 & d2), default = 0)) %>%
  mutate(Y = cumsum(X)) %>% ungroup() %>%
  select(-d, -d2)
# A tibble: 11 x 2
       X     Y
   <dbl> <dbl>
 1     3     3
 2     4     7
 3    10    17
 4    10    27
 5    10    37
 6    13    13
 7    20    33
 8    30    30
 9    31    31
10    40    71
11    45    45

较早的回答

Case-3:当下一个 cumsum 从下一个值开始时。
df %>% arrange(X) %>%
  mutate(y = accumulate(X, .init = 0, ~ifelse(.y %% 10 == 0, 1, 0))[-nrow(df)],
         y = accumulate2(X, y, .init = 0, ~ifelse(..3 == 1, ..2, ..1 + ..2))[-1])

     X    y
1     3    3
2     3    6
3     5   11
4     5   16
5     6   22
6     7   29
7     7   36
8     7   43
9     8   51
10    9   60
11    9   69
12   10   79
13   11   11
14   12   23
15   13   36
16   16   52
17   16   68
18   18   86
19   19  105
20   19  124
21   19  143
22   20  163
23   21   21
24   22   43
25   24   67
26   24   91
27   25  116
28   25  141
29   29  170
30   29  199
31   30  229
32   31   31
33   32   63
34   33   96
35   36  132
36   37  169
37   38  207
38   38  245
39   39  284
40   39  323
41   39  362
42   40  402
43   41   41
44   42   83
45   43  126
46   44  170
47   45  215
48   48  263
49   49  312
50   51  363
51   51  414
52   51  465
53   51  516
54   52  568
55   52  620
56   54  674
57   55  729
58   55  784
59   55  839
60   56  895
61   56  951
62   58 1009
63   60 1069
64   60   60
65   60   60
66   62   62
67   64  126
68   64  190
69   65  255
70   65  320
71   66  386
72   66  452
73   66  518
74   67  585
75   69  654
76   69  723
77   72  795
78   73  868
79   76  944
80   77 1021
81   81 1102
82   82 1184
83   83 1267
84   83 1350
85   84 1434
86   87 1521
87   89 1610
88   89 1699
89   89 1788
90   89 1877
91   91 1968
92   91 2059
93   92 2151
94   93 2244
95   93 2337
96   93 2430
97   95 2525
98   96 2621
99  100 2721
100 100  100

这里有一个data.table选项

setDT(df)[order(X)][, y := cumsum(X), cumsum(X %% 10 == 0)]

基础 R 解决方案:

# Number of values per group: n => integer scalar
n <- 10

# Using transform() and ave(): cumsum => numeric vector
res <- transform(
  df[order(df$X), , drop = FALSE], 
  y = ave(X, ((X - 1) %/% n), FUN = cumsum)
)