使用 lapply 和 dplyr 计算跨多个列的组列的描述性统计数据(均值、sd、n),从而产生 NA 值

Compute descriptive statistics (mean, sd, n) by a group column across multiple columns using lapply and dplyr resulting in NA values

我有一个组列指示组成员身份以及许多其他包含数值的列。对于包含数值的每一列,我想获得每个子组的均值、标准差和样本量。

以内置的鸢尾花数据集为例,我想出了以下代码:

lapply(names(iris)[1:4], function(x) {
  iris %>%
    group_by(Species) %>%
    summarise(mean = mean(noquote(x), na.rm = T),
              sd = sd(noquote(x), na.rm = T),
              n = n())
})

但是,每组数字列的平均值和标准差是 NA。 R 提供了大量警告消息,例如:

In mean.default(noquote(x), na.rm = T) :参数不是数字或逻辑:返回 NA

在 is.data.frame(x) 中:强制引入的 NAs

但是,我已确保我的数字列已经具有数字数据类型。

我也尝试过使用across函数,但结果显然是错误的:

iris %>%
  group_by(Species) %>%
  summarise(across(1:4, ~ mean(., na.rm = T),
                   sd(., na.rm = T),
                   n()))

我的实际数据集中每个数值列中的 NA 数量 of/position 因数值列而异。该解决方案必须使用该特定列的所有非 NA 值计算每个组的 mean/SD/sample 大小。谢谢!

使用 across 是正确的方法,您只需要修正语法即可。

library(dplyr)
library(tidyr)

iris %>%
  group_by(Species) %>%
  summarise(across(1:4, list(mean = ~mean(., na.rm = T),
                               sd = ~sd(., na.rm = T),
                               Count = ~n())))

# A tibble: 3 x 13
#  Species    Sepal.Length_mean Sepal.Length_sd Sepal.Length_Count Sepal.Width_mean
#  <fct>                  <dbl>           <dbl>              <int>            <dbl>
#1 setosa                  5.01           0.352                 50             3.43
#2 versicolor              5.94           0.516                 50             2.77
#3 virginica               6.59           0.636                 50             2.97
# … with 8 more variables: Sepal.Width_sd <dbl>, Sepal.Width_Count <int>,
#   Petal.Length_mean <dbl>, Petal.Length_sd <dbl>, Petal.Length_Count <int>,
#   Petal.Width_mean <dbl>, Petal.Width_sd <dbl>, Petal.Width_Count <int>

也许添加 pivot_longer 会使输出更好 -

iris %>%
  group_by(Species) %>%
  summarise(across(1:4, list(mean = ~mean(., na.rm = T),
                               sd = ~sd(., na.rm = T),
                               Count = ~n()))) %>%
  pivot_longer(cols = -Species, 
               names_to = c('name', '.value'), 
               names_sep = '_')

#  Species    name          mean    sd Count
#   <fct>      <chr>        <dbl> <dbl> <int>
# 1 setosa     Sepal.Length 5.01  0.352    50
# 2 setosa     Sepal.Width  3.43  0.379    50
# 3 setosa     Petal.Length 1.46  0.174    50
# 4 setosa     Petal.Width  0.246 0.105    50
# 5 versicolor Sepal.Length 5.94  0.516    50
# 6 versicolor Sepal.Width  2.77  0.314    50
# 7 versicolor Petal.Length 4.26  0.470    50
# 8 versicolor Petal.Width  1.33  0.198    50
# 9 virginica  Sepal.Length 6.59  0.636    50
#10 virginica  Sepal.Width  2.97  0.322    50
#11 virginica  Petal.Length 5.55  0.552    50
#12 virginica  Petal.Width  2.03  0.275    50