整洁数据
在浩如烟海的数据类型中,有一种数据类型特别为统计学家所关注。这一类数据有如下特点:
- 每行是一个个案(case)、个体(individual)、观测点(observation)、分析单位(unit of analysis)
 
- 每列是一个变量(variable)、特征(feature)
 
- 每格是一个取值(value),即某个个案的某条特征
 
这一类数据,有一种说法是整洁数据(tidy data),和其他五花八门的杂乱数据(messy data)相对。
整洁数据的结构非常清晰,通过行和列,可以锁定每个格子数值的含义。
下面是一些整洁数据的示例:
一、starwars 星球大战角色数据(87行,14列)
| Luke Skywalker | 
172 | 
77 | 
blond | 
fair | 
blue | 
19.0 | 
male | 
| C-3PO | 
167 | 
75 | 
NA | 
gold | 
yellow | 
112.0 | 
none | 
| R2-D2 | 
96 | 
32 | 
NA | 
white, blue | 
red | 
33.0 | 
none | 
| Darth Vader | 
202 | 
136 | 
none | 
white | 
yellow | 
41.9 | 
male | 
| Leia Organa | 
150 | 
49 | 
brown | 
light | 
brown | 
19.0 | 
female | 
| Owen Lars | 
178 | 
120 | 
brown, grey | 
light | 
blue | 
52.0 | 
male | 
 
二、billboard 歌曲榜单数据(79行,317列)
| 2 Pac | 
Baby Don’t Cry (Keep… | 
2000-02-26 | 
87 | 
82 | 
72 | 
77 | 
87 | 
| 2Ge+her | 
The Hardest Part Of … | 
2000-09-02 | 
91 | 
87 | 
92 | 
NA | 
NA | 
| 3 Doors Down | 
Kryptonite | 
2000-04-08 | 
81 | 
70 | 
68 | 
67 | 
66 | 
| 3 Doors Down | 
Loser | 
2000-10-21 | 
76 | 
76 | 
72 | 
69 | 
67 | 
| 504 Boyz | 
Wobble Wobble | 
2000-04-15 | 
57 | 
34 | 
25 | 
17 | 
17 | 
| 98^0 | 
Give Me Just One Nig… | 
2000-08-19 | 
51 | 
39 | 
34 | 
26 | 
26 | 
 
三、diamonds 钻石数据(53940行,10列)
| 0.23 | 
Ideal | 
E | 
SI2 | 
61.5 | 
55 | 
326 | 
3.95 | 
3.98 | 
2.43 | 
| 0.21 | 
Premium | 
E | 
SI1 | 
59.8 | 
61 | 
326 | 
3.89 | 
3.84 | 
2.31 | 
| 0.23 | 
Good | 
E | 
VS1 | 
56.9 | 
65 | 
327 | 
4.05 | 
4.07 | 
2.31 | 
| 0.29 | 
Premium | 
I | 
VS2 | 
62.4 | 
58 | 
334 | 
4.20 | 
4.23 | 
2.63 | 
| 0.31 | 
Good | 
J | 
SI2 | 
63.3 | 
58 | 
335 | 
4.34 | 
4.35 | 
2.75 | 
| 0.24 | 
Very Good | 
J | 
VVS2 | 
62.8 | 
57 | 
336 | 
3.94 | 
3.96 | 
2.48 | 
 
 
 tidyverse
本文是对 tidyverse 的入门介绍。
tidyverse (直译为``整洁宇宙’’)整合了一系列主要处理、分析整洁数据的R包(R packages)。每个包里面都有大量的函数。其特点是函数的命名、语法、用法非常整洁统一。
# 加载 tidyverse 包
library(tidyverse)
 
Warning: package 'ggplot2' was built under R version 4.3.3
 
Warning: package 'stringr' was built under R version 4.3.2
 
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.2     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ tidyr::extract()   masks magrittr::extract()
✖ dplyr::filter()    masks stats::filter()
✖ dplyr::lag()       masks stats::lag()
✖ purrr::set_names() masks magrittr::set_names()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
 
 
在载入 tidyverse 时,可能会出现类似上面的一些警告语,它们不会影响 tidyverse 的正常使用,请无须担心。
 
 
tidyverse 为整洁数据设计了一种数据格式,叫作 tibble。这个词是 tidy 和 table 的结合,顾名思义,特指整洁数据。它相当于Excel里的表格(整洁的才行)、Stata 里的数据、Python 里的 Pandas 数据框等。
在数据科学中,整洁数据是最主流的数据形式。尽管我们日常生活中,可以看到形形色色的数据呈现形式(比如12306列车时间表、网购的商品列表等),但是它们的底层数据都是很整洁的。
 打印 tibble
在接下来的几章,我将以 diamonds 钻石数据为示例数据。
# A tibble: 53,940 × 10
   carat cut       color clarity depth table price     x     y     z
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1  0.23 Ideal     E     SI2      61.5    55   326  3.95  3.98  2.43
 2  0.21 Premium   E     SI1      59.8    61   326  3.89  3.84  2.31
 3  0.23 Good      E     VS1      56.9    65   327  4.05  4.07  2.31
 4  0.29 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63
 5  0.31 Good      J     SI2      63.3    58   335  4.34  4.35  2.75
 6  0.24 Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48
 7  0.24 Very Good I     VVS1     62.3    57   336  3.95  3.98  2.47
 8  0.26 Very Good H     SI1      61.9    55   337  4.07  4.11  2.53
 9  0.22 Fair      E     VS2      65.1    61   337  3.87  3.78  2.49
10  0.23 Very Good H     VS1      59.4    61   338  4     4.05  2.39
# ℹ 53,930 more rows
 
 
在R的界面中,tibble 数据的输出格式会像上面这样。从上到下,
# A tibble: 10 × 10 表示当前 tibble 共有10行、10列 
carat cut ... 这一行是变量名 
<dbl> <ord> ... 这一行是变量类型,比如
- 数值型(
<dbl>) 
- 整数型(
<int>) 
- 有序类别型(
<ord>) 
 
1  1.5  Very Good 从这一行开始,都是钻石的具体数据了
 
如果你的 tibble 比较大,有很多行、很多列,tibble 在打印时会自动帮你隐藏多余的行和列,比方说
# A tibble: 87 × 14
   name     height  mass hair_color skin_color eye_color birth_year sex   gender
   <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
 1 Luke Sk…    172    77 blond      fair       blue            19   male  mascu…
 2 C-3PO       167    75 <NA>       gold       yellow         112   none  mascu…
 3 R2-D2        96    32 <NA>       white, bl… red             33   none  mascu…
 4 Darth V…    202   136 none       white      yellow          41.9 male  mascu…
 5 Leia Or…    150    49 brown      light      brown           19   fema… femin…
 6 Owen La…    178   120 brown, gr… light      blue            52   male  mascu…
 7 Beru Wh…    165    75 brown      light      blue            47   fema… femin…
 8 R5-D4        97    32 <NA>       white, red red             NA   none  mascu…
 9 Biggs D…    183    84 black      light      brown           24   male  mascu…
10 Obi-Wan…    182    77 auburn, w… fair       blue-gray       57   male  mascu…
# ℹ 77 more rows
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
#   vehicles <list>, starships <list>
 
 
在这里,
# ℹ 77 more rows 表示省略了77行 
# ℹ 5 more variables: homeworld <chr>, ... 表示省略了5个变量,并列出了省略的变量名、变量类型 
请注意,这里打印时省略的变量和个案,不影响数据本身的完整。
 列的性质
从上面可以看到,同样省略了一些行和列,tibble 打印了变量名、变量类型等信息,却丝毫不介绍省略的其他个案。这是为什么呢?
在整洁数据中,相对于行,列(变量)有一些特殊的性质:
- 每一列都有名称(变量名)
 
- 每一列只能储存同种类型的数值,不能“混搭”,比方说
 
- 每一列都可以统计
- A开头姓名的比例(约
5.7%) 
- 身高高于170吗?
 
 
代码
# 仅供参考,不需要掌握
starwars %>%
  summarise(
    percentage = sprintf(
      "%.1f%%",
      mean(str_detect(name, "^A")) * 100
    )
  )
 
 
# A tibble: 1 × 1
  percentage
  <chr>     
1 5.7%      
 
 
这里统计了A开头姓名的比例约为5.7%。
代码
# 仅供参考,不需要掌握
starwars %>%
  transmute(
    height,
    `height > 170` = height > 170
  )
 
 
# A tibble: 87 × 2
   height `height > 170`
    <int> <lgl>         
 1    172 TRUE          
 2    167 FALSE         
 3     96 FALSE         
 4    202 TRUE          
 5    150 FALSE         
 6    178 TRUE          
 7    165 FALSE         
 8     97 FALSE         
 9    183 TRUE          
10    182 TRUE          
# ℹ 77 more rows
 
 
这里判断了各个角色的身高有没有高于170,判断结果为TRUE或FALSE。
整理成表格如下:
| 必须起名(具名性) | 
不需要 | 
| 一定同类(同质性) | 
不一定 | 
| 可以统计(算术性) | 
不可以 | 
 列的类型
列,或者``变量’’,在 R 里面用向量(矢量,vector)来存储。下面介绍一些常见的变量类型:
- 数值型(numeric),包括实数型(double, real)和整数型(integer)
 
- 逻辑型(logical),包括 TRUE 和 FALSE
 
- 字符型(character),包括各种长度的文本
 
- 类别型(factor)、标签型(haven label),通常是数值型变量加上标签
 
- 日期型(date)、日期时间型(datetime),本质是数值型
 
- 几何型(geometry),来自 sf 包,包括点、线、面等,用于空间分析和画图
 
- 其他一维对象
 
- 二维乃至多维对象,比如一列 tibbles,每个单元格存储一个 tibble