> library(tidyverse)
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
√ ggplot2 3.3.1 √ purrr 0.3.4
√ tibble 3.0.1 √ dplyr 0.8.5
√ tidyr 1.1.0 √ stringr 1.4.0
√ readr 1.3.1 √ forcats 0.5.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
Warning messages:
1: 程辑包‘tibble’是用R版本3.6.3 来建造的
2: 程辑包‘tidyr’是用R版本3.6.3 来建造的
3: 程辑包‘purrr’是用R版本3.6.3 来建造的
4: 程辑包‘dplyr’是用R版本3.6.3 来建造的
5: 程辑包‘forcats’是用R版本3.6.3 来建造的
> da <- readLines('http://labfile.oss.aliyuncs.com/courses/978/car.csv')
> da <- unlist(strsplit(da,split=","))
> da <- matrix(da, ncol=6, byrow=TRUE)
> da <- as_tibble(da)
Warning message:
The `x` argument of `as_tibble.matrix()` must have column names if `.name_repair` is omitted as of tibble 2.0.0.
Using compatibility `.name_repair`.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.
> colnames(da) <- da[1,]
> da <- da[-1,]
> da$car <- as.numeric(da$car)
> da$GDP <- as.numeric(da$GDP)
> da$wct <- as.numeric(da$wct)
> da$CPI <- as.numeric(da$CPI)
> da
# A tibble: 31 x 6
province region car GDP wct CPI
<chr> <chr> <dbl> <dbl> <dbl> <dbl>
1 Beijing E 37.7 8.05 86.2 95.9
2 Tianjin E 20.6 8.34 80.5 104.
3 Hebei E 23.3 3.39 45.6 99.0
4 Shanxi M 18.6 3.13 49.7 99.0
5 Neimenggu W 19.6 5.79 56.6 99.1
6 Liaoning NE 11.2 5.07 64.0 100.
7 Jining NE 11.2 3.84 53.4 97.2
8 Heilongjiang NE 5.29 3.28 56.5 101.
9 Shanghai E 18.2 8.18 89.3 102.
10 Jiangsu E 23.9 6.22 61.9 99.0
# ... with 21 more rows
ggplot2 是 tidyverse 生态链的核心 package,因为实验环境中已经安装有 tidyverse package,所以我们可以直接加载它。虚线以上部分是 tidyverse 包含的核心 package,虚线以下部分是 tidyverse 和其它 package 冲突的函数,使用这些函数时需要指明来源。
tibble 本质上也是 data frame 的一种,行为观测值,列为变量,但和 R 中常见的 data.frame 不同,它有许多良好的性质。比如,我们想查看 da 变量的结构或者前几行,不需要再用 str() 或 head() 函数,而是直接运行 da 就可以了。tidyverse 中大部分数据都是 tibble 结构。
6 个变量依次为省份(或直辖市)、地区(E 为东部、M 为中部、NE 为东北、W 为西部)、家用汽车每百户平均保有量、人均GDP、城镇人口比重、交通工具消费价格指数,变量类型前两个为 char、后四个为 double。
> ggplot(data=da)
image.png
只定义数据参数data,此时 ggplot() 生成一张空白的画布。
> ggplot(data=da, mapping=aes(x=GDP, y=car))
image.png
除 data 外,还定义了映射参数 mapping,将 GDP 映射到 x 轴,car 映射到 y 轴,此时图形有了坐标轴。
> ggplot(data=da, mapping=aes(x=GDP, y=car)) + geom_point()
或
> ggplot(da, aes(GDP, car)) + geom_point()
或
> ggplot(data=da) + geom_point(mapping=aes(x=GDP, y=car))
image.png
除数据和映射参数外,还使用 geom_point() 添加了几何对象,此时图中出现了散点,这些点的分布表示平均汽车保有量和人均 GDP 之间似乎存在正相关关系。
如果我们只是想用最少的代码迅速获得对数据的直观感受,可以使用 qplot() 函数。
> qplot(GDP, car, data=da)
image.png
我们将第三个变量 region 赋值给 color,geom_point() 就会自动把观测值按照 region 分组,每组用不同颜色的点在画布上标出。
> ggplot(data=da) + geom_point(mapping=aes(x=GDP, y=car, color=region))
image.png
上图中可以看到,东部省份盘踞在右上角,人均 GDP 和平均汽车保有量都很高,中西部省份则蜷缩在左下角,这体现了我国地区间经济发展的不平衡,共同富裕的发展路线只实现了前面一半,我国仍然处于社会主义初级阶段。
> ggplot(da, aes(GDP, car)) + geom_point(aes(color=region)) + geom_text(aes(label=province), check_overlap=TRUE)
image.png
check_overlap = TRUE 省略了某些省份的名称,保证文本不会有重叠。 从图中来看,最右上角的点毫无疑问是北京。天津和上海两个城市比较特别,拥有很高的人均 GDP,家用汽车平均保有量却相对较低。对这个现象,我们可以做出许多猜想:影响汽车保有量的是否有其它更重要的因素?人均 GDP 是名义值(未经价格调整),也许这两个城市的物价水平很高,导致实际 GDP 较低。或者,这两个城市的其它交通工具较为发达、交通堵塞严重需摇号购车,家用汽车不是人们的首选出行工具…… 左上角的西藏和云南也十分引人注目,它们拥有较低的人均 GDP,家用汽车保有量却相对较高,我们可以猜想,这两个省份地广人稀,家用汽车是必要的出行工具…… 图形启发我们进行了这些猜想,它们不一定正确,需要我们进一步设计研究。
除了 color,geom_point() 还有其它一些属性,比如点的形状(shape)、透明度(alpha)、大小(size)等。
> ggplot(data=da) + geom_point(mapping=aes(x=GDP, y=car, shape=region))
image.png
我们使用 facet_wrap() 将观测值按照 region 分组,就可以看到不同地区的 car 和 GDP 之间的关系了。
> ggplot(data=da) + geom_point(mapping=aes(x=GDP, y=car)) + facet_wrap(~region, nrow=2)
image.png
> ggplot(data=mpg) + geom_point(mapping=aes(x=displ, y=cty))
image.png
面临的是大样本会发生“overplotting” 问题,有些点被临近的点覆盖掉,而且所有点看起来分布得十分均匀。 如果我们想获得更贴近现实(数据)的散点图,可以设置 position = 'jitter'。
> ggplot(data=mpg) + geom_point(mapping=aes(x=displ, y=cty), position='jitter')
image.png
使用 geom_smooth 获得一条拟合观测值的曲线
> ggplot(data=da) + geom_smooth(mapping=aes(x=GDP, y=car))
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
image.png
在图中同时呈现散点和拟合的曲线,并且令 se = FALSE 去掉曲线的置信区间
> ggplot(data=da) + geom_point(mapping=aes(x=GDP, y=car)) + geom_smooth(mapping=aes(x=GDP, y=car), se=FALSE)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
image.png
> ggplot(data=da) + geom_point(mapping=aes(x=GDP, y=car)) + geom_smooth(mapping=aes(x=GDP, y=car), se=FALSE, method='lm')
`geom_smooth()` using formula 'y ~ x'
image.png
> ggplot(data=da) + geom_line(mapping=aes(x=GDP, y=car))
image.png
这样的图看起来没有任何意义。事实上,在时间序列数据的可视化时使用 geom_line() 会比较合适。
> ggplot(data=economics) + geom_line(mapping=aes(x=date, y=unemploy/pop))
image.png
> ggplot(da, aes(GDP, car, color=region)) + geom_point() + geom_smooth(se=FALSE)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
There were 11 warnings (use warnings() to see them)
image.png
对观测值进行分类统计,我们可以用 geom_bar() 画出柱状图。柱状图只需要指定 x 坐标(离散的分类变量),另一个坐标为 count(计数)。
> ggplot(da) + geom_bar(mapping=aes(x=region))
image.png
有时候我们拿到的并不是原始数据,而是已经分类计数好的数据,这时候应该怎么办呢? 假设 demo 是我们拿到的数据,通过令 stat = 'identity',可以画出和上面一样的柱状图来。
> demo <- tribble(
+ ~region, ~freq,
+ "E", 10,
+ "M", 6,
+ "W", 12,
+ "NE", 3
+ )
> ggplot(demo) + geom_bar(mapping=aes(x=region, y=freq), stat='identity')
image.png
假设我们想统计的变量不是离散的,而是一个连续变量,这时候就可以用 geom_histogram() 画直方图。
> ggplot(da, aes(GDP)) + geom_histogram(binwidth=0.5)
image.png
注意设置合适的 binwidth 很重要,你需要根据不同的数据尝试多个 binwidth,选择一个最合适的。 除了直方图外,我们也可以用 geom_freqpoly() 画频率折线图,它与直方图的功能基本一致。
> ggplot(da, aes(GDP)) + geom_freqpoly(binwidth=0.5)
image.png
> ggplot(da, aes(region, GDP)) + geom_boxplot()
image.png
我们可以使用 xlab()、ylab() 函数为坐标轴添加标签
> ggplot(da, aes(GDP, car)) + geom_point() + xlab('Per Capita GDP') + ylab('Car Ownership (%)')
image.png
如果想去掉坐标轴标签,可使用 xlab(NULL)、ylab(NULL)
> ggplot(da, aes(GDP, car)) + geom_point() + xlab(NULL) + ylab(NULL)
image.png
如果我们只想看人均 GDP 在 2 至 4 之间,平均汽车保有量在 10 至 20 之间的省份,可以使用 xlim()、ylim() 函数限定坐标轴范围
> ggplot(da, aes(GDP, car)) + geom_point() + xlim(2, 4) + ylim(10, 20) + geom_text(aes(label=province), check_overlap=TRUE)
Warning messages:
1: Removed 20 rows containing missing values (geom_point).
2: Removed 20 rows containing missing values (geom_text).
image.png
如果我们想交换横纵坐标,可以使用 coord_flip() 函数。特别是当我们在画柱形图或箱线图,横坐标刻度标识很长时,可以交换横纵坐标,这样文字就不会挤在一起。 我们还可以使用 coord_polar() 将笛卡尔坐标系转化为极坐标系。
> bar <- ggplot(da, aes(region)) + geom_bar(mapping=aes(fill=region), show.legend=FALSE, width=1) + xlab(NULL) + ylab(NULL)
> bar + coord_flip()
image.png
> bar + coord_polar()
image.png
网友评论