问题描述
是否可以在一列中迭代使用 cumsum()
,并在另一列上以开始 - 停止为条件:
- 给定数据框
df
,其中包含一列X
,其中值是递增的。 -
cumsum()
应在达到 10 或 10 的倍数(例如 20、30、40...)时停止。 - 然后在到达这一点后 (10,20,30,40,..) cumsum() 应该开始新的......等等。
- 如果出现平局(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,32L,25L,10L,5L,8L,72L,24L,48L,44L,62L,89L,100L,69L,54L,64L,81L,9L,83L,67L,33L,84L,20L,87L,55L,96L,42L,16L,45L,30L,29L,73L,40L,92L,6L,38L,12L,89L)),class = "data.frame",row.names = c(NA,-100L))
非常感谢!!!
以最多 30 个所需的输出为例。
解决方法
更新
案例 1:有效地处理关系(OP 的条件 4)。让我们举一个不同的例子,其中存在关系以及两个连续的可被 10 整除的值。(我认为其他策略可能会失败)df1 <- data.frame(X = c(3,4,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 = 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,~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
,
我们可以通过'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))
,
这是一个 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)
)