一条指令把统计+画图都给做了?似乎太美好!
大家是否还记得我写的文章《画个小圈圈》?里面吐槽了ggpubr
这个包的存在是制造混乱,徒增学习成本。我们知道ggplot2
包里有个qplot
函数,而在《ggplot2》的第一版中,hadley先用了一章介绍qplot
,再介绍grammar of graphics,然后这个qplot
就被吐槽,先入为主,给学习grammar of graphics,学习ggplot2语法制造了不必要的麻烦。然后如果你看《ggplot2》第二版,你就会发现qplot
这一章被删掉了。我说ggpubr
制造混乱,徒增学习成本并不是为了吐槽某公众号,而是实事求是。
我并不反对封装,我并没有强迫症说大家一定要用ggplot2图形语法,而不能封装函数,我想我在《画个小圈圈》已经说得很清楚了,封装画图的包,按我的观点是要么卖了数据处理的专业知识,要么卖了画图的专业知识。如果一个包做的封装太过于简单,像ggpubr
这种,数据必须是用户整理好的data.frame,而画图只是简单的两三个图层的叠加,那么当然可以减少你敲键盘输入,然而影响了初级用户学习ggplot2
,复杂的东西,我们当然想要用封装好的函数,等你自己啥都搞懂了,老板都要跟你掀桌子了。简单的东西也可以封装,减少输入嘛,只是特别不适用于ggplot2的图层,简单的设定你写个主题,我都举双手赞成,但两三个图层的简单拼凑我不支持,因为图层是积木,大家学习就是要对积木熟悉,然后才能搭出复杂的东西出来。特别简单的图层叠加正是你熟悉积木的时候,你不多敲点键盘,做为练习,又怎么能做出稍复杂点的东西呢?
我以下面这个ggpubr
的例子来讲一下吧。
set.seed(1234)
df <- data.frame( sex=factor(rep(c("f", "M"), each=200)),
weight=c(rnorm(200, 55), rnorm(200, 58)))
head(df)
## sex weight
## 1 f 53.79293
## 2 f 55.27743
## 3 f 56.08444
## 4 f 52.65430
## 5 f 55.42912
## 6 f 55.50606
ggdensity(df, x="weight", add = "mean", rug = TRUE, color = "sex", fill = "sex",
palette = c("#00AFBB", "#E7B800"))
这个图画density,就是geom_density
这个图层,下面加个指示位置的地毯线就是用geom_rug
:
require(ggplot2)
p <- ggplot(df, aes(weight, fill=sex, color=sex)) +
geom_density(alpha=.5) +
geom_rug()
print(p)
要加上分布的均值之类的统计量,还不容易,随手一算:
require(dplyr)
df2 = group_by(df, sex) %>% summarize(m = mean(weight))
df2
## # A tibble: 2 x 2
## sex m
## <fct> <dbl>
## 1 f 54.9
## 2 M 58.1
然后再用geom_vline
加个线条,要搞颜色也是一样。
p + geom_vline(aes(xintercept=m, color=sex), df2, linetype='dashed') +
scale_fill_manual(values=c("#00AFBB", "#E7B800")) +
scale_color_manual(values=c("#00AFBB", "#E7B800"))
虽然你多输入了很多,但是在不断的输入中,你对各个图层更熟悉了,都是自由组合的组件。而且这还有个前提是ggplot2图层的文档很全,新手学习并不是很费力。所以我也不是说学习是最重要,如果费时费力,你又有产出的压力,比如老板叫你明天把结果放在他桌面上,学个鬼个!黄花菜都凉了。
ggpubr
另一方面是组间比较,这个跑个检验还不简单,要标显著嘛,我好多年前的文章《Use
ggplot2》已经手把手教你们了,就不重复了。
我知道大家都喜欢少敲点代码,对ggpubr
的吐槽一是对学习有负面,二是不中用!今天跟大家一个中用的,比ggpubr
强N倍的包。
- 一键出图,但图不是简单拼图层能够拼出来的
- 附带做了统计,把统计量都给你在图上标准了
这有什么好处?画图+统计都要做,但一般我们开始只是在探索,而不是最终出要发表文章的图,而这个包,一画图就是图+统计,特别省事/省时间,等于说我毫不费力就可以试不同的图和统计检验。
- 场景1,你对这些是懂的,那么你不需要花时间去探索,这个包帮你做了。
- 场景2, 你对这些是不懂的,这是小白福音,你不懂你根本不知道要怎么做,甚至于不知道要做什么,你连学习的方向都没有,但人家帮你做了,你可以有目的性去学习相关的背景。
画图就是在感性(可视化)地探索数据,而统计检验给了你理性(定量)的指标。我们通常需要不断试,各种探索,最后可能都没用,或者有一种是最终要的,这个过程是很花时间的,而这个包,可以让你用很少的时间来探索一下。
ggstatsplot
head(mtcars)
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
比如我想知道汽车的轮子数目和自动波/手波是否有关联,那么二联表走起,然后卡方检验,等你做完一小时过去了。而我用ggstatsplot
包,3秒钟搞定:
library(ggstatsplot)
ggpiestats(data = mtcars,
main = am,
condition = cyl) +
scale_fill_brewer(palette = "Dark2")
实际上你要做多少东西呢:
首先是二联表:
Contingency Tables
──────────────────────────────
cyl 0 1 Total
──────────────────────────────
4 3 8 11
6 4 3 7
8 12 2 14
Total 19 13 32
──────────────────────────────
再都卡方检验:
χ² Tests
──────────────────────────────
Value df p
──────────────────────────────
χ² 8.74 2 0.013
N 32
──────────────────────────────
图上还有一些你可能不懂的东西,比如:
Nominal
────────────────────────────
Value
────────────────────────────
Phi-coefficient NaN
Cramer's V 0.523
────────────────────────────
省了多少时间?如果我只是看一看,最终这个结果我不要,那只花了3秒,如果这是我要的,我不懂卡方的情况下,也能做出来,那么我再有的放矢地去学习,甚至可以自己手工来一遍,这比毫无目的在各种手工学习或试错强太多,OK,我也懂用卡方的情况下,它做的东西,里面也可能有我不懂的东西,比如这个Cramer’s V,就打在图上,不懂,又可以去学习了,学习使我快乐,如果不是在图上看到,我不要说看不懂,根本都不知道有这东西的存在!所以不单单好用,也能让我们学到新东西。最重要的是老板说你先试一下,明天给我看个初步的结果,bingo,今晚可以愉快地睡觉!
组间比较
ggbetweenstats(data = iris,
x = Species,
y = Sepal.Length)
组间比较还有生物狗最喜欢的标注均值,不管是用点和/或数字都行。
相关性
ggscatterstats(data = iris,
x = Sepal.Length,
y = Petal.Length,
title = "Dataset: Iris flower data set")
这里展示的只是最简单的,有很多参数,比如marginal.type = "density"
那么marginal画出来的就不是histogram,而是density
curve。也可以是boxplot哦。
相关性矩阵
ggcorrmat(
data = subset(iris, Species == "versicolor"),
cor.vars = c(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width))
分组做图并拼图
像上面的相关性矩阵,我只是切了versicolor一个物种来画,iris数据我们知道有三个物种,我们可以一个一个做,然后用cowplot
来拼图。
下面我先定义一个函数来画图:
plot_fun = function(data) {
ggscatterstats(
data = data,
x = Sepal.Length,
y = Sepal.Width,
marginal.type = "boxplot",
title =
glue::glue("Species: {(data$Species)} (n = {length(data$Sepal.Length)})")
)
}
然后分组做图:
library(tidyr)
library(purrr)
nested_df <- iris %>%
group_by(Species) %>%
nest() %>%
mutate(p = map(data, plot_fun))
这样就有三张图,用cowplot
当然很容易拼,但我们经常需要拼完再加个title,
再底部加个注释什么的。你当然可以自己再画个tible什么的,然后再去拼。而ggstatsplot
直接封装了cowplot
,并提供了一些参数,让你加标题和注释什么的。比如上面画的三张图,我用combine_plots
拼出来:
combine_plots(
plotlist = nested_df$p,
labels = c("(a)", "(b)", "(c)"),
nrow = 3,
ncol = 1,
title.text = "Relationship between sepal length and width for all Iris species",
title.size = 14,
title.colour = "blue",
caption.text = expression(
paste(
italic("Note"),
": Iris flower dataset was collected by Edgar Anderson."
),
caption.size = 10
)
)
安装
安装要写到最后,因为我知道大家看到这里,才会急于想要来一波走你。目前此包还没在CRAN上,不过作者已经准备提交到,所以很快就会在CRAN上。给大家安装和升级带来便利。
目前可以通过github安装:
devtools::install_github("IndrajeetPatil/ggstatsplot")