6

前言

最近在写深度学习系列文章时遇到了一些瓶颈, 很多统计分析结果和函数激活图像都需要可视化显示, 但是不太擅长这方面的相关技术, 所以先暂停理论知识更新, 准备用2天时间, 掌握一下基于R的ggplot2的可视化分析技术.

一. 图形语法

图形语法部分计划写的的大纲如下:

  • 名词解释 -- 已完成
  • 入门作图实验(入门函数qplot作图,初步认识ggplot2) -- 已完成
  • 图层语法及使用 -- 进行中
  • 工具箱, 标度,坐标轴,图例及定位
  • 美化及主题

1. 名词解释

图形语法由Wilkinson创建, 这里不做形而上学的晦涩描述, 简单来讲, 图形语法回答了"什么是统计图形"这一问题.

那么, 什么是统计图形?
一个图形就是一种映射再加一些补充信息:

  • 一种映射: 一个从数据(data)几何对象(geom)图形属性(aes)的一个映射.
  • 其它部件: 包括统计变换(stats),标度(scale), 坐标系(coord), 分面(facet).

几个重要名词的补充说明:
几何对象: 点, 线, 多边形;
标度: 数据取值映射到图形空间;
统计变换: 对数据的某种汇总, 如数据分组计数创建直方图;
分面: 绘图窗口拆分成多个子窗口, 也叫网格作图.

注:
该小节只是对图形与发的几个名词做了基本解释, 后面将对ggplot2的图形语法做深入讲解.

2. qplot用法

qplot()是ggplot2的一个入门级作图函数, 意思是quick plot. 利用它可方便做出各种复杂图形.
qplot和R的plot很像, 使用方法也差不多, 完整的参数列表可通过help(qplot)或者?qplot来获取.

2.0 相关包安装

安装tidyverse包并加载:

install.packages('tidyverse')
library(tidyverse)

注意:
tidyverse是一个集合各种常用R包的综合大礼包。安装并library(tidyverse)后, 默认导入以下包括ggplot2在内的多个依赖包:

# console output:
─────── Attaching packages ────────
✔ ggplot2 2.2.1     ✔ purrr   0.2.4
✔ tibble  1.3.4     ✔ dplyr   0.7.4
✔ tidyr   0.7.2     ✔ stringr 1.2.0
✔ readr   1.1.1     ✔ forcats 0.2.0

或者也可以单独安装ggplot2:

install.packages('ggplot2')
library(ggplot2)

2.1 数据集

使用qqplot2自带的diamonds数据集.

clipboard.png

创建一个小数据集:

set.seed(1000)
dsmall <- diamonds[sample(nrow(diamonds), 100), ]

qplot() usage:

qplot(x, y = NULL, ..., data, facets = NULL, margins = FALSE,
  geom = "auto", xlim = c(NA, NA), ylim = c(NA, NA), log = "",
  main = NULL, xlab = deparse(substitute(x)),
  ylab = deparse(substitute(y)), asp = NA, stat = NULL, position = NULL)

2.2 简单的散点图

require(ggplot2)
set.seed(1410)
dsmall <- diamonds[sample(nrow(diamonds),100),]
qplot(carat, price, data=diamonds) # 注: carat, price是diamonds数据集的两列, 分别映射到qplot()的x和y上

clipboard.png

2.3 统计变换

qplot(log(carat), log(price), data=diamonds) # 求log(carat)关于log(price)的关系

clipboard.png

2.4 颜色,形状

添加颜色:

qplot(carat, price, data=dsmall, colour=color)

clipboard.png

添加形状:

qplot(carat, price, data=dsmall, shape=cut, colour=color)

clipboard.png

颜色, 形状大小都是图形属性的具体例子,每个图形属性都对应了一个标度函数,将数据取值映射到图形属性的有效取值上, 如上图, dsmall数据集中cut列每一个取值都被映射成了一种散点形状, 右侧图形标度除了各种颜色和图形的映射关系.

2.5 透明度

使用透明度控制颜色和取值的映射, 可以有效减轻图形元素重叠现象, 使用alpha的图形属性, 取值从0到1, 通常透明度用分数表示, 如1/10, 1/20, 分母表示重叠多少次后颜色将不透明:

qplot(carat, price, data=diamonds, alpha=(1/10))

clipboard.png

2.6 适用范围

  • 颜色形状适用分类变量
  • 大小适合连续变量
  • 分面适合区分不同组之间的属性

2.7 几何对象(geom)

gplot()通过改变几何对象, 几乎可以画出任何一种类型的图形, 不同的几何对象描述了数据展示的不同方式, 特别地, 有些几何对象需要关联相应的统计变换, 如频率直方图需要先分组计数再加上条形几何对象.

常见的二维变量关系:

  • geom = 'point': 散点图, 指定x和y时qplot()的默认设置
  • geom = 'smooth': 拟合一条平滑曲线, 并展示曲线和标准误差
  • geom = 'boxplot': 箱线胡须图, 概括一系列点的分布情况
  • geom = 'path', geom = 'line': 数据点连线, 典型用法: 探索x轴变量和y轴变量之间的关系; 'line'只能创建从左到右的连线,'path'可以是任意方向.

常见的一维分布:

  • geom = 'histogram': 直方图, 若只指定x参数, qplot()默认绘制直方图
  • geom = 'freqpoly': 频率多边形
  • geom = 'density': 密度曲线
  • geometry= 'bar': 常用于离散变量, 用来绘制条形图

2.8 平滑曲线

标准平滑

数据平滑曲线可用来展示大量数据点的某种趋势, 可以利用c()函数将多个几何对象组成向量传给geom, 几何对象的堆叠顺序和传递顺序一致:

qplot(carat, price, data = diamonds, geom = c("point", "smooth"))
qplot(carat, price, data = diamonds, geom = c("point", "smooth"), se = FALSE) # 不包含标准误差

下图展示了默认参数的的平滑曲线:
i) 包含标准误差:
clipboard.png

ii) 不包含标准误差:
clipboard.png

从平滑曲线中我们可以看出carat和price之间近似的指数关系;

平滑器的选择

ggplot内置了很多平滑器:
小数据集:
n<= 1000, 默认平滑器为method = 'loess'
算法: 局部回归
取值: 曲线平滑程度由span参数控制,取值0(很不平滑)->1(很平滑)

大数据集
n>1000, Loess对大数据集并不合适(内存消耗O(n^2)), 此时使用的平滑器为method = 'gam'
算法: formula = y ~ s(x)调用mgcv包拟合一个广义加和模型, 标准平滑公式: y~s(x, bs='cs')

线性拟合
拟合一条直线, method = 'lm', 也可以通过formula = y ~ poly(x,2)拟合一个二次多项式.
method = 'rlm'和前者类似, 但是更稳健, 对异常值不太敏感.

2.9 箱线图和扰动点图

假设横轴x = c('D','E','F','G','H','I','J')是一个包含7种颜色的分类变量, y是一个或多个连续变量.
通过箱线图扰动点图可以知道连续变量是如何随着分类变量的变化而变化的:
扰动点图:

qplot(color, price/carat, data = diamonds, geom = 'jitter', alpha = I(1/40))

clipboard.png

箱线图:

qplot(color, price/carat, data = diamonds, geom = 'boxplot', alpha = I(1/5))

clipboard.png

总结:

  • 箱线图 能展示四分位数的位置, 可用colour控制外框颜色, 用fill设置填充颜色, 用size调节线的粗细
  • 扰动点图 能根据透明度的不同看出数据集中的地方, 能像普通散点图一样控制图形属性: size, colour, shape

2.10 直方图和密度曲线图

直方图

频数直方图:

qplot(carat, data = diamonds, geom = 'histogram')

clipboard.png

密度直方图:

qplot(carat, ..density.., data = diamonds, geom = 'histogram')

clipboard.png
密度直方图将数据分组求密度后映射到Y轴, 而频数直方图将数据分组计数后映射到Y轴.

分组(fill)及平滑度(binwidth)调整:

qplot(carat, data = diamonds, geom = 'histogram', binwidth=0.1, fill=color)

clipboard.png

密度曲线

qplot(carat, data = diamonds, geom = 'density')

clipboard.png

分组(colour)及平滑度(adjust)调整:

qplot(carat, data = diamonds, geom = 'density', adjust = 0.8, colour = color)

clipboard.png

总结

  • 平滑度越大, 越能看出整体特征, 平滑度越小, 越能显示细节特征.
  • 直方图平滑度通过binwidth(组距)调整, 密度曲线平滑度通过adjust调整

2.11 条形图

频率条形图

qplot(color, data = diamonds, geom = 'bar')

clipboard.png

按值加权条形图

qplot(color, data = diamonds, geom = 'bar', weight = carat) + scale_y_continuous("carat")

clipboard.png

注意:
上述两图纵坐标不同,第一张图展示了各颜色的频率分布, 第二张图展示carat属性的值在各种颜色上的加权和, 物理意义: 每种颜色的钻石的总重量.

2.12 线条图和路径图

线条图和路径图常用来可视化时间序列数据.
新数据集
ggplot2自带economics数据集, 该数据集包含美国过去40年的经济数据, 有时间变量.
clipboard.png

线条图

qplot(date, unemploy/pop, data = economics, geom = 'line')

clipboard.png

上图展示了失业率($unemploy/pop$)随时间变化趋势, 因为线条图只能从左到右绘制, 故时间变化的方向被隐藏了.

路径图
通过路径图, 将年份映射到colour属性上, 这样便能看清楚时间的行进方向:

# 定义一个函数, 将字符串类型的date('1968-08-09')转换成YYYY格式的数字(1968)
year <- function(x) as.POSIXlt(x)$year + 1900
qplot(unemploy/pop, uempmed, data = economics, geom = c('point','path'), colour = year(date))

clipboard.png
图中uempmed是失业星期数取中位数, 代表了失业时长. 从图中可以看出, 失业率和失业时间是高度相关的, 且最近几年(浅蓝色), 相同的失业率下, 失业时长急剧增长.

2.13 分面

比较不同分组的方法:

  • 同一张图上: 根据图形属性颜色形状来区分
  • 多张图上: 数据分割, 创建图像矩阵, 每个图形矩阵的窗格显示一个数据子集

y轴变换

  • 频数 qplot()的分面绘制时默认y轴映射成频数, 代表各个数据子集上, 对x分组计数
  • 密度 qplot()新语法支持以..density..的形式告诉ggplot2将密度映射到y轴
# Y轴:频数
qplot(carat, data = diamonds, facets = color ~ ., geom = 'histogram', binwidth=0.1, xlim = c(0,3))
# Y轴:密度
qplot(carat, ..density.., data = diamonds, facets = color ~ ., geom = 'histogram', binwidth=0.1, xlim = c(0,3))

qplot()中默认分面方法: 通过row_var ~ col_var创建一个图形矩阵.

# 这里我们限制了下每个子图的横轴范围xlimi, 组距设置为0.1
qplot(carat, data = diamonds, facets = color ~ cut, geom = 'histogram', binwidth=0.1, xlim = c(0,3))

clipboard.png

图示创建了一个行为color, 列为cut的图形矩阵, 每个分面的纵轴均为钻石重量carat.

只指定列, 不指定行

# 用.作为row_var的占位符
qplot(carat, data = diamonds, facets = . ~ color, geom = 'histogram', binwidth=0.1, xlim = c(0,3))

clipboard.png

只指定行, 不指定列

qplot(carat, data = diamonds, facets = color ~ ., geom = 'histogram', binwidth=0.1, xlim = c(0,3))

clipboard.png

2.14 外观控制

坐标轴区间
xlim, ylim控制, 例: xlim = c(0,20), ylim =c(-0.9, 0.9)
图形标题
main控制主标题, xlab, ylab分别控制x轴y轴的标签(label), 这三个值都可以是字符串或者数学表达式
log
log是个字符型向量,log='x'表示x轴取对数, log = 'xy'表示x轴和y轴都取对数.

完整的示例:

qplot(carat, price/carat, data = diamonds, geom = 'point', 
      xlim = c(.2, 1), # x轴显示区间: 0.2~1.0
      log = 'y', # log变换
      xlab = 'Weight (carats)',  # xlab: 字符串
      ylab = expression(frac(price,carat)),  # ylab: 数学表达式
      main='Small diamonds'  # 主标题: 字符串
      )

clipboard.png

3. 图层语法及使用

ggplot2的图层语法基于Wilkinson的图形语法, 且在此基础上添加了很多新功能.

要点
我们要明白图层语法的精髓--图层语法给了我们一个基本的作图框架, 使我们可以从更高的视角审视图形的构成,且每个图形组件都可以被修改.
我们可以按需添加所需图形组件, 其它现存的图形组件可以继续使用--在已有的几何对象基础上, 添加了新的统计变换后, 原有的几何对象依然可以使用.

下面将以以标准散点图为例, 来进一步解释几个核心概念:

qplot(carat, price, data = dsmall, colour = cut)

clipboard.png

标度转换
数据单位(升, 英里/加仑等)转换成可识别物理单位(像素, 颜色)的过程称为标度转换(scaling).
标度转换后的数据对于电脑是可识别的, 比如颜色用十六进制表示(#FF6C91), 大小, 形状分别用数字和整数来表示, 下面的图形属性中将给出grid绘图函数中(ggplot2底层使用了grid绘图函数)的图形属性的基本标度转换形式.

图形属性
在散点图中, 每个观测数据都用一个点来表示, 点的位置有两个变量的值来决定, 每个点有横坐标, 纵坐标, 还有大小, 颜色形状, 这些都称为图形属性.

总结一下, 图形属性的构成及grid绘图函数中的表示方式:

  • 颜色[1. RGB方式: '#RRGGBB'; 2. 名字表示: 'red,blue'; 3. rgb(), hsv(), hcl()可在不同的色彩空间创建颜色]
  • 线条类型[1. 整数or名字: 0=blank, 1=solid, 2=dashed, 3=dotted, 4=dotdash, 5=longdash, 6=twodash]
  • 形状[1. 0~25数字, 如0=空心方块,19=实心大圆, 2=空心三角, 3=十字, 4=叉; 2. 单字符, 直接用输入字符作绘图符号; 3. 用.绘制最小课室举行]
  • 大小[文本, 点, 线条宽度单位均是毫米]
  • 对齐方式[1.一个字符: 'left','right','centre', 'center', 'bottom', 'top'; 2: 0~1之间的数字, c(0,0): 左下角; c(1,0): 左上角, c(0,1): 右下角]

: 每个图形属性都是一个常数或者变量, 是需要用数字填充的!!

几何对象
几何对象决定了图形的类型, 举例来讲, 对于常见的只含一种几何对象的图, geom='point'时就是散点图, geom='bar'则是条形图.

常见的几何对象:

  • 点(point)
  • 线(line)
  • 条(bar)
  • 箱(boxplot)

: 多种几何对象组合而成的图形往往没有名字.

坐标系统
常见的坐标系统是笛卡尔坐标系, 此外还有极坐标底图中的球投影坐标.
ggplot2在用绘图系统的grid函数昨晚标度转换后, 最后将根据数据点的值(x,y)来确定其在途中的位置,此时由坐标系统Coord来完成.

标度变换
标度变换在ggplot2绘图过程中非常重要, 包含多个步骤

  • 标度转换(Transform scales)
  • 标度训练(Train scales)
  • 标度映射(Map scales).

在绘制复杂图形时, 标度变换需要额外的步骤, 因为在添加了统计变换后,绘图系统需要保证标度转换多个数据集里都是相同的.

比如如下包含多分面多图层的复杂图形:

qplot(displ, hwy, data = mpg, facets = .~year) + geom_smooth()

clipboard.png

说明:

  1. 上图中增加了平滑曲线层, 因此, 绘图系统将数据映射到图形属性后,要对其进行统计变换.
  2. 对于小数据集的平滑, 统计变换先用一条loess平滑曲线拟合数据, 然后用等间隔点作为输入, 计算并返回对应的预测值.
  3. 常用的统计变换有: 平滑(smooth), 封箱(binning), 求组平均(group means), 分位数回归(quantile gression), 等高线(contouring).

ggplot2绘图过程包含如下几步:

  1. 变量映射到图形属性[Map variables to aesthetics]
  2. 分面处理[Facet datasets]
  3. 标度转换[Transform scales]
  4. 计算图形属性[Compute aesthetics]
  5. 标度训练[Train scales]
  6. 标度映射[Map scales]
  7. 渲染几何对象[Render geoms]

注意以下几点:

  1. 标度转换先于统计变换 统计量基于标度变换后的数据计算, 可保证变换后的f(x),f(y)和原始x,y在线性尺度上的图保持一致
  2. 标度训练是全局操作 标度训练保证了标度在整体数据范围上统一, 不同Layer叠加后它们的位置不会错乱
  3. 标度映射是一个局部操作 ggplot2将标度映射到图形属性中, 每个数据点对应一个图形属性之, 生成新的数据集后在用几何对象渲染
  4. 绘图过程本质上是一个数据变换和映射过程

4. 标度详解

标度(scale)控制数据到图形属性的映射, 每种标度都是一个数据空间定义域图形属性空间值域映射函数.
标度有两项基本功能:

  • 将数据转化为图形属性(形状, 位置, 颜色, 大小)
  • 生成引导元素, 即提供读图工具(坐标轴, 图例, 总称)

4.1 标度的定义域和值域

定义域
标度的定义域对应着该标度变量的取值范围, 标度的定义域可能是离散型或者连续型.

  • 变量为离散型时, 标度的定义域是变量的值组成的集合,此时以因子,字符逻辑值的形式存储,如{carni, herbi, omni}, {TRUE, FALSE, TRUE}
  • 变量为连续型时, 标度的定义域是一个值域, 如[0.004, 3.923]

值域
标度的值域包含可感知的R能理解的图形属性:位置, 颜色,形状, 大小, 线条类型. 标度的, 标度的值域也可以是离散型或者连续型的.

  • 离散型标度 值域是输入值对应的图形属性值组成的一个向量
  • 连续型标度 值域是穿过,某复杂空间的一条一维路径, 如[0.004, 3.923]的标度值域是可以是一种颜色到另一种颜色通过线性差值得到的一组渐变色.

定义域到值域的映射

1.变换(transformation)
只针对连续型定义域.如, 对数据取对数或开根号.变换完成后生成新的数据, 此后将对每一层做统一摘要, 摘要保证了变换后的图形和变换前在线性尺度上一致.

2.训练(training)
标度训练主要完成标度的定义域计算.
对于单图层原始数据图形绘制中, 连续性变量,只需要得到变换后数据最大值和最小值即可,离散型更简单, 只需要列出所有不重复的类别性变量.
对对于横跨多个数据集的多个图层, 标度定义域计算将更复杂, 但本质上还是统一各图层的变量域, 保证最终画到图形上时, 各图层的标度定义域一致.

定义域通过手动设置参数limits输入时, 训练过程将被跳过.

3.映射(mapping)
执行映射函数, 将标度的值域和训练后的定义域数据映射到图形属性.

4.2 标度分类

标度分位四组:

  • 位置标度 将连续性, 离散型和日期时间型变量映射到绘图区域或者构造坐标轴
  • 颜色标度 将连续性, 离散型变量映射到颜色
  • 手动离散型标度 将离散型变量映射到用户自定义符号大小, 线条类型, 形状货颜色, 以及图例
  • 同一型标度 将变量值直接绘制成图形属性, 跳过标度映射阶段.

标度相关内容请参考R帮助文档: ?scale_brewer

通用参数
  • 标签name

设置坐标轴或者图例上的标签, 支持指定字符串或者数学表达式. 常用的辅助函数: xlab(), ylab(), labs()

默认标签为数据字段名:

p <- qplot(cty, hwy, data = mpg, colour = displ)
p

clipboard.png

注意x,y轴及图例上的标签均为输入数据字段名.

连续性数据位置标签:

p <- qplot(cty, hwy, data = mpg, colour = displ)
p + scale_x_continuous('City mpg') + scale_y_continuous('Highway')

clipboard.png

xlab, ylab指定的标签:

p <- qplot(cty, hwy, data = mpg, colour = displ)
p + xlab('City labx') + ylab('Highway laby')

clipboard.png

labs指定的标签:

p <- qplot(cty, hwy, data = mpg, colour = displ)
p + labs(x = 'city labx', y = 'Highway laby ', colour ='labcolour')

clipboard.png

expression指定的标签:

p <- qplot(cty, hwy, data = mpg, colour = displ)
p + xlab(expression(frac(miles, gallon))) + ylab(expression(frac(miles, 'denom')))

clipboard.png

  • limits

固定标度的定义域, 连续性标度接受一个长度为2的数值型向量如c(0.4, 5.2), 离散型标度接受一个字符型向量如c('red','black').
一旦设定了limits, 数据将不会进行任何训练.
无limits:

p <- qplot(cyl, wt, data = mtcars, colour = drat)
p 

clipboard.png

设定了limits:

p <- qplot(cyl, wt, data = mtcars, colour = drat)
p + scale_x_continuous(limits = c(5.5, 6.5)) 

clipboard.png

p <- qplot(cyl, wt, data = mtcars, colour = drat)
p + scale_x_continuous(limits = c(5.5, 6.5)) +  scale_colour_gradient(limits = c(4.0, 5.5))

clipboard.png

  • breaks

控制坐标轴或者图例上哪些刻度线上的值应该显示, 或者连续性标度在图例上如何被分段, labels指定了断点处显示的标签.

p <- qplot(cyl, wt, data = mtcars, colour = drat)
p + scale_x_continuous(limits = c(5.5, 6.5)) + scale_colour_gradient(breaks = c(3.0,4.5))

clipboard.png

  • formatter

如果没有指定任何标签, 将在每个断点处自动调用formatter()来格式化生成标签, 连续性标度的标签刷为comma, percent, dollar, scientific, 离散型标度的标签刷为abbreviate.

位置标度

每张图形有两个位置标度: x标度和y标度. ggplot2提供连续性, 离散型(因子,字符,逻辑型向量)和日期型标度.
相关的辅助函数: xlim(), ylim()和lims()
标度举例:
xlim(10,20): 从10到20的连续型标度
ylim(20,10): 20到10翻转后的连续型y轴标度
xlim("a","b","c"): 离散型标度
xlim(as.Data(c("2008-06-01","2008-04-01")): 日期型标度
连续型位置标度
常见: scale_x_continuousscale_y_continuous
每个连续型标度都可接受一个trans参数, 裕兴线性或非线性变化.
常见的变换器: asn($tanh^{-1}(x)$), exp, identity, log, log10, log2, logit, pow10, probit,, recip, reverse, sqrt
变换器常用来修改位置标度, 并且有渐变写法:
scale_x_continuous(trans='log10')等价于scale_x_log10()
注意: 区分对标度变换和对数据变换是不同的, 即对数据取对数和对标度进行对数变换是不同的:
对数据变换:

qplot(log10(carat), log10(price), data = diamonds)

clipboard.png

对标度变换:

qplot(carat, price, data = diamonds) + scale_x_log10()+ scale_y_log10()

clipboard.png

颜色标度
手动离散型标度
同一型标度

4.3 图例和坐标轴

5 工具箱

6 美化及主题

二. 可视化应用

1 快速制图

2 绘制条形图

3 绘制折线图

4 绘制散点图

5 绘制数据分布图

  • 直方图
  • 密度区县
  • 频数多边形
  • 箱线图及小提琴图
  • 分组点图
  • 二维密度图

6 组件示例

  • 注解
  • 坐标轴
  • 图例
  • 分面
  • 配色
  • 整体外观

未完待续~


夏天的风
152 声望42 粉丝

这里是蛮荒之地, 不再维护, 已转到: [链接]