dplyr:按学校分组的因子计数/百分比未被分组

6

我有一个长数据集,每个个体都与学校分组。每行都有一个有序因子{1,2,3,4},“cats”。我想在每个学校内获取1、2、3和4的百分比。数据集如下:

  school_number           cats
1          10505             3
2          10505             3
3          10502             1
4          10502             1
5          10502             2
6          10502             1
7          10502             1
8          10502             2
10         10503             3
11         10505             2

我尝试了类似于这样的东西:
df_pcts <- df %>%
   group_by(school_number) %>%
   mutate(total=sum(table(cats))) %>%
   summarize(cat_pct = table(cats)/total)

但是通过mutate()步骤生成的total variable会在每行中显示总行数。我甚至不能进行最终的summarize步骤。我很困惑。

P.S. 在其他帖子中,我看到了像这样的行:

n = n()

当我这样做时,会收到一条消息,内容如下:
Error in n() : This function should not be called directly

这是从哪里来的?

谢谢你!


你需要什么输出?是为1、2、3只猫分别设置列,还是为每个学校/猫组合分别设置行? - jalapic
你也可以使用 df %>% group_by(school_number, cats) %>% summarise(n=n()) %>% mutate(pct=100*n/sum(n)) - akrun
请在您的会话中键入 mutate,并确认输出的最后一行是否为 <environment: namespace:dplyr>?如果输出是 <environment: namespace:plyr>,那么这正是问题所在:在加载 dplyr 之后,某种方式加载了 plyr(而 plyr 的 mutate 不会注意 group_by)。这是“group_by 不起作用”的常见原因(尽管不是唯一的原因)。 - David Robinson
1
@DavidRobinson,是的,非分组是由于混合使用plyr和dplyr mutates引起的。但即使我解决了这个问题,我的代码仍然在使用table时失败,并显示以下消息:Error in summarise_impl(.data, named_dots(...), environment()) : dims [product 4] do not match the length of object [18] 但下面的解决方案运行良好。 - Stuart
@akrun,谢谢你的回复,但是当我尝试使用n()时仍然出现错误。这个函数从哪里来? - Stuart
@Stuart 你是在 summarize 函数内部使用 n() 吗?那就是它应该被使用的地方。如果你仍然遇到错误,也许你可以展示一个完整的可复现的例子(可能需要新开一个问题,因为这与当前问题无关)。 - David Robinson
3个回答

9
也许这可以帮助你,虽然我不完全确定你需要什么输出。
使用计算df中每个school_number / cat组合的行数。然后通过仅按school_number分组来计算每个学校中“cat”的百分比。请注意保留html标记。
df %>%
  group_by(school_number,cats) %>%
  tally  %>%
  group_by(school_number) %>%
  mutate(pct=(100*n)/sum(n))

它给出了以下内容:
  #    school_number cats n       pct
  #  1         10502    1 4  66.66667
  #  2         10502    2 2  33.33333
  #  3         10503    3 1 100.00000
  #  4         10505    2 1  33.33333
  #  5         10505    3 2  66.66667

编辑:

如果您的样本数据中缺少0%的行,您可以执行以下操作。将上面的输出与包含所有school_number/cats组合的0%的df绑定在一起。只保留此绑定的第一个实例(如果存在值>0%,则始终包含)。然后按学校编号和类别进行排列以便阅读:

y<-df %>%
  group_by(school_number,cats) %>%
  tally  %>%
  group_by(school_number) %>%
  mutate(pct=(100*n)/sum(n)) %>%
  select(-n) 

x<-data.frame(school_number=rep(unique(df$school_number),each=4), cats=1:4,pct=0)  

rbind(y,x) %>%
  group_by(school_number,cats)%>%
  filter(row_number() == 1) %>%
  arrange(school_number,cats)

这将会得到:

#   school_number cats       pct
#1          10502    1  66.66667
#2          10502    2  33.33333
#3          10502    3   0.00000
#4          10502    4   0.00000
#5          10503    1   0.00000
#6          10503    2   0.00000
#7          10503    3 100.00000
#8          10503    4   0.00000
#9          10505    1   0.00000
#10         10505    2  33.33333
#11         10505    3  66.66667
#12         10505    4   0.00000

0

正如@akrun所建议的那样,您可能之前已经调用了plyrdplyr包。由于summaris(z)e在两个包中都是有效的,您可以通过在函数名之前添加包来指定,例如dplyr::fun(argument...)


0

将学校编号和猫的所有组合进行左连接,以计算百分比。如果为NA,则为0。

expand.grid(school_number =  unique(df$school_number), cats = levels(df$cats)) %>%
  left_join(df %>%
              group_by(school_number, cats) %>%
              tally %>%
              mutate(pct = (n / sum(n) * 100))) %>%
  select(-n) %>%
  mutate(pct = ifelse(is.na(pct), 0, pct)) %>%
  arrange(school_number)

这提供了

   school_number cats       pct
1          10502    1  66.66667
2          10502    2  33.33333
3          10502    3   0.00000
4          10502    4   0.00000
5          10503    1   0.00000
6          10503    2   0.00000
7          10503    3 100.00000
8          10503    4   0.00000
9          10505    1   0.00000
10         10505    2  33.33333
11         10505    3  66.66667
12         10505    4   0.00000

1
虽然这段代码片段可能解决了问题,但加上解释确实有助于提高您的帖子质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议原因。 - J. Chomel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接