R语言 数据分组汇总:求平均值、标准差、标准误

羊&鹿 2024-07-25 11:05:03 阅读 79

Summarizing data 汇总数据

当你想按组对数据进行汇总(包括平均值、标准差等)

这里介绍的三种方法可以根据某些指定变量对数据进行分组

并对每组应用汇总函数(如平均值、标准差等):

1、函数 <code>ddply() ,来自 plyr 包,最容易使用的

2、函数 summarizeBy() ,来自 doBy 包,比较容易使用

3、函数 aggregate() ,来自R base 包,较难使用

示例数据

不同性别受试者,服用阿斯匹林或安慰剂前后的观测值以及变化差值

由性别和条件的组合来分组:F-安慰剂、F-阿司匹林、M-安慰剂和 M-阿司匹林

并希望计算出每个组的:

1) N(个体数)

2) mean of change(变化均值)

3) standard deviation(标准差)

4) standard error of the mean (均值标准误差)

data <- read.table(header=TRUE, text='

subject sex condition before after change

1 F placebo 10.1 6.9 -3.2

2 F placebo 6.3 4.2 -2.1

3 M aspirin 12.4 6.3 -6.1

4 F placebo 8.1 6.1 -2.0

5 M aspirin 15.2 9.9 -5.3

6 F aspirin 10.9 7.0 -3.9

7 F aspirin 11.6 8.5 -3.1

8 M aspirin 9.5 3.0 -6.5

9 F placebo 11.5 9.0 -2.5

10 M placebo 11.9 11.0 -0.9

11 F aspirin 11.4 8.0 -3.4

12 M aspirin 10.0 4.4 -5.6

13 M aspirin 12.5 5.4 -7.1

14 M placebo 10.6 10.6 0.0

15 M aspirin 9.1 4.3 -4.8

16 F placebo 12.1 10.2 -1.9

17 F placebo 11.0 8.8 -2.2

18 F placebo 11.9 10.2 -1.7

19 M aspirin 9.1 3.6 -5.5

20 M placebo 13.5 12.4 -1.1

21 M aspirin 12.0 7.5 -4.5

22 F placebo 9.1 7.6 -1.5

23 M placebo 9.9 8.0 -1.9

24 F placebo 7.6 5.2 -2.4

25 F placebo 11.8 9.7 -2.1

26 F placebo 11.8 10.7 -1.1

27 F aspirin 10.1 7.9 -2.2

28 M aspirin 11.6 8.3 -3.3

29 F aspirin 11.3 6.8 -4.5

30 F placebo 10.3 8.3 -2.0

')code>


1、使用 ddply()

library(plyr)

# ddply参数

ddply(data, variables, fun = NULL, ... , progress = 'none' , drop = TRUE , parallel = FALSE)

# - data : 要处理的数据框

# - variables :分组变量,可以是公式,也可以是字符向量

# - fun:处理分组数据的函数

cdata <- ddply(data, c("sex", "condition"), summarise,

N = length(change), # 长度即总数

mean = mean(change), # 求平均值

sd = sd(change), # 求标准差

se = sd / sqrt(N) # 求标准误

)

cdata

#> sex condition N mean sd se

#> 1 F aspirin 5 -3.420000 0.8642916 0.3865230

#> 2 F placebo 12 -2.058333 0.5247655 0.1514867

#> 3 M aspirin 9 -5.411111 1.1307569 0.3769190

#> 4 M placebo 4 -0.975000 0.7804913 0.3902456

处理丢失的数据:

如果数据中有 NA 值,就需要设定参数 na.rm=TRUE

length() 没有 na.rm 这个选项,因此只能 sum(!is.na(...)) 来计算有多少个非 NA

# 先放一点NA值进来

dataNA <- data

dataNA$change[11:14] <- NA

cdata <- ddply(dataNA, c("sex", "condition"), summarise,

N = sum(!is.na(change)),

mean = mean(change, na.rm=TRUE),

sd = sd(change, na.rm=TRUE),

se = sd / sqrt(N)

)

cdata

#> sex condition N mean sd se

#> 1 F aspirin 4 -3.425000 0.9979145 0.4989572

#> 2 F placebo 12 -2.058333 0.5247655 0.1514867

#> 3 M aspirin 7 -5.142857 1.0674848 0.4034713

#> 4 M placebo 3 -1.300000 0.5291503 0.3055050


2、函数 summarizeBy()

library(doBy)

cdata <- summaryBy(change ~ sex + condition, data=data, FUN=c(length,mean,sd))

cdata

#> sex condition change.length change.mean change.sd

#> 1 F aspirin 5 -3.420000 0.8642916

#> 2 F placebo 12 -2.058333 0.5247655

#> 3 M aspirin 9 -5.411111 1.1307569

#> 4 M placebo 4 -0.975000 0.7804913

# 重命名 change.length 这一列为 N

names(cdata)[names(cdata)=="change.length"] <- "N"

# 计算标准误

cdata$change.se <- cdata$change.sd / sqrt(cdata$N)

cdata

#> sex condition N change.mean change.sd change.se

#> 1 F aspirin 5 -3.420000 0.8642916 0.3865230

#> 2 F placebo 12 -2.058333 0.5247655 0.1514867

#> 3 M aspirin 9 -5.411111 1.1307569 0.3769190

#> 4 M placebo 4 -0.975000 0.7804913 0.3902456

处理丢失数据:

na.rm=TRUE 可以传递给 summaryBy() 调用的每个函数,除了 length()

# 写一个新版本的 length 让它可以识别 na.rm=T

length2 <- function (x, na.rm=FALSE) {

if (na.rm) sum(!is.na(x))

else length(x)

}

dataNA <- data

dataNA$change[11:14] <- NA

cdataNA <- summaryBy(change ~ sex + condition, data=dataNA,

FUN=c(length2, mean, sd), na.rm=TRUE)

cdataNA

#> sex condition change.length2 change.mean change.sd

#> 1 F aspirin 4 -3.425000 0.9979145

#> 2 F placebo 12 -2.058333 0.5247655

#> 3 M aspirin 7 -5.142857 1.0674848

#> 4 M placebo 3 -1.300000 0.5291503


扩充:安排一步得出均值、计数、标准差、标准误和置信区间的函数summarySE

写函数:

## 对数据进行汇总

## 得到 计数, 均值, 标准差, 标准误 和 置信区间 (95%).

## data: 数据框

## measurevar: 需要进行汇总的列

## groupvars: 提供分组的列

## na.rm: 一个布尔值,决定是否忽略NA

## conf.interval: 置信区间的百分比范围 (默认是 95%)

summarySE <- function(data=NULL, measurevar, groupvars=NULL, na.rm=FALSE,

conf.interval=.95, .drop=TRUE) {

library(plyr)

# 一个新版本的 length 让它可以识别 na.rm=T

length2 <- function (x, na.rm=FALSE) {

if (na.rm) sum(!is.na(x))

else length(x)

}

# 这一步开始汇总.

datac <- ddply(data, groupvars, .drop=.drop,

.fun = function(xx, col) {

c(N = length2(xx[[col]], na.rm=na.rm),

mean = mean (xx[[col]], na.rm=na.rm),

sd = sd (xx[[col]], na.rm=na.rm)

)

},

measurevar

)

# 重命名 均值 这一列

datac <- rename(datac, c("mean" = measurevar))

datac$se <- datac$sd / sqrt(datac$N) # 计算标准误

# 标准误的置信区间乘数

# 计算置信区间的t统计量:

# 例如, 置信区间是.95, 则使用 .975 (高于/低于), 并使用 df=N-1

ciMult <- qt(conf.interval/2 + .5, datac$N-1)

datac$ci <- datac$se * ciMult

return(datac)

}

示例计算:一部得到以上所有汇总信息

summarySE(data, measurevar="change", groupvars=c("sex", "condition"))code>

#> sex condition N change sd se ci

#> 1 F aspirin 5 -3.420000 0.8642916 0.3865230 1.0731598

#> 2 F placebo 12 -2.058333 0.5247655 0.1514867 0.3334201

#> 3 M aspirin 9 -5.411111 1.1307569 0.3769190 0.8691767

#> 4 M placebo 4 -0.975000 0.7804913 0.3902456 1.2419358

# 当有 NA 值时, 使用 na.rm=TRUE

summarySE(dataNA, measurevar="change", groupvars=c("sex", "condition"), na.rm=TRUE)code>

#> sex condition N change sd se ci

#> 1 F aspirin 4 -3.425000 0.9979145 0.4989572 1.5879046

#> 2 F placebo 12 -2.058333 0.5247655 0.1514867 0.3334201

#> 3 M aspirin 7 -5.142857 1.0674848 0.4034713 0.9872588

#> 4 M placebo 3 -1.300000 0.5291503 0.3055050 1.3144821

用NA填充空白组合:

有时,汇总数据框中会出现空的因子组合,即有可能出现的因素组合,但实际上并没有出现在原始数据框架中。

在汇总数据框中自动用 NA 填入这些组合通常很有用。

为此,在调用 ddply()summarySE() 时设置 .drop=FALSE

用法示例:

# 首先把 男性+安慰剂 组合的数据删去

dataSub <- subset(data, !(sex=="M" & condition=="placebo"))

# 这样我们汇总数据时,男性+安慰剂 组合就会有空缺列

summarySE(dataSub, measurevar="change", groupvars=c("sex", "condition"))code>

#> sex condition N change sd se ci

#> 1 F aspirin 5 -3.420000 0.8642916 0.3865230 1.0731598

#> 2 F placebo 12 -2.058333 0.5247655 0.1514867 0.3334201

#> 3 M aspirin 9 -5.411111 1.1307569 0.3769190 0.8691767

# 设置 .drop=FALSE 不放弃这些组合

summarySE(dataSub, measurevar="change", groupvars=c("sex", "condition"), .drop=FALSE)code>

#> Warning in qt(conf.interval/2 + 0.5, datac$N - 1): NaNs produced

#> sex condition N change sd se ci

#> 1 F aspirin 5 -3.420000 0.8642916 0.3865230 1.0731598

#> 2 F placebo 12 -2.058333 0.5247655 0.1514867 0.3334201

#> 3 M aspirin 9 -5.411111 1.1307569 0.3769190 0.8691767

#> 4 M placebo 0 NaN NA NA NA

用0填充空白组合:

原理同上,但改用0填充

写用0填充的函数:

fillMissingCombs <- function(df, factors, measures) {

# 列出因子level的组合列表

levelList <- list()

for (f in factors) { levelList[[f]] <- levels(df[,f]) }

fullFactors <- expand.grid(levelList)

dfFull <- merge(fullFactors, df, all.x=TRUE)

# 如果测量值中有 NA ,就用 0 代替

for (m in measures) {

dfFull[is.na(dfFull[,m]), m] <- 0

}

return(dfFull)

}

用法举例:

# 首先把 男性+安慰剂 组合的数据删去

dataSub <- subset(data, !(sex=="M" & condition=="placebo"))

cdataSub <- summarySE(dataSub, measurevar="change", groupvars=c("sex", "condition"))code>

cdataSub

#> sex condition N change sd se ci

#> 1 F aspirin 5 -3.420000 0.8642916 0.3865230 1.0731598

#> 2 F placebo 12 -2.058333 0.5247655 0.1514867 0.3334201

#> 3 M aspirin 9 -5.411111 1.1307569 0.3769190 0.8691767

# 用0填充空白组合

fillMissingCombs(cdataSub, factors=c("sex","condition"), measures=c("N","change","sd","se","ci"))

#> sex condition N change sd se ci

#> 1 F aspirin 5 -3.420000 0.8642916 0.3865230 1.0731598

#> 2 F placebo 12 -2.058333 0.5247655 0.1514867 0.3334201

#> 3 M aspirin 9 -5.411111 1.1307569 0.3769190 0.8691767

#> 4 M placebo 0 0.000000 0.0000000 0.0000000 0.0000000


3、使用R自带的aggregate()

缺点是步骤较为繁琐

优点是不用安装新的R包

# 统计每个类别(性别*条件)中的受试者人数

cdata <- aggregate(data["subject"], by=data[c("sex","condition")], FUN=length)

cdata

#> sex condition subject

#> 1 F aspirin 5

#> 2 M aspirin 9

#> 3 F placebo 12

#> 4 M placebo 4

# 重命名 "subject" 这一列为 "N"

names(cdata)[names(cdata)=="subject"] <- "N"

cdata

#> sex condition N

#> 1 F aspirin 5

#> 2 M aspirin 9

#> 3 F placebo 12

#> 4 M placebo 4

# 按 sex 排序

cdata <- cdata[order(cdata$sex),]

cdata

#> sex condition N

#> 1 F aspirin 5

#> 3 F placebo 12

#> 2 M aspirin 9

#> 4 M placebo 4

# 同时保留 __before__ 和 __after__ 这两列:

# 按性别和条件获取平均效应大小

cdata.means <- aggregate(data[c("before","after","change")],

by = data[c("sex","condition")], FUN=mean)

cdata.means

#> sex condition before after change

#> 1 F aspirin 11.06000 7.640000 -3.420000

#> 2 M aspirin 11.26667 5.855556 -5.411111

#> 3 F placebo 10.13333 8.075000 -2.058333

#> 4 M placebo 11.47500 10.500000 -0.975000

# 合并数据框

cdata <- merge(cdata, cdata.means)

cdata

#> sex condition N before after change

#> 1 F aspirin 5 11.06000 7.640000 -3.420000

#> 2 F placebo 12 10.13333 8.075000 -2.058333

#> 3 M aspirin 9 11.26667 5.855556 -5.411111

#> 4 M placebo 4 11.47500 10.500000 -0.975000

# 获取 "change"的样本 (n-1) 标准差

cdata.sd <- aggregate(data["change"],

by = data[c("sex","condition")], FUN=sd)

# 重命名为 change.sd

names(cdata.sd)[names(cdata.sd)=="change"] <- "change.sd"

cdata.sd

#> sex condition change.sd

#> 1 F aspirin 0.8642916

#> 2 M aspirin 1.1307569

#> 3 F placebo 0.5247655

#> 4 M placebo 0.7804913

# 合并

cdata <- merge(cdata, cdata.sd)

cdata

#> sex condition N before after change change.sd

#> 1 F aspirin 5 11.06000 7.640000 -3.420000 0.8642916

#> 2 F placebo 12 10.13333 8.075000 -2.058333 0.5247655

#> 3 M aspirin 9 11.26667 5.855556 -5.411111 1.1307569

#> 4 M placebo 4 11.47500 10.500000 -0.975000 0.7804913

# 最后计算标准误

cdata$change.se <- cdata$change.sd / sqrt(cdata$N)

cdata

#> sex condition N before after change change.sd change.se

#> 1 F aspirin 5 11.06000 7.640000 -3.420000 0.8642916 0.3865230

#> 2 F placebo 12 10.13333 8.075000 -2.058333 0.5247655 0.1514867

#> 3 M aspirin 9 11.26667 5.855556 -5.411111 1.1307569 0.3769190

#> 4 M placebo 4 11.47500 10.500000 -0.975000 0.7804913 0.3902456

如果数据中有NA值并希望忽略它们,设置 na.rm=TRUE

cdata.means <- aggregate(data[c("before","after","change")],

by = data[c("sex","condition")],

FUN=mean, na.rm=TRUE)

cdata.means

#> sex condition before after change

#> 1 F aspirin 11.06000 7.640000 -3.420000

#> 2 M aspirin 11.26667 5.855556 -5.411111

#> 3 F placebo 10.13333 8.075000 -2.058333

#> 4 M placebo 11.47500 10.500000 -0.975000



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。