查看原文
其他

Y叔 2018-06-01

大家是否还记得我写的文章《画个小圈圈》?里面吐槽了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")

看完还想看之R包系列


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存