接上文
缺失值 Missing Value
在数据集中我们经常会遇到异常值,但是异常值并不能阻止我们对数据进行下一步的分析,此时我们有两个选择:
1. 将具有异常值的数据记录全部删除;
diamonds2 <- diamonds %>%
filter(between(y, 3, 20))
2. 将某条记录中的异常值替换为缺失(NA);ifelse()有三个参数:第一个参数应该是一个逻辑判断test。当test为真时,结果将包含第二个参数的值yes,当test为假时,结果将包含第三个参数的值no。
diamonds2 <- diamonds %>%
mutate(y = ifelse(y < 3 | y > 20, NA, y))
我们并不推荐使用第一种做法, 因为当我们对每一列内容进行异常值判断并删除后,很有可能发现,一些质量较低的数据集中的大部分记录都被删除了,极端情况下可能得到一个空的数据集。因此我们推荐使用第二种做法, 使用缺失值NA来代替异常值。
ggplot在对空值进行绘制时会进行提示,告知部分数据已经被替换为空值无法进行绘制,此处我们使用geom_point绘制过滤后的(x,y)散点图。
ggplot(data = diamonds2) + geom_point(mapping = aes(x = x, y = y))
Warning message:
Removed 9 rows containing missing values (geom_point).
如果我们需要查看缺失值的其余字段数值分布与非缺失值的其余字段的分布时,则需要额外创建一个字段用于判断。此处可以使用is.na()方法构造一个新的字段。比如查看Y值缺失的钻石的X与其余钻石X的数值分布差异。(该用例与原书不同,原书使用了flight数据集,为避免引入额外的数据集,本文直接在diamonds数据集中进行了类似的操作)
diamonds2 %>% mutate(ymissing = is.na(y), nx = x) %>%
ggplot(mapping = aes(nx)) +
geom_freqpoly(mapping = aes(colour = ymissing), binwidth=0.3)
由于该数据中仅存在9个异常值,因此ymissing=True的折线数值较低,此时使用(一)中提到的方法将y轴值域减小,查看分布。
diamonds2 %>% mutate(ymissing = is.na(y), nx = x) %>%
ggplot(mapping = aes(nx)) +
geom_freqpoly(mapping = aes(colour = ymissing), binwidth=0.3) +
coord_cartesian(ylim = c(0, 20))
协变 Covariation
如果变差描述变量内部的行为,那么协变就用于描述变量之间的关系。协变是指两个或多个变量的值以一种相关的方式一起变化的趋势。发现协变变的最好方法是观察两个或多个变量之间的关系。如何观察协变做同样取决于所涉及变量的类型。
1. 一个离散量和一个连续量
通常,我们想要探索一个被分类变量分解的连续变量的分布,就像(一)中表示频率的直方图一样(geom_freqpoly)。但是其形态对于这类比较用处有限,因为高度是由计数给出的。这意味着,如果一个群体比其他群体小得多,就很难看出形状上的差异。例如,让我们探索一下钻石的价格如何随其质量变化:
ggplot(data = diamonds, mapping = aes(x = price)) +
geom_freqpoly(mapping = aes(colour = cut), binwidth = 500)
由于每一类切割方式的钻石在数量上差异很大,所以我们无法直观的看出价格上的数值分布差异。但是我们可以转换一下思路,将绝对数量转变为相对数量,即查看每个价格间隔上钻石的数量占该切割类型总数量的比例,即将各类钻石价格曲线中的数值归一化至了[0,1]内,且各分量数值之和等于1。
ggplot(data = diamonds, mapping = aes(x = price, y = ..density..)) +
geom_freqpoly(mapping = aes(colour = cut), binwidth = 500)
这张图中表现出的内容相当的有趣,可以发现与其余4类切割程度不同的最普通的钻石,在平均售价上居然是最高的(紫色线),这似乎违背了常理。同样我们可以使用箱线图对该现象进行进一步探索,箱线图中的每个类别用一个箱线进行表示,箱线中包含了平均值、最大最小值、25、50、75百分位数等数值统计信息。
ggplot(data = diamonds, mapping = aes(x = cut, y = price)) +
geom_boxplot()
箱线图中包含了更少的分布信息,但是其对统计数值具有更好的表达能力,在图中我们可以明确的看出在平均售价方面平平无奇的钻石是最高的,第二是优质的钻石,完美的钻石平均售价居然最便宜。此时我们可以使用排序函数对箱型图进行排序。
ggplot(data = diamonds, mapping = aes(x = reorder(cut, price, FUN=median), y = price)) +
geom_boxplot()
2. 两个离散变量
两个离散变量的协变需要统计同时发生两种情况的次数,此时可以使用geom_count函数进行统计,此处我们计算钻石切割类型于颜色之间的协变关系。图中每个圆的大小显示在每个值的组合中发生了多少次重复。协变表现为特定x值和特定y值之间的强相关性。
ggplot(data = diamonds) +
geom_count(mapping = aes(x = cut, y = color))
同样我们可以换一种可视化方式,使用网格与颜色的深浅进行度量:
diamonds %>%
count(color, cut) %>%
ggplot(mapping = aes(x = color, y = cut)) +
geom_tile(mapping = aes(fill = n))
3. 两个连续变量
一种可视化两个连续变量之间的协变的好方法是使用geom_point绘制散点图。此处可以看到钻石的克拉大小与价格之间存在的指数关系。
ggplot(data = diamonds) +
geom_point(mapping = aes(x = carat, y = price))
但是随着数据集的增长,散点开始相互覆盖后,散点图的表现形式存在了问题,会形成堆积均匀的黑色区域。解决这个问题的一种方法是根据叠加的次数在alpha通道中添加透明度,为散点图增加更多的美学特性,即点数较少的区域透明度高,反之透明度低。
ggplot(data = diamonds) +
geom_point(mapping = aes(x = carat, y = price), alpha = 1 / 100)
或者我们使用统计离散变量的思路,将整个空间划分为规则格网或规则六边形,统计落在多边形内的点数,并根据点数赋予多边形不同的颜色。
ggplot(data = smaller) +
geom_bin2d(mapping = aes(x = carat, y = price))
另一种思路是将一个连续变量转为离散变量,这样可以使用箱线图的方式对每一类进行统计。
ggplot(data = smaller, mapping = aes(x = carat, y = price)) +
geom_boxplot(mapping = aes(group = cut_width(carat, 0.1)))