用 dplyr 总结内部每个不同组的观察次数(n_distinct 等效?)

Count number of observations per distinct group inside summarise with dplyr (n_distinct equivalent?)

是否有一个函数可以像 n_distinct() 那样计算独特组内的观察次数,而不是不同组的数量?

我正在使用 dplyrgroup_by() 汇总数据,并且我正在尝试计算每个不同分组变量的观察次数的均值。

df<-data.frame(id=c('A', 'A', 'A', 'B', 'B', 'C','C','C'),
               id.2=c('1', '2', '2', '1','1','1','2','2'),
               v=c(sample(1:10, 8)))

df%>%
  group_by(id.2)%>%
  summarise(n.mean=mean(n_distinct(id)),
            v.mean=mean(v))

# A tibble: 2 × 3
  id.2  n.mean v.mean
  <chr>  <dbl>  <dbl>
1 1          3    5  
2 2          2    4.5

我需要的是:

id.2  n.mean v.mean
1          1    5  
2          2    4.5

因为
id.2==1 n.mean 是 A 的 1 个观察值,B 的 2 个观察值,C 的 1 个观察值的平均值,

> mean(1,2,1)
[1] 1

id.2==2 n.mean 是 A 的 2 个观察值的平均值,B 的 0 个,C 的 2 个,

mean(2,0,2)
[1] 2

我尝试先按 group_by(id, id.2) 分组以计算观察结果,然后在后续步骤中仅按 id.2 分组时传递这些计数,但这没有用(尽管我可能只是不我不知道如何用 dplyr 实现这个,因为我对 tidyverse 解决方案不是很有经验)

您没有正确使用 meanmean(1, 2, 1) 忽略除第一个参数以外的所有参数,因此无论第二个和第三个位置的其他数字是什么,都会 return 1 。对于 id.2 == 1,您需要 mean(c(1, 2, 1)),即 returns 1.333。

我们可以使用table快速计算id.2的每个分组中id的频率,然后取它们的平均值。我们可以在同一步骤中计算 v.mean

library(tidyverse)

df %>% 
  group_by(id.2) %>% 
  summarize(
    n.mean = mean(table(id)),
    v.mean = mean(v)
  ) 

  id.2  n.mean v.mean
  <chr>  <dbl>  <dbl>
1 1       1.33   4.25
2 2       2      6  

您的示例指出 id.2 == 2 没有 id == B 的任何值。不清楚您想要的解决方案是将其计为 zero-length 类别,还是干脆忽略它。上面的解决方案忽略了它。以下通过首先 complete-ing 输入数据将其作为 zero-length 类别包括(注意新行 #7,其中包含 NA 数据):

df_complete <- complete(df, id.2, id)

  id.2  id        v
  <chr> <chr> <int>
1 1     A         9
2 1     B         1
3 1     B         2
4 1     C         5
5 2     A         4
6 2     A         7
7 2     B        NA
8 2     C         3
9 2     C        10

我们可以将 id 转换为因子数据,这将迫使 table 即使在零长度分组中也能保持其独特的水平:

df_complete %>% 
  group_by(id.2) %>% 
  mutate(id = factor(id)) %>% 
  filter(!is.na(v)) %>% 
  summarize(
    n.mean = mean(table(id)),
    v.mean = mean(v, na.rm = T)
  )

  id.2  n.mean v.mean
  <chr>  <dbl>  <dbl>
1 1       1.33   4.25
2 2       1.33   6  

或不依赖于table的替代配方:

df_complete %>% 
  group_by(id.2, id) %>% 
  summarize(
    n_rows = sum(!is.na(v)), 
    id_mean = mean(v)
  ) %>% 
  group_by(id.2) %>% 
  summarize(
    n.mean = mean(n_rows),
    v.mean = weighted.mean(id_mean, n_rows, na.rm = T)
  )

  id.2  n.mean v.mean
  <chr>  <dbl>  <dbl>
1 1       1.33   4.25
2 2       1.33   6   

请注意,在提供随机示例数据时,您应该使用set.seed来控制随机化并确保可重复性。这是我使用的:

set.seed(0)
df<-data.frame(id=c('A', 'A', 'A', 'B', 'B', 'C','C','C'),
               id.2=c('1', '2', '2', '1','1','1','2','2'),
               v=c(sample(1:10, 8)))