将一个组视为两个,因为行是分开的

时间:2017-04-18 12:36:19

标签: r dataframe dplyr

假设我有数据框

df <- data.frame(a = c(rep("a", 5), rep("b", 5), rep("a", 5)), 
                 b = c(rep(1, 2), rep(2, 5), rep(1, 8)))

> df
   a b
1  a 1
2  a 1
3  a 2
4  a 2
5  a 2
6  b 2
7  b 2
8  b 1
9  b 1
10 b 1
11 a 1
12 a 1
13 a 1
14 a 1
15 a 1

我想按ab对数据进行分组,并在第三列中命名组(数字),但我为我的新组是具有上述组的其他值的组。所以我有小组a1a2 b2b1a1。我想将第二个a1视为新组。所以,结果应该是:

   a b group
1  a 1 1
2  a 1 1
3  a 2 2
4  a 2 2
5  a 2 2
6  b 2 3
7  b 2 3
8  b 1 4
9  b 1 4
10 b 1 4
11 a 1 5
12 a 1 5
13 a 1 5
14 a 1 5
15 a 1 5

我能做到的唯一方法就是使用循环:

group <- numeric(nrow(df))
value <- 1
for (i in 1:nrow(df)) {
    if (i == 1) {
        group[i] <- value
    } else {
        if (all(df$a[i] == df$a[i - 1], 
                df$b[i] == df$b[i - 1])) {
            group[i] <- value
        } else {
            value <- value + 1
            group[i] <- value
        }
    }
}
df$group <- group
df

但这个解决方案不是很聪明。我可以使用dplyr或不使用循环来执行类似的操作吗?

3 个答案:

答案 0 :(得分:2)

尝试:

df <- data.frame(a = c(rep("a", 5), rep("b", 5), rep("a", 5)), 
                 b = c(rep(1, 2), rep(2, 5), rep(1, 8)))

library(dplyr)
transmute(df,a,b,group=cumsum(ifelse(lag(a)!=a | lag(b)!=b | is.na(lag(a)),1,0)))

或者:

mutate(df,group=cumsum(ifelse(lag(a)!=a | lag(b)!=b | is.na(lag(a)),1,0)))

答案 1 :(得分:1)

您可以在unitetidyr中使用rle

library(dplyr);library(tidyr)
df%>%
unite("a_b",a,b,remove=FALSE)%>%
mutate(group = {sq = rle(a_b); rep(seq_along(sq$lengths), sq$lengths)})

   a_b a b group
1  a_1 a 1     1
2  a_1 a 1     1
3  a_2 a 2     2
4  a_2 a 2     2
5  a_2 a 2     2
6  b_2 b 2     3
7  b_2 b 2     3
8  b_1 b 1     4
9  b_1 b 1     4
10 b_1 b 1     4
11 a_1 a 1     5
12 a_1 a 1     5
13 a_1 a 1     5
14 a_1 a 1     5
15 a_1 a 1     5

答案 2 :(得分:1)

您可以使用dplyr::group_indices获取一系列群组ID

gi <- group_indices(df, a, b)
gi
# [1] 1 1 2 2 2 4 4 3 3 3 1 1 1 1 1

然后只需将这些组ID添加到他们的cummax

ids <- cummax(gi) + gi
ids 
# [1] 2 2 4 4 4 8 8 7 7 7 5 5 5 5 5

它们与您想要的输出不完全相同,但如果需要可以重新标记。他们将以任何方式作为集团指数。