【问题标题】:Calculating columns with row percentage after obtaining sums by group in dplyr在dplyr中按组获得总和后计算具有行百分比的列
【发布时间】:2016-03-08 06:40:45
【问题描述】:

使用dplyr 我正在为两个类别生成一个简单的汇总表:

# Data
data("mtcars")
# Lib
require(dplyr)
# Summary
mt_sum <- mtcars %>%
  group_by(am, gear) %>%
  summarise(n = n()) %>%
  spread(key = am, value = n)

这会产生预期的结果:

Source: local data frame [3 x 3]

   gear     0     1
  (dbl) (int) (int)
1     3    15    NA
2     4     4     8
3     5    NA     5

我想在生成的表中添加一组具有行百分比而不是当前可用总数的列。

期望的结果

我想让我的桌子看起来像这样:

   gear     0     1   0per   1per
1     3    15    NA   100%   
2     4     4     8   33%    67%    
3     5    NA     5          100%

尝试

我尝试通过添加代码来实现以下目标:

mt_sum <- mtcars %>%
  group_by(am, gear) %>%
  summarise(n = n()) %>%
  spread(key = am, value = n) %>%
  mutate_each(funs(./rowSums(.)))

但它返回以下错误:

Error: 'x' must be an array of at least two dimensions

因此我的问题是:如何在dplyr 中添加具有行百分比值的额外列?

支点

  • 我更喜欢空白值而不是NAs
  • 使用gmodels 中的CrossTable 可以轻松构建表格,但我想留在dplyr,因为我想在一个地方保留尽可能多的转换

【问题讨论】:

  • 当您说“空白值”时,您的意思是零吗?因为然后将 fill=0 添加到 spread() 可以解决此问题。 fill=" " 产生空白,但列是字符。
  • @atiretoo 感谢您的关注。我应该更准确,0 可以。同样出于导出目的,空字符串也可以。但我对此并不太挑剔,这只是一个侧面。

标签: r aggregate dplyr frequency crosstab


【解决方案1】:

我认为这是你需要的:

# Data
data("mtcars")
# Lib
require(dplyr)
require(tidyr)
require(scales) #for percent
# Summary
mtcars %>%
  group_by(am, gear) %>%
  summarise(n = n()) %>%
  spread(key = am, value = n) %>%
  #you need rowwise because this is a rowwise operation
  rowwise %>%
  #I find do to be the best function for ad-hoc things that 
  #have no specific dplyr function
  #I use do below to calculate the numeric percentages
  do(data.frame(.,
                per0 = .$`0` / sum(.$`0`, .$`1`, na.rm=TRUE),
                per1 = .$`1` / sum(.$`0`, .$`1`, na.rm=TRUE))) %>%
  #mutate here is used to convert NAs to blank and numbers to percentages
  mutate(per0 = ifelse(is.na(per0), '', percent(per0)),
         per1 = ifelse(is.na(per1), '', percent(per1)))

输出:

Source: local data frame [3 x 5]
Groups: <by row>

   gear    X0    X1  per0  per1
  (dbl) (int) (int) (chr) (chr)
1     3    15    NA  100%      
2     4     4     8 33.3% 66.7%
3     5    NA     5        100%

【讨论】:

  • 感谢您的出色解决方案,有没有办法动态创建per0 和per1?我希望能够将此解决方案应用于我可能有多个组的data.frame?
  • 谢谢@Konrad,我很高兴能帮上忙。我会将您重定向到this。您可能应该使用na.omit 以使行数保持不变。
  • 非常感谢,我在寻找 NA 解决方案时看到了那个帖子。
  • @Konrad 我怀疑你可以在下一步使用do 和mutate_each 中的lapply。如果您想在不指定名称的情况下进行多列操作,那么 dplyr 中的很多事情都会发生变化。很可能您无论如何都必须写下一些列名。
  • 非常感谢,我去看看。
【解决方案2】:

这是一种重塑形状的方法:

库(dplyr) 图书馆(tidyr)

mtcars %>%
  count(gear, am) %>%
  mutate(percent = n / sum(n)) %>%
  gather(variable, value, 
         n, percent) %>%
  unite("new_variable", am, variable) %>%
  spread(new_variable, value)

【讨论】:

  • 英里是我认为最优雅的解决方案。
【解决方案3】:

所以这会在其中部分完成,但不会在单个表达式中完成所有操作,也不会重命名变量。 @LyzanderR 的解决方案更好。

library(tidyr)
library(dplyr)
mt_sum <- mtcars %>%
  group_by(am, gear) %>%
  summarise(n = n()) %>%
  spread(key = am, value = n, fill=0) 
row_sum <- rowSums(mt_sum[,2:3])
mt_sum <- mutate_each(mt_sum[,2:3],funs(./row_sum)) %>% bind_cols(mt_sum)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-23
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多