dplyr 中的 boxplot.stats 与组

MrG*_*ble 4 r dplyr purrr

我需要计算包含许多组的 data.frame 的箱线图统计数据。

我理想中需要的是:

library(dplyr)
iris %>%
  group_by(Species) %>%
  summarise(boxplot=boxplot.stats(Sepal.Length))) # + some kind of magic

# A tibble: 3 x 6
  Species    lower_whisker lower_hinge median upper_hinge upper_whisker
  <fct>              <dbl>       <dbl>  <dbl>       <dbl>         <dbl>
1 setosa               4.3         4.8    5           5.2           5.8
2 versicolor           4.9         5.6    5.9         6.3           7  
3 virginica            5.6         6.2    6.5         6.9           7.9
Run Code Online (Sandbox Code Playgroud)

但到目前为止,我已经成功地完成了半purrr映射,但无法解压它。

boxplot.stats2 <- function(x, ...) {
  res <- boxplot.stats(x, ...)
  res <- res$stats
  names(res) <- c('lower_whisker','lower_hinge','median','upper_hinge','upper_whisker')
  #t(as.data.frame(res))
  res
}

iris %>%
  group_by(Species) %>%
  summarise(boxplot=list(boxplot.stats2(Sepal.Length)),
    #manual unpacking
    lower_whisker = boxplot[[1]]['lower_whisker'],
    lower_hinge = boxplot[[1]]['lower_hinge'],
    median = boxplot[[1]]['median'],
    upper_hinge = boxplot[[1]]['upper_hinge'],
    upper_whisker = boxplot[[1]]['upper_whisker']
  )
Run Code Online (Sandbox Code Playgroud)

它给出了相同的结果,但我怀疑应该有一个更优雅的解决方案。

aos*_*ith 5

如果您使用列表作为摘要输出,则可以使用tidyrunnest()包中的函数。

新版本的tidyr有一些新功能,包括unnest_wider(),这是适合您情况的方便工具。

在这里,我将仅获取箱线图统计数据的 5 个数字,并将它们放入 的列表中summarise(),就像您开始做的那样。我还命名了它们,因为统计数据boxplot.stats()没有任何识别信息。

新列是一个列表列,其中包含每个物种的 5 个值的命名向量。

library(dplyr)
library(tidyr) # development version, tidyr_0.8.3.9000

iris %>%
    group_by(Species) %>%
    summarise(boxplot= list( setNames(boxplot.stats(Sepal.Length)$stats,
                                      c('lower_whisker','lower_hinge','median','upper_hinge','upper_whisker') ) ) )

# A tibble: 3 x 2
  Species    boxplot  
  <fct>      <list>   
1 setosa     <dbl [5]>
2 versicolor <dbl [5]>
3 virginica  <dbl [5]>
Run Code Online (Sandbox Code Playgroud)

接下来就unnest_wider()可以得到想要的结果。

iris %>%
    group_by(Species) %>%
    summarise(boxplot= list( setNames(boxplot.stats(Sepal.Length)$stats,
                                      c('lower_whisker','lower_hinge','median','upper_hinge','upper_whisker') ) ) ) %>%
    unnest_wider(boxplot)

# A tibble: 3 x 6
  Species    lower_whisker lower_hinge median upper_hinge upper_whisker
  <fct>              <dbl>       <dbl>  <dbl>       <dbl>         <dbl>
1 setosa               4.3         4.8    5           5.2           5.8
2 versicolor           4.9         5.6    5.9         6.3           7  
3 virginica            5.6         6.2    6.5         6.9           7.9
Run Code Online (Sandbox Code Playgroud)

您可以跳过命名步骤,但您需要在最后命名列。

iris %>%
    group_by(Species) %>%
    summarise(boxplot= list( boxplot.stats(Sepal.Length)$stats ) ) %>%
    unnest_wider(boxplot)

# A tibble: 3 x 6
  Species     ...1  ...2  ...3  ...4  ...5
  <fct>      <dbl> <dbl> <dbl> <dbl> <dbl>
1 setosa       4.3   4.8   5     5.2   5.8
2 versicolor   4.9   5.6   5.9   6.3   7  
3 virginica    5.6   6.2   6.5   6.9   7.9
Run Code Online (Sandbox Code Playgroud)

旧版本的tidyr(1.0.0 之前)仍然可以在这里提供帮助,尽管这项工作需要执行更多步骤。由于列表名称在当前中丢失,因此unnest()您需要在取消嵌套之前手动添加这些名称,以便可以spread()添加到新列中。

iris %>%
group_by(Species) %>%
summarise(boxplot= list( boxplot.stats(Sepal.Length)$stats),
          stat = list( c('lower_whisker','lower_hinge','median','upper_hinge','upper_whisker') ) ) %>%
unnest(stat, boxplot) %>%
spread(stat, boxplot)

# A tibble: 3 x 6
  Species    lower_hinge lower_whisker median upper_hinge upper_whisker
  <fct>            <dbl>         <dbl>  <dbl>       <dbl>         <dbl>
1 setosa             4.8           4.3    5           5.2           5.8
2 versicolor         5.6           4.9    5.9         6.3           7  
3 virginica          6.2           5.6    6.5         6.9           7.9
Run Code Online (Sandbox Code Playgroud)