(七)基本统计分析

前面简要介绍了R语言的基本数据结构和基础图形,本节将简单介绍如何得到数据的描述性统计分析,以及进一步了解列联表(也即分组)。

1、描述性统计分析

本节将关注分析连续型变量的中心趋势、变化性和分布形状的方法。以mtcars数据中的mpg、hp和wt为例子对常用的统计方法进行说明。
对于数据的基础性统计分析,R中有许多方法,从R自带的summary()函数,到三方包中的方法,我们将逐步进行介绍。

> df <- mtcars[c('mpg','hp','wt')];head(df)
                   mpg  hp    wt
Mazda RX4         21.0 110 2.620
Mazda RX4 Wag     21.0 110 2.875
Datsun 710        22.8  93 2.320
Hornet 4 Drive    21.4 110 3.215
Hornet Sportabout 18.7 175 3.440
Valiant           18.1 105 3.460
> summary(df)
      mpg              hp              wt       
 Min.   :10.40   Min.   : 52.0   Min.   :1.513  
 1st Qu.:15.43   1st Qu.: 96.5   1st Qu.:2.581  
 Median :19.20   Median :123.0   Median :3.325  
 Mean   :20.09   Mean   :146.7   Mean   :3.217  
 3rd Qu.:22.80   3rd Qu.:180.0   3rd Qu.:3.610  
 Max.   :33.90   Max.   :335.0   Max.   :5.424 

如上所见,summary()函数提供了最小值、最大值、四分位数和数值型变量的均值,以及因子向量和逻辑型向量的频数统计。你可以使用apply()函数或sapply()函数计算所选择的任意描述性统计量。函数fivenum()可返回图基五数总括(Tukey’s five-number summary,即最小值、下四分位数、中位数、上四分位数和最大值)。

mystats<-function(x,na.omit=FALSE){
  if(na.omit){
    x<-x[!is.na(x)]
  }
  m<-mean(x)
  n<-length(x)
  s<-sd(x)
  skew<-sum((x-m)^3/s^3)/n
  kurt<-sum((x-m)^4/s^4)/n-3
  return(c(n=n,mean=m,stdenv=s,skew=skew,kurtosis=kurt))
}

> apply(df, 2, mystats)
               mpg          hp          wt
n        32.000000  32.0000000 32.00000000
mean     20.090625 146.6875000  3.21725000
stdenv    6.026948  68.5628685  0.97845744
skew      0.610655   0.7260237  0.42314646
kurtosis -0.372766  -0.1355511 -0.02271075

三方包Hmsic、pastecs和psych中都提供了计算描述性统计的函数。Hmisc包中的describe()函数可返回变量和观测的数量、缺失值和唯一值的数目、平均值、分位数,以及五个最大的值和五个最小的值。

> library(Hmisc)
> describe(df)
df 

 3  Variables      32  Observations
------------------------------------------------------------------------------------------------------------------------------------------
mpg 
       n  missing distinct     Info     Mean      Gmd      .05      .10      .25      .50      .75      .90      .95 
      32        0       25    0.999    20.09    6.796    12.00    14.34    15.43    19.20    22.80    30.09    31.30 

lowest : 10.4 13.3 14.3 14.7 15.0, highest: 26.0 27.3 30.4 32.4 33.9
------------------------------------------------------------------------------------------------------------------------------------------
hp 
       n  missing distinct     Info     Mean      Gmd      .05      .10      .25      .50      .75      .90      .95 
      32        0       22    0.997    146.7    77.04    63.65    66.00    96.50   123.00   180.00   243.50   253.55 

lowest :  52  62  65  66  91, highest: 215 230 245 264 335
------------------------------------------------------------------------------------------------------------------------------------------
wt 
       n  missing distinct     Info     Mean      Gmd      .05      .10      .25      .50      .75      .90      .95 
      32        0       29    0.999    3.217    1.089    1.736    1.956    2.581    3.325    3.610    4.048    5.293 

lowest : 1.513 1.615 1.835 1.935 2.140, highest: 3.845 4.070 5.250 5.345 5.424
------------------------------------------------------------------------------------------------------------------------------------------

pastecs包中有一个名为stat.desc()的函数,可用来计算种类繁多的描述性统计量。使用方法为stat.desc(x,basic=TRUE,desc=TRUE,norm=FALSE,p=0.95),其中的x是一个数据框或时间序列。若basic=TRUE(默认值),则计算其中所有值、空值、缺失值的数量,以及最小值、最大值、值域,还有总和。若desc=TRUE(同样也是默认值),则计算中位数、平均数、平均数的标准误、平均数置信度为95%的置信区间、方差、标准差以及变异系数。最后,若norm=TRUE(不是默认的),则返回正态分布统计量,包括偏度和峰度(以及它们的统计显著程度)和Shapiro–Wilk正态检验结果。这里使用了p值来计算平均数的置信区间(默认置信度为0.95)。

> options(digits=2)
> stat.desc(df)
               mpg      hp     wt
nbr.val       32.0   32.00  32.00
nbr.null       0.0    0.00   0.00
nbr.na         0.0    0.00   0.00
min           10.4   52.00   1.51
max           33.9  335.00   5.42
range         23.5  283.00   3.91
sum          642.9 4694.00 102.95
median        19.2  123.00   3.33
mean          20.1  146.69   3.22
SE.mean        1.1   12.12   0.17
CI.mean.0.95   2.2   24.72   0.35
var           36.3 4700.87   0.96
std.dev        6.0   68.56   0.98
coef.var       0.3    0.47   0.30

psych包中也有一个describe()函数,它可以计算非缺失值的数量、平均数、标准差、中位数、截尾均值、绝对中位差、最小值、最大值、值域、偏度、峰度和平均值的标准误。

> library(psych)

载入程辑包:‘psych’

The following object is masked from ‘package:Hmisc’:

    describe

The following objects are masked from ‘package:ggplot2’:

    %+%, alpha
### 这里的describe()函数被重载了,如果想使用Hmisc中的describe()函数,可使用Hmisc::describe(df)
> describe(df)
    vars  n  mean    sd median trimmed   mad  min   max range skew kurtosis    se
mpg    1 32  20.1  6.03   19.2    19.7  5.41 10.4  33.9  23.5 0.61    -0.37  1.07
hp     2 32 146.7 68.56  123.0   141.2 77.10 52.0 335.0 283.0 0.73    -0.14 12.12
wt     3 32   3.2  0.98    3.3     3.1  0.77  1.5   5.4   3.9 0.42    -0.02  0.17

2、分组计算描述性统计量

在前面我们已经使用aggregate()函数进行简单的分组计算,aggregate()的缺点是只能使用平均数、标准差这样的单返回值函数。
若想一次性返回多个统计量,可使用by()函数,格式为:by(data, Indices, FUN),其中data是一个数据框或矩阵,indices是一个因子或因子组成的列表,定义了分组,FUN则是任意函数。

### 使用aggregate()函数分组并获取单个返回值
> aggregate(df,by=list(mtcars$am),mean)
  Group.1 mpg  hp  wt
1       0  17 160 3.8
2       1  24 127 2.4

###使用by()函数分组并返回多个统计量
> dstats <- function(x)sapply(x, mystats)
> by(df, mtcars$am, dstats)
mtcars$am: 0
            mpg      hp    wt
n        19.000  19.000 19.00
mean     17.147 160.263  3.77
stdenv    3.834  53.908  0.78
skew      0.014  -0.014  0.98
kurtosis -0.803  -1.210  0.14
------------------------------------------------------------------------------------------------------- 
mtcars$am: 1
            mpg     hp    wt
n        13.000  13.00 13.00
mean     24.392 126.85  2.41
stdenv    6.167  84.06  0.62
skew      0.053   1.36  0.21
kurtosis -1.455   0.56 -1.17

###这里书中说的dstats()调用了mystats()函数,将其应用于数据框中的每一列中,在通过by()函数可得到am中每一水平的概括统计量。
###但是个人认为应该是先分类然后再应用统计函数才对。

doBy包和psych包同样提供了分祖计算统计量的函数。doBy包中的summaryBy()函数使用方法为:summaryBy(formula, data=dataframe, FUN=function),其中formula接受以下格式:var1+var2+var3+...varN ~ groupvar1+groupvar2+...+groupvarN,在~左侧的变量(varN)是需要分析的数值型变量,而右侧的变量(groupvarN)是类别型的分组变量。 function可为任何内建或用户自编的R函数。

> library('doBy')
> summaryBy(mpg+hp+wt~am,data=mtcars,FUN=mystats)
  am mpg.n mpg.mean mpg.stdenv mpg.skew mpg.kurtosis hp.n hp.mean hp.stdenv hp.skew hp.kurtosis wt.n wt.mean wt.stdenv wt.skew
1  0    19       17        3.8    0.014         -0.8   19     160        54  -0.014       -1.21   19     3.8      0.78    0.98
2  1    13       24        6.2    0.053         -1.5   13     127        84   1.360        0.56   13     2.4      0.62    0.21
  wt.kurtosis
1        0.14
2       -1.17
###########
> library(psych)
> describeBy(df)
    vars  n  mean    sd median trimmed   mad  min   max range skew kurtosis    se
mpg    1 32  20.1  6.03   19.2    19.7  5.41 10.4  33.9  23.5 0.61    -0.37  1.07
hp     2 32 146.7 68.56  123.0   141.2 77.10 52.0 335.0 283.0 0.73    -0.14 12.12
wt     3 32   3.2  0.98    3.3     3.1  0.77  1.5   5.4   3.9 0.42    -0.02  0.17

从上面可以看到doBy中的summaryBy()函数返回结果的可读性比R自带by()函数差,但其用起来较为简单。
psych包中的describeBy()函数可计算和describe相同的描述性统计量,只是按照一个或多个分组变量分层。但describeBy()函数不允许指定任意函数,所以它的普适性较低。若存在一个以上的分组变量,可使用list(groupvar1, groupvar2, ... , groupvarN)来表示它们。
最后,在前面介绍分组方法时,使用过reshape2包,借助reshape2包可以灵活的按组导出描述性统计量(如我前面所言,个人感觉这个包有点难以理解)。但是reshape2相比于reshape有一个很大的缺点,那就是他的聚合函数只能有一个返回值(虽然reshape2比reshape效率高),就好比aggregateby。他的使用步骤主要如下:
(1)融合数据框: dfm <- melt(dataframe, measure.vars=y, id.vars=g),其中的dataframe包含着数据, y是一个向量,指明了要进行概述的数值型变量(默认使用所有变量),而g是由一个或多个分组变量组成的向量;
(2)重铸数据:cast(dfm, groupvar1 + groupvar2 + ... + variable ~ . , FUN), 分组变量以+号分隔,这里的variable只取其字面含义(即仅表示重铸后数据框中的变量variable),而FUN是一个任意函数。reshape2使用的是dcast()函数,只能有一个返回值,而cast函数中却允许多个返回值。
下面使用mtcars数据看看reshape分组聚合的强大之处。

> library(reshape)

载入程辑包:‘reshape’

The following objects are masked from ‘package:reshape2’:

    colsplit, melt, recast
### rehape2和reshape包的功能和函数用法基本相同,除了上面所说的重铸的统计返回值数量
> dfm<-melt(mtcars, measure.vars=c('mpg','hp','wt'),id.vars=c('am','cyl'))
> head(dfm)
  am cyl variable value
1  1   6      mpg  21.0
2  1   6      mpg  21.0
3  1   4      mpg  22.8
4  0   6      mpg  21.4
5  0   8      mpg  18.7
6  0   6      mpg  18.1
> options(digits=2);cdf<-cast(dfm, am+cyl+variable~., mystats);head(cdf)
  am cyl variable n  mean stdenv   skew kurtosis
1  0   4      mpg 3  22.9   1.45  0.069     -2.3
2  0   4       hp 3  84.7  19.66 -0.380     -2.3
3  0   4       wt 3   2.9   0.41 -0.381     -2.3
4  0   6      mpg 4  19.1   1.63  0.482     -1.9
5  0   6       hp 4 115.2   9.18 -0.094     -2.3
6  0   6       wt 4   3.4   0.12 -0.735     -1.7

3、频数表和列联表

本部分将着眼于类别型变量的频数表和列联表。范例中的数据来源于vcd包中的Arthritis数据集,这份数据展示了一项关于风湿性关节炎新疗法的双盲临床试验结果。
R中提供了多种用于创建频数表和列连表的方法,主要常用的函数如下表:

函数 描述
table(var1, var2, var3,...,varN) 使用N个类别型变量(因子)创建一个N维列联表
xtabs(formula, data) 根据一个公式和一个矩阵或数据框创建一个N维列联表
pro.table(table, margins) 依margins定义的边际列表将表中条目表示为分数形式
margin.table(table, margins) 依margins定义的边际列表计算表中条目的和
addmargins(table,margins) 将概述边margins(默认是求和结果)放入表中
ftable(table) 创建一个紧凑的‘平铺式’列联表

接下来,我们将逐个使用以上函数来探索类别型变量。首先观察简单的频率表,然后是二维列联表,最后是多维列联表。

3.1 一维列联表

一维列联表可直接使用table()生成。

> head(Arthritis)
  ID Treatment  Sex Age Improved
1 57   Treated Male  27     Some
2 46   Treated Male  29     None
3 77   Treated Male  30     None
4 17   Treated Male  32   Marked
5 36   Treated Male  46   Marked
6 23   Treated Male  58   Marked
### 查看治疗效果
> mytable <- table(Arthritis$Improved) 
> mytable

  None   Some Marked 
    42     14     28 
### 产看治疗效果的比例
> prop.table(mytable)

  None   Some Marked 
  0.50   0.17   0.33 
> prop.table(mytable)*100

  None   Some Marked 
    50     17     33 
###求和
> margin.table(mytable)
[1] 84
###同样求和,这里将结果加入了表中
> addmargins(mytable)

  None   Some Marked    Sum 
    42     14     28     84 
> class(mytable)
[1] "table

从上面可以看到,50%的患者都得到了改善。

3.2 二维列联表

创建二维列联表有两种方式,使用table(A,B)xtabs()xtabs()的使用方式较为复杂,格式为:xtabs(~A+B, data=mydata),其中的mydata是一个矩阵或数据框。总的来说,要进行交叉分类的变量应出现在公式的右侧(即符号的右方),以+作为分隔符。若某个变量写在公式的左侧,则其为一个频数向量(在数据已经被表格化时很有用),对其进行求和运算。简言之,formula公式右边的应该都是类型变量,左边可选择加入数值型变量。
另外值得注意的一点是,table()函数是默认忽略NA的,若需要将NA作为一类,使用useNA='ifany'

### 使用table()创建二维列联表
> table(Arthritis$Treatment,Arthritis$Improved)
         
          None Some Marked
  Placebo   29    7      7
  Treated   13    7     21
### 使用xtabs()创建二维列联表
> mytable <- xtabs(~Treatment+Improved, Arthritis); mytable
         Improved
Treatment None Some Marked
  Placebo   29    7      7
  Treated   13    7     21
### 生成边际频数,其中后面的1,2指代xtabs()的formula中变量的下标,
### 如 ~Treatment+Improved 中1指的是第一个变量Treatment,2指的是第二个变量Improved
> margin.table(mytable, 1); margin.table(mytable,2)
Treatment
Placebo Treated 
     43      41 
Improved
  None   Some Marked 
    42     14     28 
### 生成边际比例
> prop.table(mytable,1)*100;prop.table(mytable,2)*100
         Improved
Treatment None Some Marked
  Placebo   67   16     16
  Treated   32   17     51
         Improved
Treatment None Some Marked
  Placebo   69   50     25
  Treated   31   50     75
### 查看每个单元格所占比例
> prop.table(mytable)
         Improved
Treatment  None  Some Marked
  Placebo 0.345 0.083  0.083
  Treated 0.155 0.083  0.250
### 添加边际和
> addmargins(mytable)
         Improved
Treatment None Some Marked Sum
  Placebo   29    7      7  43
  Treated   13    7     21  41
  Sum       42   14     28  84

######## 接下来我们再看看,在formula左边加入一个频数变量(这里将Age作为一个频数变量)的结果
> xtabs(Age~Treatment+Improved, Arthritis)
         Improved
Treatment None Some Marked
  Placebo 1439  402    403
  Treated  648  397   1193
### 可以看到关联列表的行列变量没变,但是其中的数值变了,这些数值代表什么意思呢?其实是每一个分类的和
### 使用aggregate函数可以简单实现相同的结果
> aggregate(Arthritis$Age,by=list(Treatment=Arthritis$Treatment,Improvement=Arthritis$Improved),sum)
  Treatment Improvement    x
1   Placebo        None 1439
2   Treated        None  648
3   Placebo        Some  402
4   Treated        Some  397
5   Placebo      Marked  403
6   Treated      Marked 1193

除了R中自带的table()类函数外,还可以使用三方包gmodels中的CrossTable()函数创建二维列联表。

> library(gmodels)
> CrossTable(Arthritis$Treatment,Arthritis$Improved)

 
   Cell Contents
|-------------------------|
|                       N |
| Chi-square contribution |
|           N / Row Total |
|           N / Col Total |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  84 

 
                    | Arthritis$Improved 
Arthritis$Treatment |      None |      Some |    Marked | Row Total | 
--------------------|-----------|-----------|-----------|-----------|
            Placebo |        29 |         7 |         7 |        43 | 
                    |     2.616 |     0.004 |     3.752 |           | 
                    |     0.674 |     0.163 |     0.163 |     0.512 | 
                    |     0.690 |     0.500 |     0.250 |           | 
                    |     0.345 |     0.083 |     0.083 |           | 
--------------------|-----------|-----------|-----------|-----------|
            Treated |        13 |         7 |        21 |        41 | 
                    |     2.744 |     0.004 |     3.935 |           | 
                    |     0.317 |     0.171 |     0.512 |     0.488 | 
                    |     0.310 |     0.500 |     0.750 |           | 
                    |     0.155 |     0.083 |     0.250 |           | 
--------------------|-----------|-----------|-----------|-----------|
       Column Total |        42 |        14 |        28 |        84 | 
                    |     0.500 |     0.167 |     0.333 |           | 
--------------------|-----------|-----------|-----------|-----------|

CrossTable()结果较为直观,而且已经添加了边际和和边际频率。CrossTable()函数还有很多选项,可以做许多事情:计算(行、列、单元格)的百分比;指定小数位数;进行卡方、 Fisher和McNemar独立性检验;计算期望和(皮尔逊、标准化、调整的标准化)残差;将缺失值作为一种有效值;进行行和列标题的标注;生成SAS或SPSS风格的输出。

3.3 多维列联表

table()和xtabs()都可以基于三个或更多的类别型变量生成多维列联。margin.table()、prop.table()和addmargins()函数可以自然地推广到高于二维的情况。另外, ftable()函数可以以一种紧凑而吸引人的方式输出多维列联表。

### 使用table()创建多维列联表
> with(Arthritis,table(Treatment, Sex, Improved))
, , Improved = None

         Sex
Treatment Female Male
  Placebo     19   10
  Treated      6    7

, , Improved = Some

         Sex
Treatment Female Male
  Placebo      7    0
  Treated      5    2

, , Improved = Marked

         Sex
Treatment Female Male
  Placebo      6    1
  Treated     16    5
### 使用xtabs创建多维列联表
> mytable <- xtabs(~Treatment+Sex+Improved, data=Arthritis)
> mytable
, , Improved = None

         Sex
Treatment Female Male
  Placebo     19   10
  Treated      6    7

, , Improved = Some

         Sex
Treatment Female Male
  Placebo      7    0
  Treated      5    2

, , Improved = Marked

         Sex
Treatment Female Male
  Placebo      6    1
  Treated     16    5
### 使用ftable()对三维列表输出格式进行美化
> ftable(mytable)
                 Improved None Some Marked
Treatment Sex                             
Placebo   Female            19    7      6
          Male              10    0      1
Treated   Female             6    5     16
          Male               7    2      5
> margin.table(mytable,1)
Treatment
Placebo Treated 
     43      41

4、小结

本节我们介绍了连续型数值变量和类别型变量的多种基本统计分析方法,在此对其进行一个小结,推荐一下个人认为最好用的方法。
(1)对于连续型数值变量的基本统计分析,可利用R内置的summary()函数查看数据的描述性统计量(如均值,极值,方差)等,若有特定的要求,可使用apply()sapply()函数通过自定义函数返回想要的结果。此外三方包Hmisc、pastecs、psych中也都提供了不错的统计函数。就输出结果的直观性和功能来说,查看基本统计分析推荐的方法为内置summary()函数和pastecs包中的stat.desc()函数。
(2)对于分组R同样提供了多种方法,如果只想对分组结果查看单个统计分析值(即作用函数只有单个返回值),aggregate()无疑是最佳选择,简单快速。若想对分组结果进行处理返回多个统计值,R同样有多种方法,这里从输出直观性以及使用简单来说,首推的reshape包(reshape2包无法返回多个统计分析值,因此放弃),其次为doBy包中的summaryBy()函数和内置的by()函数。
(3)对于类别型变量的分析,一般使用table()xtabs()即可满足要求,ftable()能够是多维关联列表的输出更为美观。若想进行更高级的分析,则可能需要用到三方包gmodels的CrossTable()函数。

参考:
R语言实战.

你可能感兴趣的:((七)基本统计分析)