简介
实际情况中,数据集几乎不可能是干净整洁的
整理数据的几大原则(Wickham,2014).遵循这些原则对数据进行整理将使其更便于利用ggplot2进行可视化,或利用dplyr进行操作,以及利用许多建模的包来进行建模。整理数据的工具主要由tidyr包支持,它可以帮助清晰凌乱的数据集
不少的可视化操作都需要先转换数据的格式,如从已有变量中创建新的变量或是进行简单聚合以便看到整片“森林”
1. 数据整理
整理数据的原则很简答:让数据变得更好用。数据整理是一个从数据框的统计结构(变量与观测)到形式结构(列与行)的映射。它主要遵循两个准则:
- 每一列代表一个变量
- 每一行代表一个观测
数据整理对ggplot2至关重要,因为ggplot2的任务就是将变量映射到视觉属性上:如果数据不够整洁,那可视化的难度就会增大
有时可能会不知道如何对一个数据集画图,这往往是因为这个数据不够整洁。举个例子,下面的数据框包含了美国劳工市场的月度数据
library("lubridate")
ec2 <- ggplot2::economics %>% tbl_df() %>%
transmute(year = year(date),
month = month(date), rate = uempmed) %>%
filter(year > 2005) %>% spread(year, rate)
ec2
假如想要绘制一个时间序列图以展示过去十年的失业情况变化,需要用到什么ggplot2命令呢?要是更关注失业率随季节的变化呢?也会会将月份作为x轴,对每一年的情况画一条折现。但是这会很困难,因为这个数据有些凌乱,这里由三个变量:月、年和失业率,而它们却以各不相同的方式存储
- month 存储在一列中
- year 分散在各列名中
- rate 是每个单元的值
为了让这个数据便于绘图,首先要对齐进行整理,有两对重要的工具
- spread和gather
- separate和unite
spread和gather
x | y | z |
---|---|---|
a | A | 1 |
b | D | 5 |
c | A | 4 |
c | B | 10 |
d | C | 9 |
x | A | B | C | D |
---|---|---|---|---|
a | 1 | NA | NA | NA |
b | NA | NA | NA | 5 |
c | 4 | 10 | NA | NA |
d | NA | NA | 9 | NA |
仔细观察这两个表,可以发现它们是相同的数据,只是形式不同。第一种形式称为长数据(indexed data,指标型数据),要通过指标来找到对应的数值(变量x和变量y的值)。第二种称为宽数据(Cartesian data,笛卡尔型数据),要通过看行和列的交叉点来找到对应的值。不能简单的说哪种形式更优,因为两种形式都有可能是简洁的,这取决于值 A B C D的含义
(注意到上面的缺失值:在一个形式下明确存在的缺失值可能在另一种形式下不存在。NA确实代表了一种缺失情况,但有时数值缺失单纯是因为那里没有值)
数据蒸馏常常需要化宽为长,称为聚集gathering,但偶尔也会需要化长为宽,称为扩散spreading。tidyr包分别提供了gather()函数和spread()函数来实现以上操作
还可以考虑扩展到更高维的情况,但是有时数据总是用二维存储的(行和列),所以这些考虑有趣但并不实用
1. gather
gather()函数有4个主要参数
- data 需要调用的数据集
- key 存放原来各列名的新变量的变量名
- value 存放原来各单元格中的值的新变量的变量名
- … 指定要聚集的变量 可以通过枚举进行指定:A,B,C,D,或者通过范围进行指定:A:D,或者通过-号指定不需要聚集的列:-E,-F
接下来整理上述economics数据集,首先观察year、month和rate三个变量
month变量已经排成一列了,而year和rate是宽数据形式,需要用gather()函数把它们转换成长数据形式
gather(ec2, key = year, value = unemp, `2006`: `2015`)
注意这些列名不是R中标准的列名(不以字母开头),这意味着需要加反引号来指代它们
也可以通过排除month列的方法得到需要的形式
gather(ec2, key = year, value = unemp, -month)
为了使数据更好用,还可以增加两个另外的参数
economics_2 <- gatehr(ec2, year, rate, `2006`: `2015`,
convert = TRUE, na.rm = TRUE)
economics_2
convert = TRUE 将year变量从字符串型转换为数值型,na.rm = TRUE则可以自动移除没有值的月份(其实这个缺失并不是数据的丢失,而只是因为那个时间还没有到而已)
以上数据整理好之后,就很容易对此进行各种可视化操作。比如关注长期趋势,或是查看季节性变化
ggplot(economics_2, aes(year + (month - 1)/ 12, rate)) + geom_line()
ggplot(economics_2, aes(month, rate, group = year)) + geom_line(aes(color = year), size = 1)
2. spread
spread()函数是gather()的逆运算,可以将数据化长为宽。如下数据集中有三个变量(day、rain和temp),但是rain和temp数据是长数据形式
weather <- dplyr::data_frame(
day = rep(1:3, 2),
obs = rep(c("temp", "rain"), each = 3),
val = c(c(23, 22, 20), c(0, 0, 5)))
weather
spread()函数帮助将凌乱的长数据转换为整齐的款数据,它同样有gather()函数的几个参数。需要指定需要转换的data,以及key和value对应的列名
spread(weather, key = obs, value = val)