诚邀广大R语言、数据可视化爱好者和我们一起搬迁升级谢益辉著作《现代统计图形》
- 已编辑
Jonie_Y 我出版的几本英文书都是 CC 协议,跟出版社签合同时,合同上写着我给出版社独家印刷销售的权利,而在线电子版保留 CC 许可证。我不是法律人士,我也不知道这样做是否合规,但现在很多作者都这样跟风了,也开始有别的出版社允许这样做了。
Jonie_Y 读书不算多,一年十本左右。很多我发出来的引用不是从书里读来的,而是杂七杂八的文章里读到的别人的引用,这会给人一种错觉,仿佛我读过全书,但我并没有。偶尔我会因为看到一句话而找全书来读,但这种情况比较少。
你的“道与术,道法自然,术法行转”讲得很好啊。
Jonie_Y 其实我也有写作梦(我指的是非技术方面的写作),但思来想去我好像不是这块料,我好像擅长的只是挑刺、吐槽和腹诽。
“最寒冷的冬天是旧金山的夏季”这句话据(谣)传是马克吐温说的,译成中文感觉就没那么逗了(本来是说旧金山湾区的海边气候令人惊异,大夏天去那儿被冻成狗)。
The coldest winter I ever spent was a summer in San Francisco.
而且“XX 的冬天是 XX 的夏季”读起来怪怪的,为啥不用“夏天”而用“夏季”呢(看,立马开始挑刺)。
目前该书引入的 R 包已经相当多了,R 包需要的系统依赖也很多,接下来将尽量不再引入新的依赖,如非确实必要也可加!感觉维护这玩意太累了,最近一次想添加制作视频动画的依赖就废了好大功夫,目前 Travis 编译一次竟然需要23分钟,这应该也是我想使得本书在线编译的必然结果。
Rscript -e "sessionInfo(.packages(T));capabilities()"
R version 3.6.1 (2017-01-27)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.6 LTS
Matrix products: default
BLAS: /home/travis/R-bin/lib/R/lib/libRblas.so
LAPACK: /home/travis/R-bin/lib/R/lib/libRlapack.so
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] base compiler datasets graphics grDevices grid methods
[8] parallel splines stats stats4 tcltk tools utils
other attached packages:
[1] abind_1.4-7 alphahull_2.2 animation_2.6
[4] aplpack_1.3.3 askpass_1.1 assertthat_0.2.1
[7] av_0.3 backports_1.1.5 base64enc_0.1-3
[10] BH_1.69.0-1 bitops_1.0-6 bookdown_0.14
[13] broom_0.5.2 cairoDevice_2.28 callr_3.3.2
[16] caTools_1.17.1.2 cellranger_1.1.0 classInt_0.4-1
[19] cli_1.1.0 clipr_0.7.0 coda_0.19-3
[22] colorspace_1.4-2 corrplot_0.84 cowplot_1.0.0
[25] crayon_1.3.4 crosstalk_1.0.0 curl_4.2
[28] data.table_1.12.4 DBI_1.0.0 dbplyr_1.4.2
[31] deldir_0.1-23 dendextend_1.12.0 digest_0.6.21
[34] dplyr_0.8.3 e1071_1.7-2 ellipsis_0.3.0
[37] evaluate_0.14 fansi_0.4.0 farver_1.1.0
[40] fastmap_1.0.1 filehash_2.4-2 forcats_0.4.0
[43] foreach_1.5.1 formatR_1.7 fs_1.3.1
[46] fun_0.2 gclus_1.3.2 gdata_2.18.0
[49] gdtools_0.2.1 generics_0.0.2 GGally_1.4.0
[52] gganimate_1.0.3.9000 ggplot2_3.2.1 ggpointdensity_0.1.0
[55] gifski_0.8.6 glue_1.3.1 goftest_1.1-1
[58] gplots_3.0.3 gridExtra_2.3 gtable_0.3.0
[61] gtools_3.8.1 gWidgets_0.0-54.1 gWidgetsRGtk2_0.0-86
[64] haven_2.1.1 heatmaply_0.16.0 hexbin_1.27.3
[67] highr_0.8 hms_0.5.1 htmltools_0.4.0
[70] htmlwidgets_1.5.1 httpuv_1.5.2 httr_1.4.1
[73] igraph_1.2.4.1 iplots_1.1-7.1 iterators_1.0.12
[76] jsonlite_1.6 knitr_1.25 labeling_0.3
[79] later_1.0.0 latex2exp_0.4.0 lazyeval_0.2.2
[82] leaflet_2.0.2 lifecycle_0.1.0 lmtest_0.9-37
[85] lpSolve_5.6.13.3 lubridate_1.7.4 magick_2.2
[88] magrittr_1.5 manipulateWidget_0.10.0 maps_3.3.0
[91] maptools_0.9-8 markdown_1.1 MatrixModels_0.4-2
[94] mime_0.7 miniUI_0.1.1.1 misc3d_0.8-4
[97] modelr_0.1.5 MSG_0.4 munsell_0.5.0
[100] mvtnorm_1.0-11 network_1.15 openssl_1.4.1
[103] pdftools_2.2 pillar_1.4.2 pkgconfig_2.0.3
[106] plogr_0.2.0 plot3D_1.1.1 plotly_4.9.0
[109] plotrix_3.7-6 plyr_1.8.4 png_0.1-7
[112] polyclip_1.10-0 prettyunits_1.0.2 processx_3.4.1
[115] progress_1.2.2 promises_1.1.0 ps_1.3.0
[118] purrr_0.3.2 qap_0.1-1 qpdf_1.1
[121] quantreg_5.51 R.methodsS3_1.7.1 R.oo_1.22.0
[124] R.utils_2.9.0 R6_2.4.0 randomForest_4.6-14
[127] raster_3.0-7 RColorBrewer_1.1-2 Rcpp_1.0.2
[130] readr_1.3.1 readxl_1.3.1 registry_0.5-1
[133] rematch_1.0.1 remotes_2.1.0 reprex_0.3.0
[136] reshape_0.8.8 reshape2_1.4.3 rgeos_0.5-2
[139] rggobi_2.1.22 rgl_0.100.31 RgoogleMaps_1.4.4
[142] RGtk2_2.20.36 rJava_0.9-11 rlang_0.4.0
[145] rmarkdown_1.16 rstudioapi_0.10 rvest_0.3.4
[148] scales_1.0.0 scatterplot3d_0.3-41 selectr_0.4-1
[151] seriation_1.2-8 sf_0.8-0 sgeostat_1.0-27
[154] shiny_1.4.0 showtext_0.7 showtextdb_2.0
[157] signal_0.7-6 sm_2.2-5.6 sna_2.4
[160] sourcetools_0.1.7 sp_1.3-1 SparseM_1.77
[163] spatstat_1.61-0 spatstat.data_1.4-0 spatstat.utils_1.13-0
[166] splancs_2.01-40 statnet.common_4.3.0 stringi_1.4.3
[169] stringr_1.4.0 svglite_1.2.2 sys_3.3
[172] sysfonts_0.8 systemfonts_0.1.1 TeachingDemos_2.11
[175] tensor_1.5 tibble_2.1.3 tidyr_1.0.0
[178] tidyselect_0.2.5 tidyverse_1.2.1 tikzDevice_0.12.3
[181] tinytex_0.16 transformr_0.1.1 tripack_1.3-8
[184] TSP_1.1-7 tuneR_1.3.3 tweenr_1.0.1
[187] units_0.6-5 utf8_1.1.4 vcd_1.4-4
[190] vctrs_0.2.0 vioplot_0.3.2 viridis_0.5.1
[193] viridisLite_0.3.0 webshot_0.5.1 whisker_0.4
[196] withr_2.1.2 xfun_0.10 xml2_1.2.2
[199] xtable_1.8-5 yaml_2.2.0 zeallot_0.1.0
[202] zoo_1.8-7 boot_1.3-22 class_7.3-15
[205] cluster_2.1.0 codetools_0.2-16 foreign_0.8-71
[208] KernSmooth_2.23-15 lattice_0.20-38 MASS_7.3-51.4
[211] Matrix_1.2-17 mgcv_1.8-28 nlme_3.1-140
[214] nnet_7.3-12 rpart_4.1-15 spatial_7.3-11
[217] survival_2.44-1.1
jpeg png tiff tcltk X11 aqua
TRUE TRUE TRUE TRUE TRUE FALSE
http/ftp sockets libxml fifo cledit iconv
TRUE TRUE TRUE TRUE FALSE TRUE
NLS profmem cairo ICU long.double libcurl
TRUE TRUE TRUE TRUE TRUE TRUE
有时候只用到一个大包的一个小函数,不妨自己替换一下,若是在文中重复用到倒也不必替换。举个栗子,我看到 Hadley 的书 《Advanced R》里写了 ruler
函数,它的作用是显示当前页面一行容纳的字数。这个玩意和调用 LaTeX 里的文武线有点相似!
https://github.com/hadley/adv-r/blob/4915e2984168da50671491db238d351e5590c07b/Introduction.Rmd#L267
ruler <- function(width = getOption("width")) {
x <- seq_len(width)
y <- case_when(
x %% 10 == 0 ~ as.character((x %/% 10) %% 10),
x %% 5 == 0 ~ "+",
TRUE ~ "-"
)
cat(y, "\n", sep = "")
cat(x %% 10, "\n", sep = "")
}
ruler()
替换为下面这样
https://github.com/XiangyunHuang/MASR/blob/83f6faad32ca2e4114d043b8d21284fb4b9d4685/index.Rmd#L118
ruler <- function(width = getOption("width")) {
x <- seq_len(width)
y <- ifelse(x %% 10 == 0, as.character((x %/% 10) %% 10),
ifelse(x %% 5 == 0, "+", "-")
)
cat(y, "\n", sep = "")
cat(x %% 10, "\n", sep = "")
}
ruler()
从而去掉 dplyr 及其相关依赖。我这拨操作会不会引来一些负面效应?比如侵权啥的?如果不会的话,我真希望大家把自己的包的依赖都搞得尽可能小(在性能不会有显著损失的情况下)。
Cloud2016 如果是曾国藩来写这个函数,恐怕会是这种天然呆风格:
ruler <- function(width = getOption("width")) {
x <- seq_len(width)
y <- rep('-', width)
y[x %% 5 == 0] <- '+'
y[x %% 10 == 0] <- seq_len(width %/% 10) %% 10
cat(y, "\n", sep = "")
cat(x %% 10, "\n", sep = "")
}
ruler()
你用 ifelse()
当然也是极好的。此处用 dplyr::case_when()
在我看来就属于杀鸡用牛刀了,用一个笨重的依赖完成了一个细枝末节的任务,我觉得不值当。
净土宗在包的依赖问题方面确实是有不少问题,它的那些不靠谱的反对党还煞有介事地搞了个踢馆的网站名曰 Tinyverse:http://www.tinyverse.org 但基本上都是说了些废话(谁还不知道引入依赖的坏处?)、给自己的个人网站打广告(独孤求赞)、以及展示他们自己的确认偏误(看!Tidyverse 又搞砸了吧)。这个问题不能一概而论,不同人的平衡点不一样:你是选择臃肿而方便,还是选择轻量而麻烦?就以上的 ruler()
函数而言,引入 dplyr 当然是毫无必要;但如果在一个项目中大量使用了 dplyr 包中的其它主打函数,那么顺手用一下 case_when()
也无妨。就是看引入依赖的动机和目的是什么了。我一般倾向于用基础 R 函数,如果有什么杂项任务需要完成,我就写个零依赖的函数丢到 xfun 包中,当然偶尔也需要用到依赖,但 xfun 包本身没有硬性依赖,依赖按需安装就好了。ruler()
这种函数就适合放在这般乌合之众的包中。
@yihui 谢大在这里提到曾国藩,我乍一看不明白其中逻辑!搜罗一番才知道他有个特点:结硬寨、打呆仗!吸引我去搜罗的另一个原因是我以前看过《走向共和》这部剧,里面多次提到李鸿章的老师曾国藩,同治中兴的重要人物!这部剧我觉得是对李鸿章一个富有立体感的呈现,非常推荐!以前有人推荐我看《曾文正公》文集,说里面还有很多为人处世的东西,今天搜罗一番后,我觉得我应该弄来好好看看!
回到正题,我其实没想那么多,引起 tidyverse or not 的讨论?tidyverse 本身是好的,它的一致性胜过一切,在《现代统计图形》这本书所有内容都完备的时候,我会再清理一遍代码,看一些地方是不是值得用,或者是不是某一章可以全部转化为 tidyverse 风格,但是最后应该不是随处散落 tidyverse 的代码
至于宣传方面,《Tidyverse design principles》<https://principles.tidyverse.org/> 《Tidyverse 设计原理》的风格就是举例子说明 Base R 哪个地方不好,所以我要造一个新的东西!这本身就是一个强大的宣传攻势,新事物诞生往往也是靠这个路子,这个风有点猛,一些 R 前辈老人可能受不住!两边能融合该多好,不要去学习两个新的东西,让 R 来一次壮士断腕,奔向一个 4.0 or 5.0 时代,像 Python2 走向 Python3 那样?
limiting dependencies in R package development 里面介绍的小技巧长姿势了。