如何检查分组列中的所有值是否相同?

How to check whether all values in grouped columns are the same?

如何检查分组列中的所有值是否相同?

比如我有以下df:

   id category yes
1   1       in   1
2   1       in   1
3   1       in   1
4   1       in   1
5   1       in   1
6   1      out   1
7   1      out   1
8   1      out   1
9   2       in   1
10  2       in   1
11  2      out   0
12  2      out   1
13  2      out   1
14  3       in   1
15  3       in   1
16  3       in   0
17  3      out   1
18  3      out   1
19  4       in   1
20  4       in   1
21  4       in   1
22  4      out   1
23  4      out   0

我想做这样的事情:

df <- df %>%
  group_by(id, category) %>%
  mutate(
    out = ifelse(# id, category, and yes have the same values in each row within the group)
  )

因此预期的输出将如下所示:

   id category yes same
1   1       in   1    1
2   1       in   1    1
3   1       in   1    1
4   1       in   1    1
5   1       in   1    1
6   1      out   1    1
7   1      out   1    1
8   1      out   1    1
9   2       in   1    1
10  2       in   1    1
11  2      out   0    0
12  2      out   1    0
13  2      out   1    0
14  3       in   1    0
15  3       in   1    0
16  3       in   0    0
17  3      out   1    1
18  3      out   1    1
19  4       in   1    1
20  4       in   1    1
21  4       in   1    1
22  4      out   1    0
23  4      out   0    0

第 11-13 行具有相同的“id”和“category”,但“yes”列具有不同的值。因此,“相同”列应标记为 0(因为它们不相同)。与第 14-16 行和第 22-23 行相同。

这是 df 的可重现代码:

structure(list(id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L), category = c("in", 
"in", "in", "in", "in", "out", "out", "out", "in", "in", "out", 
"out", "out", "in", "in", "in", "out", "out", "in", "in", "in", 
"out", "out"), yes = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
0L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 0L)), class = "data.frame", row.names = c(NA, -23L))

如有任何指导,我们将不胜感激!

我们可以使用 n_distinct 检查组中唯一元素的频率,转换为逻辑 (== 1),然后使用 as.integer+ 转换为二进制

library(dplyr)
df %>%
  group_by(id, category) %>% 
  mutate(same = +(n_distinct(yes) == 1)) %>% 
  ungroup

或使用data.table

library(data.table)
setDT(df)[, same := +(uniqueN(yes) == 1), by = .(id, category)]

一个选项,如果您的数据是 data.table。

在像本例这样的情况下,您只有一列要检查,我认为这不是一个好的解决方案。在那种情况下,您可以使用 uniqueN 就像@akrun 显示的那样。如果我没记错的话,当你在下面函数的 cols 参数中有很多行和很多列时,这会更快,因为在这种情况下要使用 uniqueN 你必须先创建一个data.table 来自要检查的列,每组检查一次(uniqueN 输入必须是矢量或 data.table)。但是,我没有任何基准,所以可能我记错了。

library(data.table)
setDT(df)

check_single_value <- function(df, col_uq, by, show_groups = FALSE) {
  n_uq <- unique(df[, c(col_uq, by), with = FALSE])[, .N, by = by]
  if (show_groups)
    n_uq[N > 1]
  else 
    n_uq[, !any(N > 1)]
}

check_single_value(df, 'yes', by = c('id', 'category'))
#> [1] FALSE

check_single_value(df, 'yes', by = c('id', 'category'), show_groups = T)
#>       id category     N
#>    <int>   <char> <int>
#> 1:     2      out     2
#> 2:     3       in     2
#> 3:     4      out     2

reprex package (v2.0.1)

于 2022-02-24 创建