点击蓝字
关注我!
写在前面
本系列为《R数据科学》(R for Data Science)的学习笔记。相较于其他R语言教程来说,本书一个很大的优势就是直接从实用的R包出发,来熟悉R及数据科学。更新过程中,读者朋友如发现错误,欢迎指正。如果有疑问,也可以在评论区留言或后台私信。希望各位读者朋友能学有所得!
BOOK
1.5
几何对象
以下两张图的相似程度有多大?
两张图有同样的 x 变量和 y 变量,而且描述的是同样的数据。但这两张图并不一样,它们各自使用不同的可视化对象来表示数据。在 ggplot2 语法中,我们称它们使用了不同的几何对象。
几何对象是图中用来表示数据的几何图形对象。我们经常根据图中使用的几何对象类型来描述相应的图。例如,条形图使用了条形几何对象,折线图使用了直线几何对象,箱线图使用了矩形和直线几何对象。散点图使用了点几何对象。如上面的两幅图所示。左侧的图使用了点几何对象,右侧的图使用了平滑曲线几何对象,以一条平滑曲线来拟合数据。 要想改变图中的几何对象,需要修改添加在 ggplot() 函数中的几何对象函数。举例来说,要想绘制出上图,你可以使用以下代码:
1# 左图
2ggplot(data = mpg) +
3 geom_point(mapping = aes(x = displ, y = hwy))
4# 右图
5ggplot(data = mpg) +
6 geom_smooth(mapping = aes(x = displ, y = hwy))
根据表示汽车驱动系统的 drv 变量的值,这里的geom_smooth() 函数分别用 3 条曲线来表示汽车。
1ggplot(data = mpg) +
2 geom_smooth(mapping = aes(x = displ, y = hwy, linetype = drv))
只要将一个图形属性映射为一个离散变量(如上个示例中的 linetype),ggplot2 就会自动对数据进行分组来绘制多个几何对象。这个功能非常方便,因为按照图形属性的这种分组不用添加图例,也不用为几何对象添加区分特征:
1ggplot(data = mpg) +
2 geom_smooth(mapping = aes(x = displ, y = hwy))
3ggplot(data = mpg) +
4 geom_smooth(mapping = aes(x = displ, y = hwy, group = drv))
5ggplot(data = mpg) +
6 geom_smooth(
7 mapping = aes(x = displ, y = hwy, color = drv),
8 show.legend = FALSE #不添加图例
9 )
要想在同一张图中显示多个几何对象,可以向 ggplot() 函数中添加多个几何对象函数:
1ggplot(data = mpg) +
2 geom_point(mapping = aes(x = displ, y = hwy)) +
3 geom_smooth(mapping = aes(x = displ, y = hwy))
但是,这样代码就产生了一些重复。假如你想将 y 轴上的变量从 hwy 改成 cty,那么就要在两个地方修改这个变量,但你或许会漏掉一处。避免这种重复的方法是将一组映射传递给 ggplot() 函数。ggplot2 会将这些映射作为全局映射应用到图中的每个几何对象中。换句话说,以下代码将绘制出与上面代码同样的图:
1ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
2 geom_point() +
3 geom_smooth()
如果将映射放在几何对象函数中,那么 ggplot2 会将其看作这个图层的局部映射,它将使用这些映射扩展或覆盖全局映射,但仅对该图层有效。这样一来,我们就可以在不同的图层中显示不同的图形属性:
1ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
2 geom_point(mapping = aes(color = class)) +
3 geom_smooth()
同理,你也可以为不同的图层指定不同的数据。下图中的平滑曲线表示的只是 mpg 数据集的一个子集,即微型车。geom_smooth() 函数中的局部数据参数覆盖了 ggplot() 函数中的全局数据参数,当然仅对这个图层有效:
1ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
2 geom_point(mapping = aes(color = class)) +
3 geom_smooth(
4 data = filter(mpg, class == "subcompact"),#filter()函数用来选取部分数据
5 se = FALSE #se 是否在平滑曲线周围显示置信区间,False不显示,True显示
6 )
1.6
统计变换
下面的条形图显示了 diamonds 数据集中按照 cut 变量分组的各种钻石的总数量。diamonds 数据集是 ggplot2的内置数据集,包含大约 54000 颗钻石的信息,每颗钻石具有 price、carat、color、 clarity 和 cut 变量。条形图显示,高质量切割钻石的数量要比低质量切割钻石的数量多:
1ggplot(data = diamonds) +
2 geom_bar(mapping = aes(x = cut))
条形图 x 轴显示的是 cut,这是diamonds 数据集中的一个变量。y 轴显示的是 count,但count 不是 diamonds 中的变量!那么 count 来自哪里呢?很多图形绘制的是数据集的原始数据,比如散点图。另外一些图形则可以绘制那些计算出的新数据,比如条形图。
• 条形图、直方图和频率多边形图可以对数据进行分箱,然后绘制出分箱数量和落在每个分箱的数据点的数量。
• 平滑曲线会为数据拟合一个模型,然后绘制出模型预测值。
• 箱线图可以计算出数据分布的多种摘要统计量,并显示一个特殊形式的箱体。绘图时用来计算新数据的算法称为 stat(statistical transformation,统计变换)。下图描述了geom_bar() 函数的统计变换过程。
通常来说,几何对象函数和统计变换函数可以互换使用。例如,你可以使用 stat_count()替换 geom_bar() 来重新生成前面那张图:
1ggplot(data = diamonds) +
2 stat_count(mapping = aes(x = cut))
如果想显示一张表示比例(而不是计数)的条形图
1ggplot(data = diamonds) +
2 geom_bar(
3 mapping = aes(x = cut, y = ..prop.., group = 1)
4 )
你可能想要在代码中强调统计变换。例如,你可以使用 stat_summary() 函数将人们的注意力吸引到你计算出的那些摘要统计量上。stat_summary() 函数为 x 的每个唯一值计算 y 值的摘要统计:
1ggplot(data = diamonds) +
2 stat_summary(
3 mapping = aes(x = cut, y = depth),
4 fun.min = min,
5 fun.max = max,
6 fun = median #统计最大、最小值,中位数
7 )
ggplot2 提供了 20 多个统计变换以供你使用。每个统计变换都是一个函数,因此你可以按 照通用方式获得帮助,例如 ?stat_bin。
1.7
位置调整
条形图还有一项神奇的功能,你可以使用 color 或者 fill 图形属性来为条 形图上色:
1ggplot(data = diamonds) +
2 geom_bar(mapping = aes(x = cut, color = cut)) #边框
3ggplot(data = diamonds) +
4 geom_bar(mapping = aes(x = cut, fill = cut)) #填充
注意,如果将 fill 图形属性映射到另一个变量(如 clarity),那么条形会自动分块堆叠起来。每个彩色矩形表示 cut 和 clarity 的一种组合。
1ggplot(data = diamonds) +
2 geom_bar(mapping = aes(x = cut, fill = clarity))
这种堆叠是由 position 参数设定的位置调整功能自动完成的。如果不想生成堆叠式条形图,你还可以使用以下 3 种选项之一:"identity"、"fill" 和 "dodge"。
• position = "identity" 将每个对象直接显示在图中。这种方式不太适合条形图,因为条形会彼此重叠。为了让重叠部分能够显示出来,我们可以设置 alpha 参数为一个较小的数,从而使得条形略微透明;或者设定 fill = NA,让条形完全透明:
1ggplot(
2 data = diamonds,
3 mapping = aes(x = cut, fill = clarity)
4) +
5 geom_bar(alpha = 1/5, position = "identity")#透明度,上图
6ggplot(
7 data = diamonds,
8 mapping = aes(x = cut, color = clarity)
9) +
10 geom_bar(fill = NA, position = "identity") #空白填充,下图
• position = "fill" 的效果与堆叠相似,但每组堆叠条形具有同样的高度,因此这种条形图可以非常轻松地比较各组间的比例:
1ggplot(data = diamonds) +
2 geom_bar(
3 mapping = aes(x = cut, fill = clarity),
4 position = "fill"
5 )
• position = "dodge" 将每组中的条形依次并列放置,这样可以非常轻松地比较每个条形表示的具体数值:
1ggplot(data = diamonds) +
2 geom_bar(
3 mapping = aes(x = cut, fill = clarity),
4 position = "dodge"
5 )
通过将位置调整方式设为“抖动”,可以避免网格化排列。position = "jitter" 为每个数据点添加一个很小的随机扰动,这样就可以将重叠的点分散开来,因为不可能有两个点会收到同样的随机扰动:
1ggplot(data = mpg) +
2 geom_point(
3 mapping = aes(x = displ, y = hwy),
4 position = "jitter"
5 )
添加随机性来改善图形似乎是一种奇怪的方式,然而尽管这种方式会损失图形的精确性, 但可以大大提高图形的启发性。因为这种操作的用处非常大,所以 ggplot2 提供了geom_ point(position = "jitter") 的一种快速实现方式:geom_jitter()。
1ggplot(data = mpg) +
2 geom_jitter(
3 mapping = aes(x = displ, y = hwy))
1.8
坐标系
坐标系可能是 ggplot2 中最复杂的部分。默认的坐标系是笛卡儿直角坐标系,可以通过其 独立作用的 x 坐标和 y 坐标找到每个数据点。偶尔也会用到一些其他类型的坐标系。
coord_flip() 函数可以交换 x 轴和 y 轴。当想要绘制水平箱线图时,这非常有用。它也非常适合使用长标签,但要想在 x 轴上不重叠地安排好它们是非常困难的:
1ggplot(data = mpg, mapping = aes(x = class, y = hwy)) +
2 geom_boxplot() #左图
3ggplot(data = mpg, mapping = aes(x = class, y = hwy)) +
4 geom_boxplot() +
5 coord_flip() #右图
• coord_quickmap() 函数可以为地图设置合适的纵横比。当使用 ggplot2 绘制空间数据时, 这个函数特别重要:
1BiocManager::install('maps')
2install.packages("maps") #下载maps包(两种方法任选一种可用的)
3library(maps) #加载maps
4nz <- map_data("nz") #导入内置数据
5ggplot(nz, aes(long, lat, group = group)) +
6 geom_polygon(fill = "white", color = "black") #左图
7ggplot(nz, aes(long, lat, group = group)) +
8 geom_polygon(fill = "white", color = "black") +
9 coord_quickmap() #调整纵横比,右图
• coord_polar() 函数使用极坐标系。极坐标系可以揭示出条形图和鸡冠花图间的一种有 趣联系:
1bar <- ggplot(data = diamonds) +
2 geom_bar(
3 mapping = aes(x = cut, fill = cut),
4 show.legend = FALSE,
5 width = 1
6 ) +
7 theme(aspect.ratio = 1) +
8 labs(x = NULL, y = NULL)
9bar
10bar + coord_flip()
11bar + coord_polar()
1.9
图形分层语法
在前面几节中,你学到的绝不仅仅是如何绘制散点图、条形图和箱线图,而是使用 ggplot2绘制任何类型图形的基础知识。为了说明这一点,我们向前面的代码模板中添加位置调整、统计变换、坐标系和分面:
1ggplot(data = <DATA>) +
2 <GEOM_FUNCTION>(
3 mapping = aes(<MAPPINGS>),
4 stat = <STAT>,
5 position = <POSITION>
6 ) +
7 <COORDINATE_FUNCTION> +
8 <FACET_FUNCTION>
模板中的 7 个参数一同组成了图形语法,即用于建立图形的一个正式语法系统。你可以将任何图形精确地描述为数据集、几何对象、映射集合、统计变换、位置调整、坐标系和分面模式的一个组合,图形语法正是基于这样的深刻理解构建出来的。
为了说明图形语法的工作方式,我们看一下如何从头开始构建一个基本图形:首先需要有 一个数据集,然后(通过统计变换)将其转换为想要显示的信息。
接下来,你可以选择一个几何对象来表示转换后的数据中的每个观测值,然后选择几何对象的图形属性来表示数据中的变量,这会将每个变量的值映射为图形属性的水平。
下一步是选择放置几何对象的坐标系。你可以使用对象位置(对象本身的一个图形属性) 来显示 x 变量和 y 变量的值。这样就生成了一张完整的图。但你还可以进一步调整几何对象在坐标系中的位置(位置调整),或者将图划分为多个子图(分面)。你还可以通过添加一个或多个附加图层对图进行扩展,其中每个附加图层都使用一个数据集、一个几何对象、一个映射集合、一个统计变换和一个位置调整。
你可以使用这种方法构建你能够想象到的任何图形。换句话说,你可以使用在本章中学到 的代码模板来构建成千上万种独特的图形。
— END —
往期 · 推荐
《R数据科学》学习笔记|Note2:使用ggplot2进行数据可视化(上)
零基础"机器学习"自学笔记|Note6:正规方程及其推导(内附详细推导过程)
欢迎关注 木舟笔记