如何计算按列名分组的数据框/矩阵中的平均值和标准差

Posted

技术标签:

【中文标题】如何计算按列名分组的数据框/矩阵中的平均值和标准差【英文标题】:How to calculate mean and standard deviation in a dataframe/matrix grouped by column name 【发布时间】:2021-11-02 00:50:16 【问题描述】:

示例数据:

sun sun sun sky sky
1 1.0 2.0 1.1 4.0 9.8
2 3.7 1.0 1.0 3.3 NA
3 1.5 0.4 2.1 3.3 6.0
4 3.7 NA 3.6 3.1 5.6
5 2.9 1.1 10.0 7.1 7.7
6 7.0 4.9 6.9 5.4 4.9

我想计算每个唯一列名的平均值和标准差(忽略 NA)以获得如下输出:

mean sd
sun 3.170588235 2.677630647
sky 5.472727273 2.102422845

可重现的数据:

df <- data.frame(c(1, 3.7, 1.5, 3.7, 2.9, 7),
                 c(2, 1, 0.4, NA, 1.1, 4.9),
                 c(1.1, 1, 2.1, 3.6, 10, 6.9),
                 c(4, 3.3, 3.3, 3.1, 7.1, 5.4),
                 c(9.8, NA, 6, 5.6, 7.7, 4.9))
names(df) <- c("sun", "sun", "sun", "sky", "sky")

我得到的最接近的是

#for mean
sapply(split.default(df, names(df)), rowMeans, na.rm = TRUE) 

#for sd
sapply(split.default(df, names(df)), function(x) apply(x, 1, sd, na.rm=TRUE))

我从这个post 得到的,但我不知道如何调整它以获得我想要的。我知道我可以取 rowmeans 的平均值来获得每个组的平均值,但这不适用于标准差。

【问题讨论】:

【参考方案1】:

我们可以使用

t(sapply(split.default(df, names(df)), function(x)  
    x1 <- unlist(x)
    data.frame(mean = mean(x1, na.rm = TRUE), sd = sd(x1, na.rm = TRUE))))

-输出

       mean     sd      
sky 5.472727 2.102423
sun 3.170588 2.677631

或使用data.table

library(data.table)
melt(setDT(df), measure = patterns("^sun", "^sky"), 
  value.name = c("sun", "sky"))[, c(list(categ = c("mean", "sd")), 
    lapply(.SD, function(x) c(mean = mean(x, na.rm = TRUE), 
     sd = sd(x, na.rm = TRUE)))), .SDcols = sun:sky]
   categ      sun      sky
1:  mean 3.170588 5.472727
2:    sd 2.677631 2.102423

【讨论】:

【参考方案2】:

这里是tidyverse 解决方案

library(tidyverse)

样本数据

df <- data.frame(c(1, 3.7, 1.5, 3.7, 2.9, 7),
                 c(2, 1, 0.4, NA, 1.1, 4.9),
                 c(1.1, 1, 2.1, 3.6, 10, 6.9),
                 c(4, 3.3, 3.3, 3.1, 7.1, 5.4),
                 c(9.8, NA, 6, 5.6, 7.7, 4.9))
names(df) <- c("sun", "sun", "sun", "sky", "sky")

代码

df %>%
  #Pivotting data
  pivot_longer(cols = everything()) %>%
  #Grouping by sun/sky
  group_by(name) %>% 
  #Caluclating mean and sg grouped by sun/sky
  summarise(
    mean = mean(value,na.rm = T),
    sd = sd(value,na.rm = T)
  )

输出

  name   mean    sd
  <chr> <dbl> <dbl>
1 sky    5.47  2.10
2 sun    3.17  2.68

【讨论】:

【参考方案3】:

这是dplyr 中的另一种方法,将相似命名列的值放在一个列中,然后对它们计算meansd

library(dplyr)
library(tidyr)

df %>%
  pivot_longer(cols = everything(), 
               names_to = '.value') %>%
  summarise(across(.fns = list(mean = ~mean(., na.rm = TRUE), 
                              sd = ~sd(., na.rm = TRUE))))

#  sun_mean sun_sd sky_mean sky_sd
#     <dbl>  <dbl>    <dbl>  <dbl>
#1     3.17   2.68     5.47   2.10

如果您希望 meansd 值在单独的列中,您可以添加到上述答案 -

 %>% pivot_longer(cols = everything(), names_to = c('col', '.value'), names_sep = '_')

#  col    mean    sd
#  <chr> <dbl> <dbl>
#1 sun    3.17  2.68
#2 sky    5.47  2.10

【讨论】:

【参考方案4】:

您可以使用以下解决方案:

t(as.data.frame(split.default(df, names(df)) |>
  sapply(\(x) unlist(data.frame(mean = mean(unlist(x), na.rm = TRUE),
                          sd = sd(unlist(x), na.rm = TRUE)))))) |> 
  as.data.frame()

        mean       sd
sky 5.472727 2.102423
sun 3.170588 2.677631

【讨论】:

【参考方案5】:
df = data.frame(c(1, 3.7, 1.5, 3.7, 2.9, 7),
c(2, 1, 0.4, NA, 1.1, 4.9),
c(1.1, 1, 2.1, 3.6, 10, 6.9),
c(4, 3.3, 3.3, 3.1, 7.1, 5.4),
c(9.8, NA, 6, 5.6, 7.7, 4.9))
names(df) <- c("sun1", "sun2", "sun3", "sky1", "sky2") # it's good to have unique names

我们需要做一些重塑(变长)。作为 base-r 的倡导者,我会使用stats::reshape

但是,我们需要在 data.frame 中再添加一个sky columnNAs),这样reshape 才能工作,但这不会对稍后的计算产生任何影响,因为我们'将使用na.rm=T

df[, 'sky3'] = rep(NA, nrow(df))

df_long = reshape(df, direction = 'long', varying = c(1:3, 4:6), sep="", times=1:3)

df_long 

    time  sun sky  id
1.1    1  1.0 4.0  1
2.1    1  3.7 3.3  2
3.1    1  1.5 3.3  3
4.1    1  3.7 3.1  4
5.1    1  2.9 7.1  5
6.1    1  7.0 5.4  6
1.2    2  2.0 9.8  1
2.2    2  1.0  NA  2
3.2    2  0.4 6.0  3
4.2    2   NA 5.6  4
5.2    2  1.1 7.7  5
6.2    2  4.9 4.9  6
1.3    3  1.1  NA  1
2.3    3  1.0  NA  2
3.3    3  2.1  NA  3
4.3    3  3.6  NA  4
5.3    3 10.0  NA  5
6.3    3  6.9  NA  6

lapply(df_long[, c('sun', 'sky')],
 \(x, na.rm=T) list(mean=mean(x, na.rm=na.rm), sd=sd(x, na.rm=na.rm))) |> 
do.call(what = rbind)
    mean     sd      
sun 3.170588 2.677631
sky 5.472727 2.102423

【讨论】:

以上是关于如何计算按列名分组的数据框/矩阵中的平均值和标准差的主要内容,如果未能解决你的问题,请参考以下文章

R中具有多个分组因子的多个变量的均值和标准差

为data.frame中的多个变量按组计算平均值和标准差

R语言使用psych包的describeBy函数计算不同分组(group)的描述性统计值(样本个数均值标准差中位数剔除异常均值最小最大值数据范围极差偏度峰度均值标准差等)

Python | Numpy:详解计算矩阵的均值和标准差

Python | Numpy:详解计算矩阵的均值和标准差

如何使用 Pandas 中的数据透视表计算标准差?