Chapter 5 1. summarytools 概述

summarytools提供了一套连贯的函数集,以数据探索和简单报告为中心。其核心包括以下四个函数:

函数名 描述
freq() 频率表,包括计数、比例、累积统计以及缺失数据报告
ctable() 两个离散/分类变量之间的交叉表(联合频率),包括边际总数以及行、列或总体比例
descr() 数值数据的描述性(单变量)统计,包括常见的集中趋势和离散度指标
dfSummary() 数据框摘要,为所有变量提供类型特定信息:单变量统计和/或频率分布、条形图或直方图,以及缺失数据计数和比例。非常有用,可以快速检测异常并一目了然地识别趋势

5.1 2. 频率表:freq()

freq()函数生成带有计数、比例以及缺失数据信息的频率表。需要注意的是:创建此包的最初想法源自于base R中缺少这样一个函数。

library(summarytools)
## Warning in system2("/usr/bin/otool", c("-L", shQuote(DSO)), stdout = TRUE):
## running command ''/usr/bin/otool' -L
## '/Library/Frameworks/R.framework/Resources/library/tcltk/libs//tcltk.so'' had
## status 1
## Warning in fun(libname, pkgname): couldn't connect to display ":0"
## system might not have X11 capabilities; in case of errors when using dfSummary(), set st_options(use.x11 = FALSE)
freq(iris$Species)
## Frequencies  
## iris$Species  
## Type: Factor  
## 
##                    Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ---------------- ------ --------- -------------- --------- --------------
##           setosa     50     33.33          33.33     33.33          33.33
##       versicolor     50     33.33          66.67     33.33          66.67
##        virginica     50     33.33         100.00     33.33         100.00
##             <NA>      0                               0.00         100.00
##            Total    150    100.00         100.00    100.00         100.00

summarytools的主要目的之一是帮助清理和准备数据以供进一步分析。但在某些情况下,我们不需要(或已经有了)有关缺失数据的信息。使用report.nas = FALSE可以使输出表格减少一行两列:

freq(iris$Species, report.nas = FALSE, headings = FALSE)
## 
##                    Freq        %   % Cum.
## ---------------- ------ -------- --------
##           setosa     50    33.33    33.33
##       versicolor     50    33.33    66.67
##        virginica     50    33.33   100.00
##            Total    150   100.00   100.00

参数headings = FALSE抑制了标题部分。通过“关闭”所有可选元素,可以生成一个简化的表格:

freq(iris$Species, 
     report.nas = FALSE, 
     totals     = FALSE, 
     cumul      = FALSE, 
     headings   = FALSE)
## 
##                    Freq       %
## ---------------- ------ -------
##           setosa     50   33.33
##       versicolor     50   33.33
##        virginica     50   33.33

5.1.1 同时生成多个频率表

要为数据框中的所有变量生成频率表,我们可以(并且在最早的版本中需要)使用lapply()。但是,这不是必需的,因为freq()接受数据框作为主要参数:

freq(tobacco)
## Variable(s) ignored: age, BMI, cigs.per.day
## Frequencies  
## tobacco$gender  
## Type: Factor  
## 
##               Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ----------- ------ --------- -------------- --------- --------------
##           F    489     50.00          50.00     48.90          48.90
##           M    489     50.00         100.00     48.90          97.80
##        <NA>     22                               2.20         100.00
##       Total   1000    100.00         100.00    100.00         100.00
## 
## tobacco$age.gr  
## Type: Factor  
## 
##               Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ----------- ------ --------- -------------- --------- --------------
##       18-34    258     26.46          26.46     25.80          25.80
##       35-50    241     24.72          51.18     24.10          49.90
##       51-70    317     32.51          83.69     31.70          81.60
##        71 +    159     16.31         100.00     15.90          97.50
##        <NA>     25                               2.50         100.00
##       Total   1000    100.00         100.00    100.00         100.00
## 
## tobacco$smoker  
## Type: Factor  
## 
##               Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ----------- ------ --------- -------------- --------- --------------
##         Yes    298     29.80          29.80     29.80          29.80
##          No    702     70.20         100.00     70.20         100.00
##        <NA>      0                               0.00         100.00
##       Total   1000    100.00         100.00    100.00         100.00
## 
## tobacco$diseased  
## Type: Factor  
## 
##               Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ----------- ------ --------- -------------- --------- --------------
##         Yes    224     22.40          22.40     22.40          22.40
##          No    776     77.60         100.00     77.60         100.00
##        <NA>      0                               0.00         100.00
##       Total   1000    100.00         100.00    100.00         100.00
## 
## tobacco$disease  
## Type: Character  
## 
##                         Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## --------------------- ------ --------- -------------- --------- --------------
##                Cancer     34     15.32          15.32      3.40           3.40
##           Cholesterol     21      9.46          24.77      2.10           5.50
##              Diabetes     14      6.31          31.08      1.40           6.90
##             Digestive     12      5.41          36.49      1.20           8.10
##               Hearing     14      6.31          42.79      1.40           9.50
##                 Heart     20      9.01          51.80      2.00          11.50
##          Hypertension     36     16.22          68.02      3.60          15.10
##           Hypotension     11      4.95          72.97      1.10          16.20
##       Musculoskeletal     19      8.56          81.53      1.90          18.10
##          Neurological     10      4.50          86.04      1.00          19.10
##                 Other      2      0.90          86.94      0.20          19.30
##             Pulmonary     20      9.01          95.95      2.00          21.30
##                Vision      9      4.05         100.00      0.90          22.20
##                  <NA>    778                              77.80         100.00
##                 Total   1000    100.00         100.00    100.00         100.00
## 
## tobacco$samp.wgts  
## Type: Numeric  
## 
##                           Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ----------------------- ------ --------- -------------- --------- --------------
##       0.861423220973783    267     26.70          26.70     26.70          26.70
##        1.04417670682731    249     24.90          51.60     24.90          51.60
##        1.04938271604938    324     32.40          84.00     32.40          84.00
##                  1.0625    160     16.00         100.00     16.00         100.00
##                    <NA>      0                               0.00         100.00
##                   Total   1000    100.00         100.00    100.00         100.00

为避免结果混乱,忽略具有超过25个不同值的数值列。可以通过使用st_options()来更改这个阈值;例如,将其更改为10,我们将使用st_options(freq.ignore.threshold = 10)。

数据框tobacco包含模拟数据,并包含在包中。另一个包含的模拟数据框是exams。两者都有法语版本(tabagisme、examens)。

5.1.2 子集(过滤)频率表

参数rows允许对频率表进行子集(过滤);我们可以以不同的方式使用此参数:

  1. 通过它们的出现顺序对行进行过滤,使用数值向量;rows = 1:10将仅显示前10个值的频率。为了考虑未显示值的频率,“(Other)”行会自动添加
  2. 通过名称对行进行过滤,可以使用
  • 指定要保留的所有行名的字符向量
  • 单个字符字符串,将用作正则表达式(有关此主题的更多信息,请参阅?regex)

显示最常见的值

通过组合order和rows参数,我们可以轻松地将结果过滤为显示因子中最常见的5个值:

freq(tobacco$disease, 
     order    = "freq",
     rows     = 1:5,
     headings = FALSE)
## 
##                      Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ------------------ ------ --------- -------------- --------- --------------
##       Hypertension     36     16.22          16.22      3.60           3.60
##             Cancer     34     15.32          31.53      3.40           7.00
##        Cholesterol     21      9.46          40.99      2.10           9.10
##              Heart     20      9.01          50.00      2.00          11.10
##          Pulmonary     20      9.01          59.01      2.00          13.10
##            (Other)     91     40.99         100.00      9.10          22.20
##               <NA>    778                              77.80         100.00
##              Total   1000    100.00         100.00    100.00         100.00

5.1.3 可折叠节

在生成html结果时,使用print()、view()或stview()与collapse = TRUE参数可获得可折叠节;单击标题部分中的变量名将折叠/显示频率表(结果未显示)。

view(freq(tobacco), collapse = TRUE)
## Variable(s) ignored: age, BMI, cigs.per.day
## Output file written: /var/folders/dg/jgfdmlcn4dj4j5f5yls_lhph0000gn/T//Rtmp2pmXmD/file93804f24b0d2.html
## Switching method to 'browser'
## Output file appended: /private/var/folders/dg/jgfdmlcn4dj4j5f5yls_lhph0000gn/T/Rtmp2pmXmD/file93804f24b0d2.html

5.2 3. 交叉表:ctable()

ctable()生成两个分类变量的交叉表(联合频率)。

使用模拟数据框tobacco,我们将对两个分类变量smoker和diseased进行交叉表分析。

ctable(x = tobacco$smoker, 
       y = tobacco$diseased, 
       prop = "r")   # 显示行比例
## Cross-Tabulation, Row Proportions  
## smoker * diseased  
## Data Frame: tobacco  
## 
## -------- ---------- ------------- ------------- ---------------
##            diseased           Yes            No           Total
##   smoker                                                       
##      Yes              125 (41.9%)   173 (58.1%)    298 (100.0%)
##       No               99 (14.1%)   603 (85.9%)    702 (100.0%)
##    Total              224 (22.4%)   776 (77.6%)   1000 (100.0%)
## -------- ---------- ------------- ------------- ---------------

5.2.1 行、列或总体比例

默认情况下显示行比例。要显示列或总体比例,请使用prop = “c”或prop = “t”。要完全省略比例,请使用prop = “n”。

ctable(x = tobacco$smoker, 
       y = tobacco$diseased, 
       prop = "c")   # 显示行比例
## Cross-Tabulation, Column Proportions  
## smoker * diseased  
## Data Frame: tobacco  
## 
## -------- ---------- -------------- -------------- ---------------
##            diseased            Yes             No           Total
##   smoker                                                         
##      Yes              125 ( 55.8%)   173 ( 22.3%)    298 ( 29.8%)
##       No               99 ( 44.2%)   603 ( 77.7%)    702 ( 70.2%)
##    Total              224 (100.0%)   776 (100.0%)   1000 (100.0%)
## -------- ---------- -------------- -------------- ---------------

5.2.2 最小交叉表

通过“关闭”所有可选功能,我们得到一个简单的“2 x 2”表格:

with(tobacco, 
     print(ctable(x = smoker, 
                  y = diseased, 
                  prop     = 'n',
                  totals   = FALSE, 
                  headings = FALSE),
           method = "render")
)
diseased
smoker Yes No
Yes 125 173
No 99 603

Generated by summarytools 1.0.1 (R version 4.2.1)
2024-02-14

5.2.3 卡方检验(𝛘²)、几率比和风险比

要显示卡方统计量,请设置chisq = TRUE。对于2 x 2表格,使用OR和RR显示几率比和风险比(也称为相对风险),分别设置为TRUE,此时会显示95%置信区间;要使用不同的置信水平,请使用例如OR = .90。

使用管道通常更容易生成ctable()结果。

library(magrittr)
tobacco %$%  # 类似于with(tobacco, ...)
  ctable(x = smoker, y = diseased,
         chisq = TRUE,
         OR    = TRUE,
         RR    = TRUE,
         headings = FALSE) %>%
  print(method = "render")
diseased
smoker Yes No Total
Yes 125 ( 41.9% ) 173 ( 58.1% ) 298 ( 100.0% )
No 99 ( 14.1% ) 603 ( 85.9% ) 702 ( 100.0% )
Total 224 ( 22.4% ) 776 ( 77.6% ) 1000 ( 100.0% )
 Χ2 = 91.7088   df = 1   p = .0000
O.R. (95% C.I.) = 4.40  (3.22 - 6.02)
R.R. (95% C.I.) = 2.97  (2.37 - 3.73)

Generated by summarytools 1.0.1 (R version 4.2.1)
2024-02-14

5.3 4. 描述性统计: descr()

descr() 函数生成描述性/单变量统计信息,即常见的集中趋势统计和离散度量。它接受单个向量以及数据框作为输入;在后一种情况下,所有非数值列都会被忽略,并显示相应的消息。

descr(iris)
## Non-numerical variable(s) ignored: Species
## Descriptive Statistics  
## iris  
## N: 150  
## 
##                     Petal.Length   Petal.Width   Sepal.Length   Sepal.Width
## ----------------- -------------- ------------- -------------- -------------
##              Mean           3.76          1.20           5.84          3.06
##           Std.Dev           1.77          0.76           0.83          0.44
##               Min           1.00          0.10           4.30          2.00
##                Q1           1.60          0.30           5.10          2.80
##            Median           4.35          1.30           5.80          3.00
##                Q3           5.10          1.80           6.40          3.30
##               Max           6.90          2.50           7.90          4.40
##               MAD           1.85          1.04           1.04          0.44
##               IQR           3.50          1.50           1.30          0.50
##                CV           0.47          0.64           0.14          0.14
##          Skewness          -0.27         -0.10           0.31          0.31
##       SE.Skewness           0.20          0.20           0.20          0.20
##          Kurtosis          -1.42         -1.36          -0.61          0.14
##           N.Valid         150.00        150.00         150.00        150.00
##         Pct.Valid         100.00        100.00         100.00        100.00

要关闭变量类型的消息,请使用 silent = TRUE。可以全局设置该选项,在本文档的其余部分中将不会显示该消息。

st_options(descr.silent = TRUE)

5.3.1 转置和选择统计信息

结果可以通过使用 transpose = TRUE 进行转置,也可以使用 stats 参数选择统计信息:

descr(iris,
      stats     = c("mean", "sd"),
      transpose = TRUE,
      headings  = FALSE)
## 
##                      Mean   Std.Dev
## ------------------ ------ ---------
##       Petal.Length   3.76      1.77
##        Petal.Width   1.20      0.76
##       Sepal.Length   5.84      0.83
##        Sepal.Width   3.06      0.44

5.4 5. 数据框摘要: dfSummary()

dfSummary() 创建一个摘要表,包含数据框中所有变量的统计信息、频率和图表。显示的信息是类型特定的(字符、因子、数值、日期),并根据不同值的数量而变化。

view(dfSummary(iris))
## Switching method to 'browser'
## Output file written: /var/folders/dg/jgfdmlcn4dj4j5f5yls_lhph0000gn/T//Rtmp2pmXmD/file938024fc33d4.html

请注意使用 view() 而不是 View()。如果使用后者,则结果将显示在数据查看器中。

5.5 可选统计信息

自从发布以来,这一功能已经多次被请求。在 1.0.0 版中引入,它可以控制要在统计/值列中显示的统计信息。

 st_options(
  dfSummary.custom.1 = 
    expression(
      paste(
        "Q1 - Q3 :",
        round(
          quantile(column_data, probs = .25, type = 2, 
                   names = FALSE, na.rm = TRUE), digits = 1
        ), " - ",
        round(
          quantile(column_data, probs = .75, type = 2, 
                   names = FALSE, na.rm = TRUE), digits = 1
        )
      )
    )
)

print(
  dfSummary(iris, 
            varnumbers   = FALSE,
            na.col       = FALSE,
            style        = "multiline",
            plain.ascii  = FALSE,
            headings     = FALSE,
            graph.magnif = .8),
  method = "render"
)
Variable Stats / Values Freqs (% of Valid) Graph Valid
Sepal.Length [numeric]
Mean (sd) : 5.8 (0.8)
min ≤ med ≤ max:
4.3 ≤ 5.8 ≤ 7.9
Q1 - Q3 : 5.1 - 6.4
35 distinct values 150 (100.0%)
Sepal.Width [numeric]
Mean (sd) : 3.1 (0.4)
min ≤ med ≤ max:
2 ≤ 3 ≤ 4.4
Q1 - Q3 : 2.8 - 3.3
23 distinct values 150 (100.0%)
Petal.Length [numeric]
Mean (sd) : 3.8 (1.8)
min ≤ med ≤ max:
1 ≤ 4.3 ≤ 6.9
Q1 - Q3 : 1.6 - 5.1
43 distinct values 150 (100.0%)
Petal.Width [numeric]
Mean (sd) : 1.2 (0.8)
min ≤ med ≤ max:
0.1 ≤ 1.3 ≤ 2.5
Q1 - Q3 : 0.3 - 1.8
22 distinct values 150 (100.0%)
Species [factor]
1. setosa
2. versicolor
3. virginica
50(33.3%)
50(33.3%)
50(33.3%)
150 (100.0%)

Generated by summarytools 1.0.1 (R version 4.2.1)
2024-02-14

5.6 6.Grouped Statistics

stby() 函数是 summarytools 包中的一个函数,用于生成分组统计信息。它的使用方式与基本的 by() 函数相同,但为了产生最佳结果,stby() 做了一些优化。下面是一些示例以及相应的输出。

# 分组统计:按照鸢尾花的不同种类计算描述统计信息
(iris_stats_by_species <- stby(data      = iris, 
                               INDICES   = iris$Species, 
                               FUN       = descr, 
                               stats     = "common", 
                               transpose = TRUE))
## Descriptive Statistics  
## iris  
## Group: Species = setosa  
## N: 50  
## 
##                      Mean   Std.Dev    Min   Median    Max   N.Valid   Pct.Valid
## ------------------ ------ --------- ------ -------- ------ --------- -----------
##       Petal.Length   1.46      0.17   1.00     1.50   1.90     50.00      100.00
##        Petal.Width   0.25      0.11   0.10     0.20   0.60     50.00      100.00
##       Sepal.Length   5.01      0.35   4.30     5.00   5.80     50.00      100.00
##        Sepal.Width   3.43      0.38   2.30     3.40   4.40     50.00      100.00
## 
## Group: Species = versicolor  
## N: 50  
## 
##                      Mean   Std.Dev    Min   Median    Max   N.Valid   Pct.Valid
## ------------------ ------ --------- ------ -------- ------ --------- -----------
##       Petal.Length   4.26      0.47   3.00     4.35   5.10     50.00      100.00
##        Petal.Width   1.33      0.20   1.00     1.30   1.80     50.00      100.00
##       Sepal.Length   5.94      0.52   4.90     5.90   7.00     50.00      100.00
##        Sepal.Width   2.77      0.31   2.00     2.80   3.40     50.00      100.00
## 
## Group: Species = virginica  
## N: 50  
## 
##                      Mean   Std.Dev    Min   Median    Max   N.Valid   Pct.Valid
## ------------------ ------ --------- ------ -------- ------ --------- -----------
##       Petal.Length   5.55      0.55   4.50     5.55   6.90     50.00      100.00
##        Petal.Width   2.03      0.27   1.40     2.00   2.50     50.00      100.00
##       Sepal.Length   6.59      0.64   4.90     6.50   7.90     50.00      100.00
##        Sepal.Width   2.97      0.32   2.20     3.00   3.80     50.00      100.00

此外,还有一些其他用法,包括 stby() 与 ctable() 的结合使用,以及特殊情况下 descr() 与 stby() 的结合使用,这些情况在示例中有所提及。

with(tobacco, 
     stby(data    = BMI, 
          INDICES = age.gr, 
          FUN     = descr,
          stats   = c("mean", "sd", "min", "med", "max"))
)
## Descriptive Statistics  
## BMI by age.gr  
## Data Frame: tobacco  
## N: 258  
## 
##                 18-34   35-50   51-70    71 +
## ------------- ------- ------- ------- -------
##          Mean   23.84   25.11   26.91   27.45
##       Std.Dev    4.23    4.34    4.26    4.37
##           Min    8.83   10.35    9.01   16.36
##        Median   24.04   25.11   26.77   27.52
##           Max   34.84   39.44   39.21   38.37
stby(data    = list(x = tobacco$smoker, y = tobacco$diseased), 
     INDICES = tobacco$gender, 
     FUN     = ctable)
## Cross-Tabulation, Row Proportions  
## smoker * diseased  
## Data Frame: tobacco  
## Group: gender = F  
## 
## -------- ---------- ------------- ------------- --------------
##            diseased           Yes            No          Total
##   smoker                                                      
##      Yes               62 (42.2%)    85 (57.8%)   147 (100.0%)
##       No               49 (14.3%)   293 (85.7%)   342 (100.0%)
##    Total              111 (22.7%)   378 (77.3%)   489 (100.0%)
## -------- ---------- ------------- ------------- --------------
## 
## Group: gender = M  
## 
## -------- ---------- ------------- ------------- --------------
##            diseased           Yes            No          Total
##   smoker                                                      
##      Yes               63 (44.1%)    80 (55.9%)   143 (100.0%)
##       No               47 (13.6%)   299 (86.4%)   346 (100.0%)
##    Total              110 (22.5%)   379 (77.5%)   489 (100.0%)
## -------- ---------- ------------- ------------- --------------
# or equivalently
with(tobacco, 
     stby(data    = list(x = smoker, y = diseased), 
          INDICES = gender, 
          FUN     = ctable))
## Cross-Tabulation, Row Proportions  
## smoker * diseased  
## Data Frame: tobacco  
## Group: gender = F  
## 
## -------- ---------- ------------- ------------- --------------
##            diseased           Yes            No          Total
##   smoker                                                      
##      Yes               62 (42.2%)    85 (57.8%)   147 (100.0%)
##       No               49 (14.3%)   293 (85.7%)   342 (100.0%)
##    Total              111 (22.7%)   378 (77.3%)   489 (100.0%)
## -------- ---------- ------------- ------------- --------------
## 
## Group: gender = M  
## 
## -------- ---------- ------------- ------------- --------------
##            diseased           Yes            No          Total
##   smoker                                                      
##      Yes               63 (44.1%)    80 (55.9%)   143 (100.0%)
##       No               47 (13.6%)   299 (86.4%)   346 (100.0%)
##    Total              110 (22.5%)   379 (77.5%)   489 (100.0%)
## -------- ---------- ------------- ------------- --------------

5.7 7. 分组统计:group_by()

要使用 freq()、descr() 或 dfSummary() 创建分组统计信息,可以使用 dplyr 的 group_by() 作为 stby() 的替代方法。除了语法上的差异之外,一个关键区别是 group_by() 将分组变量中的 NA 值视为有效类别,尽管会发出警告建议使用 forcats::fct_explicit_na 将 NA 显式地表示为因子。遵循这个建议,我们可以这样做:

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
tobacco$gender %<>% forcats::fct_explicit_na()
## Warning: `fct_explicit_na()` was deprecated in forcats 1.0.0.
## ℹ Please use `fct_na_value_to_level()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
tobacco %>% 
  group_by(gender) %>% 
  descr(stats = "fivenum")
## Descriptive Statistics  
## tobacco  
## Group: gender = F  
## N: 489  
## 
##                  age     BMI   cigs.per.day   samp.wgts
## ------------ ------- ------- -------------- -----------
##          Min   18.00    9.01           0.00        0.86
##           Q1   34.00   22.98           0.00        0.86
##       Median   50.00   25.87           0.00        1.04
##           Q3   66.00   29.48          10.50        1.05
##          Max   80.00   39.44          40.00        1.06
## 
## Group: gender = M  
## N: 489  
## 
##                  age     BMI   cigs.per.day   samp.wgts
## ------------ ------- ------- -------------- -----------
##          Min   18.00    8.83           0.00        0.86
##           Q1   34.00   22.52           0.00        0.86
##       Median   49.50   25.14           0.00        1.04
##           Q3   66.00   27.96          11.00        1.05
##          Max   80.00   36.76          40.00        1.06
## 
## Group: gender = (Missing)  
## N: 22  
## 
##                  age     BMI   cigs.per.day   samp.wgts
## ------------ ------- ------- -------------- -----------
##          Min   19.00   20.24           0.00        0.86
##           Q1   36.00   24.97           0.00        1.04
##       Median   55.50   27.16           0.00        1.05
##           Q3   64.00   30.23          10.00        1.05
##          Max   80.00   32.43          28.00        1.06