【问题标题】:Group rows and add sum column of unique values分组行并添加唯一值的总和列
【发布时间】:2017-03-26 20:45:18
【问题描述】:

这是我的 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 对行进行分组;

  • 找到每个组的唯一值colB

  • 在新列中添加唯一值 (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 的重复值是:组 10 和 9 为 11 和 21,组 2 和 1 为 23。

【问题讨论】:

  • 条件语句不清楚
  • 您需要修改这句话:“对于每个不同于零的 colC 组,每个 colA 值及其前一个值(即 10 和 9、2 和 1)并添加一个新列来说明总和colB 唯一值的数量(对于每个组)。” .所以它可以由以英语为母语的人解释,或者您需要逐步说明过程,以便推断意图。对动词-宾语短语没有解释:“每个 colA 值都比零多样化”。
  • 不要对评论采取防御措施,而是学会监控您的问题,并及时、适当地回应建设性的建议,不要发布重复的跟进。点数与否决票无关。他们与不按照建议使用该网站有关

标签: r dataframe grouping unique rows


【解决方案1】:

您可以使用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

【讨论】:

  • 您好,谢谢,我会等一两天再将其标记为最佳答案。
  • 非常感谢,我确信我的示例 df 的代码可以正常工作。但是如何将它扩展到具有> 30,000行的真实data.frame?还有更通用的功能吗?
  • 我的第一个答案是更通用的版本。问题是您的分组机制是自定义的。为什么 11 单独在其组中,而 10 和 9 组合在一起?对于长 df,我将使用 case_whenifelse 创建一个新的分组向量。除非有分组方法,否则无法绕过它。
  • 好的,我会试试的。谢谢你,让我们等待任何其他可能的答案.....再次感谢。
【解决方案2】:

您真的不方便我们,而是重新发布同一问题的细微变化,而不是更新旧问题并提出模糊且与所需输出所暗示的内容不一致的条件。无论如何,这是我的尝试。这是对您发布的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]
    }
}

【讨论】:

  • 感谢您的努力@AkselA,但这是不对的。我还需要在新列中标记 colC 观察值 = 0
  • 那么“不同于 0”的说法是什么?
  • 我很抱歉,但似乎没有人理解我。不要在这个问题上浪费你的时间..再见
  • @aaaaa:我添加了一个处理所有行的版本,而不考虑 colC 值。
  • 仍然不正确....0s 行与其他行有关系...请参阅上面的预期输出,而不是 newcolD 中的 5,4,3,2,请考虑 1, 2,3,4 就像您在答案中所做的那样..
猜你喜欢
  • 1970-01-01
  • 2023-03-16
  • 2021-12-08
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-05
相关资源
最近更新 更多