R语言数据实战 | 代码规范与文档撰写
R语言虽然有着强大的统计分析和绘图功能,但说到底它是一门编程语言。既然如此,那么R语言就有自己的代码规范,这些规范旨在让R学习者养成良好的代码写作习惯,也方便代码作者和他人阅读代码。至于R语言文档撰写,R Markdown是一款基于Markdown功能强大的R语言文档撰写和排版工具,它可以轻松地重现我们的数据分析工作。本节将了解基本的R语言代码规范和如何利用R Markdown进行文档撰写工作。值得注意的是,本节介绍的代码规范属于“约定俗成”,但并不是“金科玉律”。熟练运用语言后,每个人可能会有自己的代码风格,这其中最重要的,是秉持简洁、可读性强的原则。
1. 注释
注释是一门编程语言的基本要素,更是R语言用户的自我修养。抱着对自己代码负责任的态度,养成良好的注释习惯,利人利己。一般的R代码中,注释包括:文件注释、代码块的注释以及具体重要单行代码的注释。
所谓文件注释,就是要在文件代码开始前需要声明的一些内容,比如:什么环境下运行本代码、使用哪个版本的RStudio、约定编码方式(通常是 utf-8)以及这个代码文件主要是用来干什么的。通常文件注释开始可以用两个#。
代码块注释顾名思义就是对某个代码块的一个注释。在R中为了提高代码效率,通常把函数模块化,以避免代码大面积重复,这时来一行代码块注释可能会更搭配。代码块注释通常也是使用两个#开头。
最后是单行代码注释,也可以叫作短注释,通常放在一行代码的后面,在代码较长时也可以另起一行进行注释,但要尽量保证每行代码对齐,不然代码加注释混在一起,就给人一种“一桶浆糊”的感觉了。
2. 命名规范
与注释一样,R语言中规范地对代码中的变量、函数和文件名进行命名也是R语言用户的一项基本操守。
对R文件的命名应尽可能以体现文件内容为准,比如,这个文件代码是用来分析NBA球员投篮数据的,那么文件可以命名为analysis_nba_data.R,千万不要随便命名,日后坑的都是自己。
函数和变量的命名则需要尤其小心,R环境对于大小写是极其敏感的,变量名应该都使用小写字母,而函数名则可以在首字母使用大写。另一点需要注意的是,变量和函数命名时应尽量避免与R环境中本身存在的一些函数或者变量重名,不然系统也会混乱弄不清。不同单词间可以用“.”或者“_”来连接。这主要看个人使用习惯,也可以遵从一些业内固定代码规范。谷歌曾推出过一套R语言代码规范,推荐使用“.”来连接。而命名函数则尽量不要使用下划线或者点连接符,在单词选择上也最好能体现函数的动作,以动词来命名函数。看下面的例子:
变量
正例:shooting_distance shooting.distance
反例:ShootingDistance
函数
正例:GetShootingEff
反例:getshootingeff
3. 代码组织
有组织有层次的R代码通常会出现在正式的项目中,读者可以去github上观摩一下项目代码的组织形式。在正式的R语言项目里,以下内容是必不可少的:
(1)版权声明;
(2)编码和环境声明;
(3)作者注释;
(4)文件说明;
(5)项目目的;
(6)输入与输出说明;
(7)函数定义说明;
(8)其他。
在日常的R代码训练中,这些就有点过于苛求了。但是还是提醒读者,平时养成多声明的习惯好,不然等正式接项目了,必定手足无措、漏洞百出。
4. R语言编程的一般约定
除了上述不能违背的一些较为明显的规定之外,在R中通常还包括一些约定俗成的规则。Google的R代码规范手册中有如下规定:
(1)每行代码最长不超过80个字符合理。一行代码过长,效率低又不美观。
(2)使用空格键空两格进行缩进,尽量不要用Tab键。
(3)在使用二次运算符时(+ - = <-)两端都需要空一格。非常简单的建议,保证代码不挤在一起一团糟。
(4)逗号。逗号前不用空格,但逗号后一定要空一格。同第3条,很实用的建议。
(5)分号。无特殊情况不要使用分号。
(6)花括号。通常在循环语句或者自定义函数中需要用到。左花括号不换行写,右花括号独占一行写。
(7)尽量少用attach()函数。
(8)小括号。在前括号前加一个空格,但调用函数时除外,特指if等循环命令。
(9)全部代码约定应保持一致。不能一会儿有空格,一会儿又挤在一起,当然我们要求是全部有空格。
最后,需要提醒读者注意的是,这里的规范是指“约定俗成”的一种规矩,但并不是“金科玉律”。以上Google代码规范是由Google公司总结定义的,而每个数据分析师也可以在这个规范上稍有不同,遵从其他规范或自成一体。尽管在R语言的基因中有诸多争议的地方[ R的若干基因及争论:https://yihui.name/cn/2012/09/equal-and-arrow/],但是从语言规范上,仍然需要保持代码整洁、风格一致、可读性强的原则。
5. 测试代码效率并优化
实际上,这部分并不属于R代码规范的必备内容。但还是有必要强调一下。无论新手老手,都不可能把程序写得完美无缺,当你写完一段代码之后,需要测试这段代码的效率并对其进行不断地优化。RGui中没有测试代码的工具,但RStudio完美地解决了这一问题。在用Debug检测完代码正确与否之后,还可以使用Profile来检测代码效率如何,这一点无论是对R新用户还是老用户都不容易。
常用的优化代码效率的方式包括:函数模块化、向量化运算以及多使用R内置函数。首先介绍函数模块化。通常在重复调用一些含有较多参数的函数时,代码会看起来很臃肿,一眼看去就有很多冗余。比如,ggplot()函数通常会包括众多参数,在重复调用时可以自定义一个调用函数,将我们想利用的图形、格式、参数都模块化到自定义函数模块中去,这样会大大提升代码效率。
其次少用循环而多用R自带的向量化运算。常常被人告诫R的循环效率极低,能不用则不用;事实也是如此,不妨在写for或者while时想想能否用现成的向量或者矩阵运算替代。
最后则是要尽可能地利用R中已经封装好了的函数,不要为求平均值还要自己去编循环,其实mean()函数就可以搞定。重复的事情在目前情况下尽量少做,一句话,都是为了效率。
R Markdown(简称Rmd),从字面上看,就是一款基于Markdown的R语言写作工具。Markdown是什么呢?首先Markdown一定是用来写作的,其次用Markdown写作的文本具有一定的格式。简单来说,Markdown是一款可以用文本编辑器编写的标记语言。通过一些简单的标记语言,就可以使文本具备一定的排版格式,非常简单好用。下面就来看看在RStudio中如何使用R Markdown。
1. 为什么要使用R Markdown?
使用Rmd最大的好处就是:可以轻松地重现你的数据分析工作(make your work reproducible)。从原始数据的读入、清洗到最后的分析挖掘过程,每一步的R code都被清晰地记录在案。阅读你的Rmd结果的人可以完整地审查你的分析思路和过程。
如何用Rmd将数据分析代码和结果以文件的形式输出为相应的报告呢?由于这块知识点细节的内容非常多,下面用一个数据实例来进行Rmd基本操作流程的演示,然后再去总结一些关键点帮助大家理清Rmd的基本知识。
一个以iris数据集为基础生成的Rmd展示如图1所示。
图1 完整的Rmd输出效果
下面就以iris数据集为例,从Rmd的文档结构、Markdown基本语法、插入代码、以及结果输出等4个方面讲述如何做一份美观大方的Rmd数据分析报告。图2展示的是笔者以html格式输出的Rmd结果,可以看到Rmd输出的R代码块还是比较整洁美观的。
图2 Rmd中的代码块
2. Rmd的文档结构
由图1中的框框和箭头可以直观地看到,一份完整的Rmd文档通常由以下三个部分构成:
(1)---:符号内的YAML渲染参数
(2)可自由写作的text文本
(3)```:符号内的R代码块
其实在创建Rmd文档时,R就已经按照这三大内容配置好了模板文档,只需在此基础上按照个人需求对这三个结构进行参数设置和代码修改即可。创建新的Rmd文档时的模块如图3所示。
图3 Rmd的三大结构
可自由编辑的text文本这里不再叙述,R代码块会在后面进行详细阐述,这里先来看一下YAML参数。YAML(Yet Another Multicolumn Layout)本意为另一种标记语言,在Rmd里面一般用于开头的一些参数值指定,通常用来指定文档的标题、作者信息、写作时间、文档输出方式以及其他一些信息。YAML参数以上下两个“---”符号来划定该结构,在上述的iris例子中,其YAML参数设置如图4所示。
图4 YAML参数设置
值得补充的是,在指定输出文档下继续设置toc参数为yes可对全文档添加目录。设置效果如图5所示。
图5 YAML参数效果
3. R Markdown基本语法
R Markdown作为R和Markdown的结合产物,完全接受了Markdown的基本语法,Markdown通过一款叫作pandoc的标记语言转化工具将我们设定的各种语法格式转化为文档中想要实现的效果。Markdown常见语法格式如表2所示。
表2 Markdown常见语法格式
关于Markdown另外一点需要提到的是,标题的分级设置。标题对于显示文档结构作用重大,一篇完整的Rmd文档需要各级标题来使得文档结构清晰明了起来,不要满篇全是大标题,也不要都是蝇头小字。那么在Rmd中标题的使用也是相当简单,只需要学会使用#号键(见图6)。
图6 分级标题的设置
几级标题就由几个“#”来表示,6级标题就有6个“#”,各级标题字体也是逐渐缩小的。在实际操作中可以自行根据需要选择级标题,通常选择“##二级标题”作为第一标题,毕竟大家都是挺在乎标题字体大小的。在上面的例子中简单展示一下标题效果如图7所示。
图7 Rmd的分级标题
4. 插入代码块
作为Rmd三大结构中最重要的一个组成部分,代码块在报告中扮演着重要的角色。它可以清晰地展示你做数据分析的思路过程,全部的代码都会被公开呈现给大家看到,那么在Rmd中插入R代码有哪些需要注意的呢?
除了手动输入“```”符号插入代码之外,最方便的插入代码的方法莫过于通过菜单栏的insert来执行插入代码的功能了,如图8所示。
图8 Insert插入R代码块
插入之后代码块如图9所示。
图9 插入代码块界面
就像在R脚本中一样,大家可以愉快地在里面写代码了。
由图8可以看出,除了主要的R代码之外,Rmd对于Python,SQL等也是支持的。点击之后会在Rmd中自动生成代码块,这样就可以在代码块中编写代码。可以在代码块中直接编写程序,也可以将事先在R脚本中编辑好的代码复制到代码块中去,然后点击代码块最右上角的运行按钮即可运行代码块。为了满足不同的代码需要,Rmd代码块还提供了多种个性化的设置。点击代码块右上角第一个齿轮按钮即可对代码块进行各种设置。打开后这个设置如图10所示。
图10 代码块设置
比如,现在给读者出个R语言小练习,要求读者最后的代码做出的结果要跟给的示例一样。这时就可以通过如图10所示的齿轮按钮进行仅显示代码运行结果的设置(见图11)。
图11 仅显示结果不显示代码
当然,这里面还有很多设置选项,比如,R经常运行出来会出现一些warning,太难看,我们不想让它们出现在Rmd中,这里也是可以设置不显示warning。除此之外,还有一些其他的输出设置,大家可以自行去尝试。在进行代码块选择输出设置的时候,除了齿轮按钮之外,还可以在代码块里手动输入命令参数进行设置(见图12)。
图12 手动进行代码设置
在完成自定义的代码块设置之后,就可以对单个代码块进行运行测试啦,没有报错的话,代码块运行会出现一个包含代码运行结果的R Console,如果代码中有绘图命令的话,还会出现一个单独的绘图框结果。比如,这里用iris数据集中的花瓣长度与鸢尾花类型作了一个简单的箱线图(见图13)。
图13 代码块运行效果
5. Rmd的输出
以上全部工作完成之后,就可以将Rmd文档的结果输出为其他形式的报告展示给别人看了 。为了生成想要的Rmd结果,需要对创建的文件对象执行render命令。如果代码块不报错的话,在RStudio右侧的viewer一栏会显示运行结果。Rmd在这其中生成最后输出结果的过程如图14所示。
图14 Rmd输出过程
首先R Markdown会将Rmd文件转化为一个名为knitr的文档, knitr可以理解为一个由纯文本和代码交织在一起的文档,然后再将这个文档转化为一个新的Markdown文件(.md),最后由pandoc转化为任意指定的文档格式。pandoc是一种标记语言转换工具,可以实现不同标记语言之间的转换。就这样,我们最终的数据分析报告得以呈现在大家面前。
再稍微高级一点,一般不使用render命令,而是通过一个叫knitr的小按钮将Rmd生成想要的格式,比如,HTML、PDF以及word等。knitr也就是上文提到的文本和代码交织文档,这里可以将其理解为编织文档。正常的Rmd输出效果如图15所示,这里以HTML为默认输出。
图15 Rmd的HTML输出
除了这些常见格式文档的输出之外,Rmd能做的事远比想象的要多,比如图16所示的各种输出形式。
图16 Rmd的其他输出形式
图17是基于shiny做出来的Rmd交互式文档展示,这个实际效果就很酷炫了,大家有兴趣也可以去尝试一下。
图17 Rmd交互式文档
关于R Markdown的基本知识,已经基本讲完了,这些内容基本上包括了R Markdown的方方面面,足够大家参考做出一份自己的Rmd报告。
到此为止,就把R语言的代码规范和R Markdown的基本知识介绍完了。代码规范方面,一定要在日常的R语言学习过程就养成好的习惯;Rmd方面,一定要多去探索和尝试,相信一定可以做出比本文所展示的更漂亮的Rmd文档。
请扫描以下二维码/点击链接购买
《R语言:从数据思维到数据实战》
https://detail.tmall.com/item.htm?spm=a220z.1000880.0.0.0A6pvS&id=581845865737
点击"阅读原文"下载数据、代码!