【发布时间】:2019-03-14 17:57:32
【问题描述】:
我遇到了一个问题,迫使我使用循环而不是我喜欢的 dplyr 管道流。
我想根据对相同值的连续观察对行进行分组。
例如,如果type 的前四个观察值等于a,则前四个观察值应分配给同一组。订单很重要,所以我不能dplyr::group_by 和dplyr::summarize。
下面的代码应该很好地解释了这个问题。我想知道是否有人可以提出一种不那么冗长的方法来做到这一点,最好使用tidyverse 包,而不是data.tables。
library(tidyverse)
# Crete some test data
df <- tibble(
id = 1:20,
type = c(rep("a", 5), rep("b", 5), rep("a", 5), rep("b", 5)),
val = runif(20)
)
df
#> # A tibble: 20 x 3
#> id type val
#> <int> <chr> <dbl>
#> 1 1 a 0.0606
#> 2 2 a 0.501
#> 3 3 a 0.974
#> 4 4 a 0.0833
#> 5 5 a 0.752
#> 6 6 b 0.0450
#> 7 7 b 0.367
#> 8 8 b 0.649
#> 9 9 b 0.846
#> 10 10 b 0.896
#> 11 11 a 0.178
#> 12 12 a 0.295
#> 13 13 a 0.206
#> 14 14 a 0.233
#> 15 15 a 0.851
#> 16 16 b 0.179
#> 17 17 b 0.801
#> 18 18 b 0.326
#> 19 19 b 0.269
#> 20 20 b 0.584
# Solve problem with a loop
count <- 1
df$consec_group <- NA
for (i in 1:nrow(df)) {
current <- df$type[i]
lag <- ifelse(i == 1, NA, df$type[i - 1])
lead <- ifelse(i == nrow(df), NA, df$type[i + 1])
if (lead %>% is.na) {
df$consec_group[i] <- ifelse(current == lag, count, count + 1)
} else {
df$consec_group[i] <- count
if (current != lead) count <- count + 1
}
}
df
#> # A tibble: 20 x 4
#> id type val consec_group
#> <int> <chr> <dbl> <dbl>
#> 1 1 a 0.0606 1
#> 2 2 a 0.501 1
#> 3 3 a 0.974 1
#> 4 4 a 0.0833 1
#> 5 5 a 0.752 1
#> 6 6 b 0.0450 2
#> 7 7 b 0.367 2
#> 8 8 b 0.649 2
#> 9 9 b 0.846 2
#> 10 10 b 0.896 2
#> 11 11 a 0.178 3
#> 12 12 a 0.295 3
#> 13 13 a 0.206 3
#> 14 14 a 0.233 3
#> 15 15 a 0.851 3
#> 16 16 b 0.179 4
#> 17 17 b 0.801 4
#> 18 18 b 0.326 4
#> 19 19 b 0.269 4
#> 20 20 b 0.584 4
由 reprex 包 (v0.2.1) 于 2019 年 3 月 14 日创建
这种连续出现的type 分组实际上只是一个中间步骤。我的结局是根据在前一个consec_group 中发生的val 的值,为给定的consec_group 操作val。对相关软件包的建议将不胜感激。
【问题讨论】:
-
with(rle(df$type), rep(seq_along(lengths), lengths)) -
这是一篇接近于被欺骗的帖子:stackoverflow.com/q/47169195/5325862
-
@camille 这很接近,但这里的问题和答案要清楚得多。也许把这个问题当作这个问题的骗子来结束?