在一列中使用 cumsum() 迭代

时间:2021-04-18 18:59:58

标签: r dplyr cumsum

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

  1. 给定数据框 df,其中包含一列 X,其中值是递增的。
  2. cumsum() 应在达到 10 或 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 个所需的输出为例。

enter image description here

4 个答案:

答案 0 :(得分:5)

更新

案例 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 完成。

Case-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

较早的回答

情况 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

答案 1 :(得分:4)

我们可以通过'X'arrange,用%/%创建一个分组列并得到'X'的累积和(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))

答案 2 :(得分:2)

这是一个 data.table 选项

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

答案 3 :(得分:1)

基础 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)
)
相关问题