24.关于Exploratory Data Analysis之四
【上一篇:23.关于Exploratory Data Analysis之三】
【下一篇:24.关于Exploratory Data Analysis之五】
关于共变(Covariation)
如果variation描述的是变量内部的行为,那covariation描述的是变量之间的行为。共变是两个或多个变量的值以一种相关的方式一起变化的趋势。发现共变的最好方法是将两个或多个变量之间的关系形象化。如何做到这一点又取决于所涉及的变量类型。
共变这一篇分三部分:第一部分是一个分类变量和一个连续变量的共变;第二部分是两个分类变量的共变;第三部分是两个连续变量的共变。这一篇只讲第一部分,第一部分主要介绍的是geom_boxplot()箱线图函数,也就是说箱线图是展示一个分类变量和一个连续变量共变的几何图形。
一个分类变量和一个连续变量
我们经常想要探索连续变量被分类变量分解的分布,如前面的频率多边形(横坐标表示的是连续型变量,颜色代表不同的分类变量的值)。geom_freqpoly()的default appearance对于这种比较不是很有用,因为高度是由计数给出的。这意味着,如果其中一个group比其他群体小得多,就很难看出形状上的差异。例如,让我们看看钻石的价格是如何随质量变化的:
ggplot(data = diamonds, mapping = aes(x = price)) +
geom_freqpoly(mapping = aes(colour = cut), binwidth = 500)
图片.png
很难看出分布上的差异,因为总体数量差异太大了:
ggplot(diamonds) +
geom_bar(mapping = aes(x = cut))
图片.png
为了使比较更容易,我们需要交换y轴上显示的内容。而不是显示计数,我们将显示density,这是计数标准化,以便每个频率多边形下的面积是1。
ggplot(data = diamonds, mapping = aes(x = price, y = ..density..)) +
geom_freqpoly(mapping = aes(colour = cut), binwidth = 500)
图片.png
这里有一些相当令人惊讶的事情——似乎Fair的钻石(最低质量)有最高的平均价格!但这可能是因为频率多边形有点难以解释——在这个图中有很多东西。
用分类变量来显示连续变量分布的另一种方法是箱线图。箱线图是一种可视化的值分布简写,在统计学家中很流行。每个箱线图包括:
1. 一个从第25百分位延伸到第75百分位的分布的方框,这个距离被称为四分位数区间(IQR)。在方框的中间是一条显示中位数的线,即第50百分位数的分布。这三条线可以让你了解distribution的spread以及distribution是关于中位数对称还是偏向一边。
2. 分布在box任意边沿的点是超过1.5倍IQR的observations,这些边缘点是不寻常的,所以单独绘制。
3. 从盒子的两端延伸到分布中最远的非离群点的线(或须)。
箱线图的说明
让我们看看使用geom_boxplot()不同cut下price的分布:
ggplot(data = diamonds, mapping = aes(x = cut, y = price)) +
geom_boxplot()
箱线图
我们看到的关于分布的信息要少得多,但是箱线图更紧凑,所以我们可以更容易地比较它们(并在一个图上适合更多)。它支持了一个反直觉的发现,即质量更好的钻石平均来说更便宜!在练习中,你会被要求找出原因。
cut是一个有序的因子(factor),上图中横坐标的顺序就是按照cut这个因子的顺序排的,很多分类变量并没有这样内置的顺序,这时可以用reorder()这个函数,例如,mpg数据集中,hwy(每加仑高速公路英里数)在每个class(汽车类型,两座车还是SUV等等):
ggplot(data = mpg, mapping = aes(x = class, y = hwy)) +
geom_boxplot()
图片.png
为了使趋势更容易看到,我们可以基于hwy的中值对class进行重新排序:
ggplot(data = mpg) +
geom_boxplot(mapping = aes(x = reorder(class, hwy, FUN = median), y = hwy))
# 还记得coord_flip()吗?如果横坐标名字太长,可以用这个函数翻转图片
ggplot(data = mpg) +
geom_boxplot(mapping = aes(x = reorder(class, hwy, FUN = median), y = hwy)) +
coord_flip()
图片.png
reorder()函数的title是Reorder Levels of a Factor,帮助文档是:
reorder(x, ...)
## Default S3 method:
reorder(x, X, FUN = mean, ...,
order = is.ordered(x))
# x:向量,通常是个因子,被认为是用来被排序的分类变量,如果不是因子,那它的唯一值将会用来做隐式level。
# 我的理解是很多时候我们遇到的多是不是因子的情况。
# X:是一个与x相同长度的向量,函数根据第二个参数对应变量的值对分类变量进行重新排序
# FUN:默认是按照X的平均值对x进行排序,当然也可以是其他的
# order : 返回值是否为有序因子而非因子。如果x是有序的,那最后返回的就是有序的,反之不是
练习题
1. 用你学到的知识改进取消和未取消航班的预计出发时间的分布。
nycflights13::flights %>%
mutate(
cancelled = is.na(dep_time),
sched_hour = sched_dep_time %/% 100,
sched_min = sched_dep_time %% 100,
sched_dep_time = sched_hour + sched_min / 60
) %>%
ggplot(mapping = aes(sched_dep_time)) +
geom_boxplot(mapping=aes(x=cancelled,y=sched_dep_time))
图片.png
2. 在diamonds数据集中,哪个变量对预测钻石的价格最重要。这个变量和cut有什么关联?为什么这两种关系的结合会导致低质量的钻石更贵呢?
首先需要看一个diamonds数据集中各个变量与price系,对于连续型变量(carat,克拉、x,长度、y,宽度、z,深度、depth,总深度百分比、table,钻石顶点相对最宽点的宽度),用散点图可视化变化趋势,甚至可以加上geom_smooth()看一下曲线;对离散型变量,用到本篇学到的共变思想,采用箱线图展示变量和price分布的关系。最后我发现,钻石价格受重量(carat)的影响更大。看一下cut与carat的关系,如下图,发现质量比较好的钻石重量都偏小,Fair类代表的质量最差的钻石的重量趋向于更大。正是这种重量会在更大程度上影响价格的原因才导致质量低的钻石反而更贵的结果。
图片.png
3. 用ggstance包画一个水平的箱线图,这个与coord_clip()比如何?
当你不了解一个包或者一个函数的时候,第一时间应该去找这个包或函数的官方文档。个人的不良习惯是第一时间去百度找翻译好的,这样的坏处是百度翻译好的大部分是碎片化的,看不到这些包和函数的原文解释,总觉得跟要学习的知识隔着一层。
找到这个包里能画箱线图的函数是geom_boxploth()。
ggstance包含的函数
ggstance包相较于coord_flip()函数可以实现更精细化的水平调整,coord_flip()实现的是图片的整体翻转,更精细的有的是实现不了的。用法和其他ggplot函数是一样的,从帮助文档中截取的命令:
ggplot(mpg, aes(class, hwy, fill = factor(cyl))) +
geom_boxplot() +
coord_flip()
ggplot(mpg, aes(hwy, class, fill = factor(cyl))) +
geom_boxploth()
# 注意下geom_boxploth()中参数的顺序哈,稍稍拧一下
4. 箱形图的一个问题是,它们是在一个数据集小得多的时代开发的,往往显示大量的“离群值”。解决这个问题的一种方法是使用the letter value plot。安装lvplot包,并尝试使用geom_lv()来显示price和cut的分布。你学到了什么?你如何解释这些图?(我又要刨坑了)
5. 将geom_violin()与facetted的geom_histogram()或colored的geom_freqpoly()进行比较和对比。每种方法的优点和缺点是什么?
个人观点:小提琴图每个纵坐标处的宽度代表每组中此carat对应的count,小提琴图更简洁直观,还可以画在一张图里,分面的话对于较多分组比较不太友好。但分面图可以看到count具体落在什么区间范围内,小提琴图就看不到了,你只能比较组间肚子大小,却不能看到具体值。freqpoly图在比较组间的时候效果比直方图更好些,但看起来线很乱,如果组太多而且组间趋势不那么相似的话,估计这个图就不好看了。
ggplot(data=diamonds)+geom_violin(mapping = aes(x=cut,y=carat))
ggplot(data=diamonds)+geom_histogram(mapping = aes(y=carat))+facet_wrap(~cut,nrow=1,ncol=5)
ggplot(data=diamonds)+geom_freqpoly(mapping = aes(y=carat,color=cut))
geom_violin
geom_histogram
geom_freqpoly
6. 如果您有一个较小的数据集,有时使用geom_jitter()来查看连续变量和分类变量之间的关系是很有用的。ggbeeswarm包提供了许多类似于geom_jitter()的方法。列出它们,并简要描述每一个的作用。
还记得用geom_point()做散点图的时候,position="jitter"可以让所有的点都显示出来,原因是position_jitter()函数为每个点加的抖动。
library("ggpubr")
p1<-ggplot(data=mpg)+geom_point(mapping = aes(x=cty,y=hwy))
p2<-ggplot(data=mpg)+geom_point(mapping = aes(x=cty,y=hwy),position="jitter")
ggarrange(p1,p2)
散点图jitter
geom_jitter()函数的官方文档描述是:The jitter geom is a convenient shortcut for geom_point(position = "jitter"). It adds a small amount of random variation to the location of each point, and is a useful way of handling overplotting caused by discreteness in smaller datasets.以前没看过,现在记录下。
安装ggbeeswarm包的时候遇到些麻烦,因为我的R是4.1.0版本的,直接install.packages("ggbeeswarm")的时候提示"package or namespace"错误,这是版本不行的问题,直接默认安装ggbeeswarm是0.6.0版本,所以我安装了0.5.3版本
require(devtools)
install_version("ggbeeswarm",version = '0.5.3')
如果有必要的话,所依赖的beeswarm也安装低版本的吧,目前最新的版本是0.4.0,是基于R4.2.0构建的
install_version("beeswarm",version = '0.3.1')
ggbeeswarm包中的函数有:geom_beeswarm、geom_quasirandom、ggbeeswarm、position_beeswarm、position_quasirandom。好吧,一眼看过去又是我不能理解的部分,刨坑!
虽然又刨了两个坑,但今天是我最认真做练习题的一天。
【上一篇:23.关于Exploratory Data Analysis之三】
【下一篇:24.关于Exploratory Data Analysis之五】