对行进行分组并添加唯一值的总和列

时间:2017-03-26 20:45:19

标签: r dataframe grouping unique rows

这是我的data.frame的一个例子:

df = read.table(text='colA   colB   colC
10  11   7
10  34   7
10  89   7
10  21   7
2   23   5
2   21   5
2   56   5
22  14   3
22  19   3
22  90   3
11  19   2
11  45   2
1   45   0
1   23   0
9   8    0
9   11   0
9   21   0', header = TRUE)

我需要按colAcolC对行进行分组,然后添加一个新列,根据colB说明唯一值的总和。

在这里,我需要为这个特定的data.frame:

做些什么
  • colA = 10和9,colA = 2和1,colA = 22和colA = 11;

    <的行分组/ LI>
  • 找到每组colB的唯一值;

  • 在新col(newcolD)中添加唯一值。

请注意,colC表示colA = 10和9,colA = 2和1,colA = 22和colA的观察总数= 11。 data.frame需要按colC递减排序。

我的预期输出是:

colA   colB   colC  newcolD
   10  11   7      5
   10  34   7      5
   10  89   7      5
   10  21   7      5
   9   8    0      5
   9   11   0      5
   9   21   0      5
   2   23   5      4
   2   21   5      4
   2   56   5      4
   1   45   0      4
   1   23   0      4
   22  14   3      3
   22  19   3      3
   22  90   3      3
   11  19   2      2
   11  45   2      2

请注意,在df colB重复的值为:11和21表示组10和9,23表示组2和1。

2 个答案:

答案 0 :(得分:0)

您可以使用dplyr执行此操作。诀窍是创建一个新的分组列,该列对colA中的连续值进行分组。这是通过以下示例中的cumsum(c(1, diff(colA) < -1)完成的。

df1 = read.table(text='colA   colB   colC
10  11   7
10  34   7
10  89   7
10  21   7
2   23   5
2   21   5
2   56   5
22  14   3
22  19   3
22  90   3
1   45   0
1   23   0
9   8    0
9   11   0
9   21   0', header = TRUE,stringsAsFactors=FALSE)

library(dplyr)
df1 %>%
arrange(desc(colA)) %>%
group_by(group_sequential = cumsum(c(1, diff(colA) < -1))) %>%
mutate(newcolD=n_distinct(colB))

    colA  colB  colC group_sequential newcolD
   <int> <int> <int>            <dbl>   <int>
1     22    14     3                1       3
2     22    19     3                1       3
3     22    90     3                1       3
4     10    11     7                2       5
5     10    34     7                2       5
6     10    89     7                2       5
7     10    21     7                2       5
8      9     8     0                2       5
9      9    11     0                2       5
10     9    21     0                2       5
11     2    23     5                3       4
12     2    21     5                3       4
13     2    56     5                3       4
14     1    45     0                3       4
15     1    23     0                3       4

编辑新数据 使用您添加的数据,我们需要创建自定义分组。我在下面的示例中使用case_when。这与您在所需输出列中显示的顺序相匹配。在文中,您写道您希望表格按colC排序。为此,请将最后一行更改为arrange(desc(colC))

df1 = read.table(text='colA   colB   colC
10  11   7
10  34   7
10  89   7
10  21   7
2   23   5
2   21   5
2   56   5
22  14   3
22  19   3
22  90   3
11  19   2
11  45   2
1   45   0
1   23   0
9   8    0
9   11   0
9   21   0', header = TRUE,stringsAsFactors=FALSE)

library(dplyr)
df1 %>%
group_by(group_sequential = case_when(.$colA==10|.$colA==9~1,
                                      .$colA==2|.$colA==1~2,
                                      .$colA==22~3,
                                      .$colA==11~4)) %>%
mutate(newcolD=n_distinct(colB)) %>%
arrange(desc(newcolD))

    colA  colB  colC group_sequential newcolD
   <int> <int> <int>            <dbl>   <int>
1     10    11     7                1       5
2     10    34     7                1       5
3     10    89     7                1       5
4     10    21     7                1       5
5      9     8     0                1       5
6      9    11     0                1       5
7      9    21     0                1       5
8      2    23     5                2       4
9      2    21     5                2       4
10     2    56     5                2       4
11     1    45     0                2       4
12     1    23     0                2       4
13    22    14     3                3       3
14    22    19     3                3       3
15    22    90     3                3       3
16    11    19     2                4       2
17    11    45     2                4       2

答案 1 :(得分:0)

你真的没有让我们轻松,重新定位同一个问题的轻微变化,而不是更新旧问题,并提出模糊的条件,与所需的输出意味着不一致。无论如何,这是我的尝试。这更像是您发布的second question的答案,因为它在形式上更为通用。

它有点乱,它几乎是你的条件直接转换为带有一些if语句的for循环。我选择专注于你的书面条件而不是预期的输出,因为这更容易理解。如果您想要更好的答案,请考虑大大清理您的问题。

df1 <- read.table(text="
  colA colB colC
    10   11    7
    10   34    7
    10   89    7
    10   21    7
    2    23    5
    2    21    5
    2    56    5
    22   14    3
    22   19    3
    22   90    3
    11   19    2
    11   45    2
    1    45    0
    1    23    0
    9    8     0
    9    11    0
    9    21    0", header=TRUE)

df2 <-  read.table(text="
  colA colB colC
    10   11    7
    10   34    7
    10   89    7
    10   21    7
    2    23    5
    2    21    5
    2    56    5
    33   24    3
    33   78    3
    22   14    3
    22   19    3
    22   90    3
    11   19    2
    11   45    2
    1    45    0
    1    23    0
    9    8     0
    9    11    0
    9    21    0
    32   11    0", header=TRUE)

df <- df1
for (i in 1:nrow(df)) {
            df$colD[i] <- ifelse(df$colC[i] == 0,
      0,
      length(unique(df$colA[1:i])))

    if (any(df$colA[i]-1 == df$colA[1:i]) & df$colC[i] != 0) {
        df$colD[i] <- df$colD[which(df$colA[i]-1 == df$colA[1:i])][1]
    }
}

# colA colB colC colD
#   10   11    7    1
#   10   34    7    1
#   10   89    7    1
#   10   21    7    1
#    2   23    5    2
#    2   21    5    2
#    2   56    5    2
#   22   14    3    3
#   22   19    3    3
#   22   90    3    3
#   11   19    2    1
#   11   45    2    1
#    1   45    0    0
#    1   23    0    0
#    9    8    0    0
#    9   11    0    0
#    9   21    0    0

df <- df2
for (i in 1:nrow(df)) {
            df$colD[i] <- ifelse(df$colC[i] == 0,
      0,
      length(unique(df$colA[1:i])))

    if (any(df$colA[i]-1 == df$colA[1:i]) & df$colC[i] != 0) {
        df$colD[i] <- df$colD[which(df$colA[i]-1 == df$colA[1:i])][1]
    }
}
df
# colA colB colC colD
#   10   11    7    1
#   10   34    7    1
#   10   89    7    1
#   10   21    7    1
#    2   23    5    2
#    2   21    5    2
#    2   56    5    2
#   33   24    3    3
#   33   78    3    3
#   22   14    3    4
#   22   19    3    4
#   22   90    3    4
#   11   19    2    1
#   11   45    2    1
#    1   45    0    0
#    1   23    0    0
#    9    8    0    0
#    9   11    0    0
#    9   21    0    0
#   32   11    0    0

要对colC为零的行进行分组,只需调整这样的条件:

for (i in 1:nrow(df)) {
    df$colD[i] <- length(unique(df$colA[1:i]))

    if (any(df$colA[i]-1 == df$colA[1:i])) {
        df$colD[i] <- df$colD[which(df$colA[i]-1 == df$colA[1:i])][1]
    }
}