R语言(The R Programming Language)是一个用于统计计算和统计制图的优秀工具,[2]具有开源免费、源包众多、面向应用、持续迭代等优点,[7]被广泛应用于数据分析和可视化。[2][8]R语言的核心是一种解释型计算机语言,其允许分支和循环,以及使用函数的模块化编程,并可以与 C、C++、Java、Python 等语言集成,以提高效率。[9]
1992年,新西兰奥克兰大学统计系的罗斯·伊哈卡(Ross Ihaka)和罗伯特·杰特曼(Robert Gentleman)为了方便给学生教授统计学,基于S语言开发了R语言。[10][11]1995年6月,R通过 GPL 协议正式成为开源软件,[1]这一行为使得其所有源代码公开透明,并进一步拓展了其应用范围。[11]1997年4月23日,CRAN 正式上线,[12]其托管的第三方R包为跨领域复杂问题的解决提供了强大的软件支撑。[13]2005年,哈德利·威克汉姆(Hadley Wickham)博士推出了 ggplot2 包,进一步拓展了R的画图功能。[14]截至2024年7月,CRAN上的R包数量增至21085个,[15]这为程序员实现更高效、简洁的代码开发提供了有力的支持。[16]
R语言自加入到开源计划 GNU 项目后,便迅速发展,其软件包开发环境、社区和各类网站迅速增加,应用范围不断扩展。[11]强大的数据分析功能和整合能力使R语言可以独立完成数据科学工作中的大部分任务;[17]开源的统计和绘图系统使R语言被广泛地应用到生命科学领域的各个分支学科,使得数据分析过程变得简单易行。[18]随着R数据库的不断壮大和更新以及人们对于R语言认识的深入,R语言的普及范围和应用越来越广泛。[18]在 TIOBE 2024年4月对编程语言人气的排名中,R排名第20。[19]
来源与诞生
R语言是从S语言发展而来的一种计算机语言,[11]可以认为是S语言的一种“方言”,同时也吸收了很多 Scheme语言的特性,如“词法作用域”[1]。
1976年,S语言作为第一款统计分析和绘图语言首次面世,其聚集了各种统计和绘图函数,对于统计及数据可视化方面具有里程碑意义。第一版S语言运行于 Honeywell CCOS 操作系统,为大量的数据分析提供了一种工具,称为S Version 1。[11]第二版和第三版的S语言分别增加了支持 Unix 系统和基于面向对象的功能。[1][11]其中,第三版的S语言于1988年面世,且与今天的S语言和R语言差别不大。[1][11]
1992年,新西兰奥克兰大学的统计学教授罗斯·伊哈卡(Ross Ihaka)[注1]和罗伯特·杰特曼(Robert Gentleman)[注2],为了方便给学生教授统计学,以S语言为基础开始设计开发R语言。[22]


开源化与早期发展
1993年8月,Ross Ihaka 和 Robert Gentleman 在数据平台 StatLib 和邮件列表中发布了R的早期版本,吸引了一些人与他们合作,并建立了一个关于R语言的邮件系统,这是R语言的首次亮相。[23]1995年6月,R在 GPL 协议下作为开源软件正式发布,[1]该举动使得R语言的所有源代码对于所有人都是透明的,对今后R语言的发展至关重要。[11]同年,S语言经过了一次比较大的更新,该版本称为 S Version 4,其核心是“所有的东西都是对象”,并有了类-方法的模式,以及与 Java 等语言的接口。现在的R语言中面向对象机制用到的术语 S3 和 S4 就是来自于 S Version 4。[1][11]
自R语言作为开源软件发布后,两位创始人吸纳了许多其他开发者参与R的更新,[1]并分别于1996年和1997年创建了 Public Mailing List 和 R Core Group。[11]Public Mailing List 目前主要包括 R-announce、R-help、R-package-devel、R-devel 和 R-packages 五个板块,其使用者可以获取R语言的最新进展情况,如版本更新、R包发布等。[11]R Core Group 作为R语言的核心团队,负责R语言的维护和更新。除了最初的两位开发者,还有来自世界各地的R语言爱好者。[11]其中,奥克兰大学、斯坦福大学和赖斯大学的统计系兼职教授 Hadley Wickham,为了使数据科学更简洁、高效、有趣,编写了大量知名的R包,包括数据科学、数据导入等。另外,Hadley博士还编写了多本包括《R数据科学》(R for Data Science)和《R包开发》(R Packages)在内的关于R语言和数据科学的书籍,其作为Rstudio首席科学家,也因此被称为改变了R的人。[22]

R包与持续发展
1997年4月23日,R综合典藏网(Comprehensive R Archive Network;CRAN)正式上线。CRAN 除了收藏了R的可执行文件下载版、源代码和帮助文档,也收录了各种用户撰写的R软件包。[12]
进入21世纪后,R语言迅速发展,由于其强大的数学统计分析功能、开源性和丰富的算法包,在大数据时代得到越来越广泛的应用。[24]2005年,Hadley Wickham 推出了ggplot2 包,其作为R语言的一个数据可视化绘图包,进一步拓展了R的画图功能。[14]2012到2020年,R语言及其全球社区发展迅速,CRAN上托管的第三方R包的平均复合增速约为43%,R包不仅为跨领域复杂问题的解决提供了强大的软件支撑,也加快了前沿算法的应用落地。[13]2016年,Rstudio公司推出了tidyverse包,[22]为R语言提供了一个简洁、完整的数据科学工作流程所需的工具。[25]2022年,R4.1.2发布,CRAN上的R包数量增至18985。[22]截至2024年7月,在R的官方网站中公开发布的可用R包达到了21085个。[15]随着R版本的逐渐成熟和稳定,R在行业里的应用得到了飞速的发展,逐渐成为主流的数据科学工具和数据分析软件之一。[1]
设计原则
R语言是20世纪90年代初由统计学家为统计计算和图形绘制而创造的,其设计初衷之一就是要让非计算机专业的人也能用计算机语言完成统计计算和数据分析工作。[2]与其他编程语言相比,R语言的主要优势在于其为数据分析提供的专用功能和丰富的包生态系统。其语法结构设计使得学生和研究者能够轻松地进行数据探索和可视化。R语言中许多高度专业化的统计方法已经被封装成了包,CRAN 仓库里有上万个可用包供用户下载和使用,使其具有强大的拓展性,可以帮助研究者更高效地处理数据以及更便捷地创建可视化图形。[26]
主要特点
免费开源:商业数据分析软件如 SAS、SPSS 花费不菲。而R作为一种 GNU 项目,开放了全部源代码,使得用户可以免费使用和修改。[6]开源意味着用户可以通过源代码学习算法思想,而且可以自行开发R包。[27]可扩展性:R语言拥有强大的功能包,使得R语言的可扩展性特别强大,从而被应用到各行各业。[27]平台无关性:R语言可在多种操作系统下运行,如 Windows、macOS、各种版本的 Linux 和 UNIX 等。用户甚至可以在浏览器中运行R语言。[6]强大的绘图功能:R语言的绘图能力远远强大于别的统计软件[27],其提供了很多便于绘图的程序包,如 lattice 包、ggplot2 包等,大大提升了数据可视化程度,便于分析解释数据。[8]编程简单:R语言作为一种解释性的高级语言,程序的编写非常简洁,仅仅需要了解一些函数的参数和用法;而且R能够即时解释输入的程序或命令。[6]整合能力强:R语言可以通过相应接口连接各类数据库获取数据,如 Oracle、DB2、MySQL 等;可以通过各种接口和包与其他语言集成;提供了 API 接口,使得很多统计软件可调用R函数,如 SAS、SPSS、Statistica 等;还可与 web整合部署,构成网页应用。[6]丰富的GUI工具:R语言有各式各样的 GUI(Graphical User Interface,图形用户界面)工具,通过菜单和对话框提供了与R语言同等的功能。[28]
主要功能
数据存储处理:R语言提供了强大的数据存储和处理系统,可以完成数据的初步存储与处理。[29]数组运算:R语言提供了数组运算工具,其向量、矩阵运算功能尤其强大。[29]统计分析:R语言有完整连贯的统计分析工具,可以使用绝大多数经典以及最新的统计方法。[29]统计制图:R语言有优秀的统计制图功能,且输出的图形可以直接保存为 JPG 等图片格式或 PDF 格式,其中 PDF 格式可以保存为矢量图。[29]可编程性:R语言是一个简便且强大的编程语言,可操纵数据的输入和输出;可实现分支、循环结构;用户可自定义功能。[29]
常量和变量
在程序中,数据按其表现形式,可以分为常量和变量两类。[30]
常量:在R语言中,常量是指直接写在程序中的值,包括数值、字符串等。例如,123、123.45、1.23E2为数值型常量;"Li Ming""李明"为字符型常量;TRUE和FALSE为逻辑型常量,分别表示真值和假值。[31]
变量:在R语言中,变量是用来保存输入的值或者计算得到的值,包括标量、向量、矩阵、数据框、函数等数据类型。R语言中的变量名要求以字母、数字、下划线和句点组成,且第一个字符不能取为数字。变量名是区分大小写的,例如,y_1和Y_1是两个不同的变量名。R语言用“<-”或“=”对变量进行赋值,代码示例如下:[31]
x5 <- 6.25 x6 = sqrt(x5)
存储角度划分
由于不同类型数据在计算机中所需的存储字节不同,可将R数据对象划分为数值型(Numerie)、字符型(Character)、逻辑型(Logical)三种存储类型。[32]
| 类型 | 定义 | 存储空间 | 具体形式 |
|---|---|---|---|
| 数值型(Numerie) | 是计算机存储诸如家庭人口数、身高等数字形式数据的类型总称,可进一步细分为整数型和实数型。整数型是整数的组织形式;实数型用来组织包含小数位的数值型数据 | 整数型根据整数位数的长短,通常需要2字节或4字节的存储空间;实数型根据实数取值范围的大小和小数位精度的高低,通常需要4字节或8字节存储 | 如123.5,1.235E2,1.235E-2 |
| 字符型(Character)[33] | 是计算机存储诸如姓名、贯等字符形式数据的类型 | 字符串的长度决定了存储所需占用的字节数 | 如"ZhangSan","Beijing" |
| 逻辑型(Logical) | 是计算机存储诸如是否已婚、是否通过某个考试等是非判断形式数据的类型 | 逻辑型数据只需1字节存储 | TRUE和FALSE |
结构角度划分
向量
向量是R数据组织的基本单位,用于组织多个数据,是多个具有相同存储类型的数据的集合[注3]。[34]下表为R语言中向量的常用函数。[35]
| 分类 | 函数 | 作用 |
|---|---|---|
| 排序函数 | sort()函数 | 返回排序后的向量 |
| order()函数 | 返回排序后的向量索引 | |
| 去重函数 | duplicated()函数 | 用于判断元素是否重复 |
| unique()函数 | 用于直接删除重复值 | |
| 集合运算 | intersect()函数 | 用于求交集 |
| union()函数 | 用于求并集 | |
| setdiff()函数 | 用于求差集 | |
| 字符串处理函数 | paste()函数 | 用于连接字符或字符串 |
向量运算规则:短向量循环使用,如果长向量的长度不是短向量长度的整数倍则可能给出警告,但多数函数不会中断运行且仍会给出结果。[35]向量下标和子集:向量是有顺序的系列值,其顺序由从1开始递增的整数编号表示,这就是向量的索引,即下标。一个向量的下标也是一个向量,可以用其下标来提取向量元素,提取向量元素实际上就是取向量的子集。[36]因子:因子向量是一类特殊的字符向量,区别于一般字符向量,其具有一个标签属性(levels),因此因子向量可以视为一个由标签组成的字符向量。[37]R语言中用因子代表数据中的分类变量,如性别、省份、职业。有序因子代表有序量度,如打分结果,疾病严重程度等。[38]可以使用 gl()函数构建一个因子向量,也可以利用factor()函数将一般字符向量转为因子向量。[37]
矩阵和数组
在R语言中,矩阵和数组可以视为向量的一种特殊表现形式,其实质是将一个向量中的元素按指定格式进行排列。[39]
矩阵:用于组织多个具有相同存储类型的变量,其列称为变量,行称为观测。[34]矩阵在形式上是一个行列表,下表为R语言中矩阵的常用函数和运算符。[39]
| 分类 | 名称 | 作用 |
|---|---|---|
| 矩阵构建 | matrix()函数 | 常用的矩阵构建函数 |
| diag()函数 | 用于构建对角矩阵 | |
| upper_tri()函数、lower_tri()函数 | 用于构建三角矩阵;分别用于将矩阵的上三角或下三角元素置为0 | |
| 行列命名 | colnames()函数 | 用于对矩阵各列的名称进行查看或修改 |
| rownames()函数 | 用于对矩阵各行的名称进行查看或修改 | |
| 矩阵运算 | t()函数 | 用于矩阵的转置,进行行列变换 |
| cbind()函数、rbind()函数 | 用于两个行数或列数相同的矩阵的合并 | |
| apply()函数 | 用于对矩阵进行逐行或逐列运算 | |
| det()函数 | 将一个数值矩阵视为行列式,进行求值 | |
| 运算符“%*%” | 用于矩阵乘法运算 | |
| 运算符“%o%”、outer()函数 | 用于外积运算 | |
| eigen()函数 | 用于求解矩阵的特征值和特征向量 | |
| scale()函数 | 用于对矩阵进行标准化 | |
| cov()函数、cor()函数 | 用于计算协方差矩阵和相关矩阵 |
数组:同一类型数据的集合。[34]在R语言中,数组是二维矩阵向更高维度扩展的形式,可以使用函数array()进行构建。大于二维的数组可以利用apply()函数对指定维度进行循环运算。[40]
数据框
在R语言中,数据框用于组织多个存储类型不尽相同的变量,其列称为变量,行称为观测。[34]数据框在形式上是行列表的形式,其要求同一列数据的类型必须一样,不属于R语言的基础结构。一个数据框可以视为由若干等长向量按列合并构成的集合,每一个向量是数据框中的一个子集。[41]
| 分类 | 名称 | 作用 |
|---|---|---|
| 数据框构建 | data.frame()函数 | 用于构建数据框 |
| str()函数 | 用于查看数据框的结构摘要 | |
| length()函数、names()函数 | 分别用于查看数据框中子集的数目、名称 | |
| 元素选取 | 符号“$” | 用于选取数据框相应子集 |
| subset()函数 | 用于数据框的条件选取 | |
| 数据框的运算 | as.data.frame()函数 | 可将矩阵转换为数据框 |
| rbind()函数、cbind()函数、merge()函数 | 分别用于将列数相同、行数相同或有共同字段的矩阵进行合并 | |
| colSums()函数、rowSums()函数、colMeans()函数、rowMeans()函数 | 用于对全部有数值组成的数据框,进行逐行或逐列计算 | |
| table()函数、addmargins()函数 | 分别用于生成列联表、对表格加上周边合计 | |
| aggregate()函数 | 用于数据框分组计算 | |
| order()函数 | 用于对数据框进行多分类的排序 |
列表
多个向量、矩阵、数组、数据框的集合即列表,多用于相关分析结果的“打包”集成[注4]。[34]
工作空间和变量赋值
工作空间:R语言把在命令行定义的变量都保存到工作空间中,在退出R时可以选择是否保存工作空间,在命令行定义的变量称为“全局变量”。利用ls()命令可以查看工作空间中的内容,利用rm()函数可以删除工作空间中的变量。随着多次在命令行使用R,工作空间的变量会越来越多,重名的可能性也越来越大。由于自定义函数中定义的变量都是临时的,不会保存到工作空间中,所以为避免工作空间杂乱,可以将所有的运算都写到自定义函数中。[43]
变量赋值:变量赋值本质上是把一个存储的对象与一个变量名“绑定”(bind)在一起。[43]在R语言中,变量名要求由字母、数字、下划线和小数点组成,[31]开头不能是数字、下划线、小数点,中间不能使用空格、减号、井号等特殊符号,不能与if、NA等保留字相同。有时为了与其它软件系统兼容,需要使用不符合规则的变量名,可以将变量名两边用反向单撇号(`)保护,例如,`max score` <- 100。[43]
类型转换
| 数据类型 | 辨别函数 | 转换函数 |
|---|---|---|
| numeric | is.numeric( ) | as.numeric( ) |
| integer | is.integer( ) | as.integer( ) |
| character | is.character( ) | as.character( ) |
| logical | is.logical( ) | as.logical( ) |
| complex | is.complex( ) | as.complex( ) |
| NA | is.na( ) | as.na( ) |
is函数:通过is函数判断数据对象的存储类型,基本书写格式为:is.存储类型名(数据对象名)。[45]
as函数:可利用as函数将数据对象的存储类型转换为指定的类型,基本书写格式为:as.存储类型名(数据对象名)。[45]
运算符
| 分类 | 运算符号 |
|---|---|
| 算术运算符 | (加)、(减)、(乘)、(除)、(求余)、(求模)、(求幂) |
| 关系运算符 | (大于)、(大于等于)、(小于)、(小于等于)、(等于等于)、(不等于) |
| 逻辑运算 | (逻辑与,向量运算)、(逻辑或,向量运算)、(逻辑非)、(逻辑与,标量运算)、 (逻辑或,标量运算) |
表达式
R语言是一种表达式语言,其任何一个语句都可以看成是一个表达式。表达式之间以分号分隔或用换行分隔,若干个表达式可以放在一起组成一个复合表达式,组合用大括号{}表示,[47]作为一个表达式使用。复合表达式的值为最后一个表达式的值,示例如下:[48]
# 复合表达式语法结构 { 表达式1 表达式2 ... 表达式n }
# 代码示例 { x<-15 # 对x进行赋值 x<-25 x # 输出x的值,以最后一个表达式为最终结果 }
分支结构
分支结构根据一定条件选择执行不同的语句,[47]包含 if...else 语句组和 switch 语句两种结构。
if...else 语句组
R语言中分支结构控制语句中最基本的语句组就是if...else语句组。这组语句包含if语句、if...else 语句和 if…else if…else 语句。[49]if 语句用来检查逻辑运算、逻辑函数、逻辑变量值等逻辑表达式的真假,若为真则执行 if 和 else 之间的执行语句,否则,转去执行另一分支。[47]示例如下:
if 语句:单一 if 语句一般用在程序中只有一个分支的情况下,语法结构和示例如下:[49]
# 语法结构 if(logical 表达式){ 程序体 }
其中 logical 表达式(其他语言称为Boolean表达式)如果是真,则运行大括号中的程序体;如果是假,则跳过 if 语句继续运行下面的程序。[49]
# 代码示例 # 计算水果总价,要求用一个向量来存储水果单价,用一个数值存储水果斤数 # 如果水果斤数大于5,则水果总价下调10% if(y>5){ fruit.pro<-fruit.pro*0.9 }
if...else 语句:if…else 语句的语法结构和if语句的语法结构的区别只在于,如果 if 的 logical 表达式的判定是假,则运行 else 中的程序体,logical 表达式如果是真,则运行首个大括号中的程序体。语法结构和示例如下:[49]
# 语法结构 if(logical 表达式){ 程序体 }else{ 程序体 }
# 代码示例 # 计算水果总价,要求用一个向量来存储水果单价,用一个数值存储水果斤数 # 如果水果斤数大于5,则水果总价下调10%;如果水果斤数不大于5,则水果总价下调1元 if(y>5){ fruit.pro<-fruit.pro*0.9 } else{ fruit.pro<-fruit.pro-1 }
if…else if…else 语句:对于有多个分支的函数,R语言可以使用 if…else if…else 语句,这里 else if 的个数需要通过程序的分支个数来确定。语法结构和示例如下:[49]
# 语法结构 if(logical 表达式){ 程序体 }else if(logical 表达式){ 程序体 }else{ 程序体 }
# 代码示例 # 计算水果总价,要求用一个向量来存储水果单价,用一个数值存储水果斤数,最终返回所有水果总价的总和 # 如果水果斤数大于10,则水果总价下调15%;大于5,则水果总价下调10%;不大于5,则水果总价下调1元 if(y>10){ fruit.pro<-fruit.pro*0.85 } else if(y>5){ fruit.pro<-fruit.pro*0.9 }else{ fruit.pro<-fruit.pro-1 }
switch 语句
在编程中一个常见的问题就是检测一个对象值是否符合某一个条件,如果不符合,再用另一个条件来检测,以此类推。这种多重判断的问题,可借助 switch 语句。语法结构和示例如下:[50]
# 语法结构 switch(表达式,实例1,实例2.…)
# 代码示例 # 计算水果总价,要求用一个向量来存储水果单价,用一个数值存储水果斤数,最终返回所有水果总价的总和 # 如果水果斤数大于10,则水果总价下调15%;如果水果斤数小于或等于10且大于5,则水果总价下调10% # switch应用参数为整数 switch{num, fruit.pro<-x* Y, fruit.pro<-x*y*0.85, fruit.pro<-x* y*0.9} }
用逻辑下标代替分支结构
R语言是向量化语言,应尽可能少用标量运算,可以用逻辑下标代替分支结构。 例如,x为一个向量,要定义y与x等长,且y的每一个元素当且仅当x的对应元素为正数时等于1,否则等于零。其代码示例如下:[51]
# 用分支结构表达 if(x>0) y<-1 else y<-0 # 用逻辑下标代替分支结构 y<-numeric(length(x)) y[x>0]<-1 y
循环结构
循环结构重复执行一组语句,它是计算机解决问题的主要手段。[47]R语言是一种擅长处理向量、列表、数据框等复杂数据结构的语言,这些复杂数据结构多数都需要对其中的元素进行迭代。R提供了多种用于数据迭代的函数,但是在实际项目中,普通的天量数据循环也是不可避免的,所以R也提供了for或while之类的循环方式。[52]
for 循环
for 循环语句会依照计数器的值来决定运算指令的循环次数,for 循环内不能对循环变量重新赋值,可以按需要嵌套,它的循环判断条件就是对循环次数的判断,也就是说,循环次数是预先设定好的。[47]语法结构和示例如下:[52]
# 语法结构 for(循环变量in循环区间){ 循环体 }
# 代码示例 # 建立一个向量,遍历向量中所有元素,并打印出本次遍历的值是多少 # for循环 for(i in n){ y<-sprintf("本次遍历的值是:%s",i) print(y) }
while 循环
while 循环语句的判断控制可以是逻辑判断语句,只要“循环条件”里的所有元素为真,就执行 while 和 end 语句之间的命令串,因此它的循环次数可以是一个不定数,这赋予了它比 for 循环更广泛的用途。[47]语法结构和示例如下:[53]
# 语法结构 while(logical 表达式){ 循环体 }
# 代码示例 # 建立一个向量,遍历向量中所有元素,如果向量没有到结尾,就判断一下本次遍历的值是否大于15 # 如果大于15,打印“本次循环值大于15,循环结束”;如果不大于15,打印这个值并遍历打印出其位于向量的第几位 # while循环,break应用 i<-1 while(i<length(n)+1){ if(n[i]>15){ print("本次循环值大于15,循环结束") break } y<-sprintf("本次遍历值位于向量第%s位,遍历的值是:%s",i,n[i]) print(y) i<-i+1 }
repeat 循环
repeat 循环在循环体内部进行条件判断,如果满足条件则使用 break 退出循环。repeat 循环使用命令 next,跳过循环中 next 后面的代码,重新开始一次循环。[54]语法结构[55]和示例[54]如下:
repeat{ ... if(循环退出条件) break if(循环跳出条件) next }
# 代码示例 x<-0 i<-0 repeat{ i<-i+1 if(i>100) break if(i%%2==0) next x<-x+i }
R中判断条件
if 语句和 while 语句中用到判断条件,其必须是标量值,且为 TRUE 或 FALSE,不能是 NA 或零长度。[56]
管道控制
R语言从4.1.0版本开始提供了运算符“|>”实现对同一个变量进行多个步骤的操作,例如,先筛选部分有用的变量,再定义若干新变量,再排序。示例如下:[57]
# 变量x先用函数f(x)进行变换,再用函数g(x)进行变换 g(f(x)) # 一般表示 x |> f() |> g() # 用|>运算符表示
使用“|>”的表达更符合处理发生的次序,且插入一个处理步骤也很容易。[57]
管道操作符“%>%”:R语言中的magrittr包提供了管道操作符“%>%”[57]用于简化代码和提高代码的可读性。[58]“%>%”的坐左边是数据,右边是函数,其思想为,函数是构建块,并允许用户将函数组合在一起产生所需的结果。管道操作符本质是取左边的数据,并将它作为右边函数的第一个参数,适用于有多个函数嵌套的情况。等价代码示例如下:[58]
f(x)=x %>% f() # 将x的数据作为f函数的第一个参数 a(b(c(d(x))))=x %>% d() %>% c() %>% b() %>% a() # 用函数链的结果替换原来的x
函数
R软件中有许多R函数存储为特殊的内部形式,并可以被进一步的调用,这样在使用时可以使语言更有力、更方便。此外,R允许用户自己创建模型的目标函数,学习写自己的程序是学习使用R语言的主要方法之一。事实上,R系统提供的绝大多数函数,如mean(),var(),postscript()等,是系统编写人员写在R语言中的函数,与用户自己创建的函数本质上没有多大差别。[59]
定义和结构
定义:用户可以根据自己的需求编写自定义函数,[60]定义一个函数的基本语法如下:[61]
函数名<-function(参数1,参数2,…,参数m){ R表达式1 R表达式2 ... R表达式n }
结构:函数的“结构”中包括函数名、赋值号、function、函数参数和函数体五部分。[61]
| 名称 | 说明 |
|---|---|
| 函数名 | 函数名和参数名的命名规则需符合R变量名的命名规则 |
| function | 是R函数定义的“关键字”,表示通过赋值语句产生的是个函数而不是普通变量 |
| 函数参数 | function后圆括号内为函数的参数,参数的数量可根据需要任意定制 |
| 函数体 | 函数参数后花括号内的语句称为“函数体”,如果只有一个语句,花括号可以省略 |
输入/输出函数
R语言基本的输入输出功能主要包括键盘录入和屏幕输出、文本格式的输入输出、自有二进制格式的输入输出三种形式。[62]
| 类型 | 名称 | 作用 | |
|---|---|---|---|
| 屏幕输出 | print() | 是一个类函数,一次对一个变量进行输出;其会根据变量的类别,调用合适的函数,以相应的格式进行输出;但在输出时不对转义字符进行变换 | |
| cat() | 功能较为简单,其只能对向量进行输出;在输出时,其将向量中的元素转换为字符串并逐个输出 | ||
| 文本格式的输入\输出 | 矩阵和数据框 | write.csv() | 用于将矩阵和数据框输出为逗号分隔(CSV)文件 |
| read.csv() | 用于对指定文件进行读取,不指定路径时,默认在工作目录下查找该文件 | ||
| 向量 | scan() | 可以利用参数file直接读取文件中的向量;通常用于从键盘输入或读取文本文件 | |
| 二进制格式的输入\输出 | save() | 用于将数据保存为二进制(RData)格式,可以保存任意变量类型的数据 | |
| load() | 用于读取RData文件,保存数据时会保存变量名,因此读取数据时需避免和当前工作环境下的变量重名 | ||
字符串的处理
| 类型 | 名称 | 语法结构 | 参数说明 |
|---|---|---|---|
| 字符串分割 | strsplit() | strsplit(x,split,fixed=FALSE,perl=FALSE,useBytes=FALSE) | strsplit()函数中的必要参数是x和split,其中x表示需要函数来处理的字符串格式的向量;split表示拆分位置的字符串向量;参数fixed=TRUE表示用普通文本匹配或者是正则表达式精确匹配;参数perI=TRUE时,表示使用perl语言里面的正则表达式;参数useBytes表示是否逐字节进行匹配 |
| 字符串拼接 | paste() | paste(..., sep=" ",collapse=NULL) | 参数sep用于设置两个字符串间的拼接内容,参数collapse用于将字符串向量连接成一个字符串 |
| 字符串长度计算 | nchar() | nchar(x,type="chars" ,keepNA=TRUE) | 参数x是目标字符串,参数type用于判断长度的类型,参数keepNA用于设置NA值是否参与计算 |
| 字符串截取 | substr() | substr(x,start,stop) | 必须设置参数start和stop |
| substring() | substring(text,first,last=1000000L) | 可以只设置参数first,若不设置参数last,则last默认直到字符串末尾L,指字符串的最大长度 | |
| 字符串替换 | chartr() | chartr(old,new,x) | 参数old用于设定对目标字符串中的哪些字符做替换,参数new用于设置替换的字符串,参数x是替换的目标字符串 |
| 字符串匹配 | grep() | grep(pattern,x,ignore,case=FALSE,perl=FALSE,value=FALSE,fixed=FALSE.useBytes=FALSE,invert=FALSE) | 参数pattern和参数x是必要参数,参数pattern是要匹配的内容,参数x是匹配的目标数据对象;参数value决定返回的是匹配的元素还是整个向量,invert用于反转匹配结果。grep()函数返回的结果参考参数value的值;grepl()函数返回是否匹配到值 |
| grepl() | grepl( pattern, x, ignore, case = FALSE, perl = FALSE, fixed= FAlSE, useBytes=FALSE) | ||
| 字符串格式化输出 | sprintf() | sprintf(fmt,...) | 参数fmt存放的是要输出的格式化字符向量;参数...代表替换字符 |
统计函数
在R语言中可以进行随机变量概率密度、累积概率和分位数的运算,所用的函数名称有统一的格式:在相应的概率分布名称前加人字符d/p/q/r即可。在R语言中可以产生各种单变量伪随机数,方法是在相应的概率分布名称前加入字符r即可。 [65]
| 函数名 | 作用 |
|---|---|
| mean( r) | 均值 |
| median(z) | 中值 |
| sd(r) | 标准差 |
| var(r) | 方差 |
| mad(z) | 绝对中位差 |
| quantile(x,p) | 分位数 |
| scale(x.center=TRUE,scale=TRUE) | 为数据对象x按列进行中心化,或标准化 |
图形函数
R语言以其强大的图形功能而著名,这些图形函数用于绘制各种类型的图表,如散点图、直方图、箱线图等,帮助用户直观地展示和分析数据。同时,R提供一系列图形参数,通过对这些参数的设置或修改以定制R的图形绘制环境。[67]
| 类型 | 作用 |
|---|---|
| 高级绘图函数(high-level plottingfunctions) | 用于迅速创建一个新的图形 |
| 低级绘图函数(low-level plotting functions) | 用于在现有的图形上添加元素如点、线和标记等 |
| 交互式图形函数(Interactive fiunction) | 允许通过点击设备,以添加信息或提取信息 |
R包
R包本质上来说其实就是事先编辑好的并实现了一系列功能的代码库,其包含了大量的函数,可以看作是R的功能扩展。截至2024年7月,在R的官方网站中公开发布的可用R包达到了21085个,[15]有效地利用这些包可以减少程序员自己的编写量。[16]
OOP
OOP[注5]是一种理论,不同的计算机语言可能有不同的实现方法。当前的R语言存在S3、S4、RC和R6等多种OOP体系。S3简单方便但动态性和结构化不明显,OOP的很多概念和理论没有实现或实现不彻底;S4具有明显的结构化特征,比S3实现了更多的OOP概念和理论,是比较典型的OOP系统,但程序开发和使用复杂度提高了;RC和R6是较新的OOP实现,可完成很多S3和S4不可能实现的功能。[70][71]
S3
在R语言中,基于S3对象的面向对象编程,是一种基于泛型函数的实现方式。泛型函数是一种特殊的函数,根据传入对象的类型决定调用那个具体的方法。[72]这不同其他语言的面型对象编程,如Java、C++和C#,这些编程语言在消息传递中,由对象来决定使用哪个方法。S3由泛型函数来决定该调用哪个方法,比如 drawRect(canvas,"blue")。S3没有对类的正规定义,[71]被广泛应用于R的早期的开发包中。[72]
S4
S4对象系统是一种标准的R语言面向对象实现方式,S4对象有明确的类定义,参数定义,参数检查,继承关系,实例化等的面向对象系统的特征。[72]S4的工作机制相比S3更加正式,其有特定的函数来定义泛型和方法。S4还有多重派遣特性,即S4的泛型函数可以根据任意多个参数的类来选择多个方法,而不仅仅是根据一个参数的类。[71]
RC
引用类(Reference Classes,RC),又称为R5,在R语言的2.12版本被引入,是基于信息传递的面向对象系统。RC不同于原来的S3和S4独享系统,RC队形系统得的方法是在类中自定的,而不是泛型函数,[72]因此它的方法属于类,而不是函数。RC的对象和方法之间用.隔开,所以调用方法的形式如: canvas.drawRect("b1ue")。RC的对象可以直接修改,加大了程序推理的难度,但是却可以帮助解决一些S3、S4难以解决的问题。[71]
R6
R6是一个单独的R包。在R语言的面向对象系统中,R6类型与RC类型是比较相似的,但在使用R6类型开发R包的时候,不依赖于methods包,而用RC类开发R包时必须设置methods包的依赖。由于RC类型的面向对象系统设计并不彻底,所以才会有R6这样的包出现。[72]
作用域规则
R语言使用的是词法作用域(Lexical Scoping),也被称为静态作用域。在这种作用域中,变量的值在取用时,会检查函数定义时的文本环境,即捕捉函数定义时对该变量的绑定。这意味着词法变量的作用域是在编译时静态确定的,可以是一个函数或一段代码,在这段代码区域内变量可见,而在代码区域以外该变量则不可见或无法访问。[73]
扩展性与互操作性
拓展包:R 语言具有强大的扩展性。由于 R 语言的设计初衷是统计计算和数据分析,许多高度专业化的统计方法已经被封装成了包。[74]与其他软件的交互与集成:R程序与由Rcpp支持的C++程序之间需要传递数据, 就需要将R的数据类型经过转换后传递给C++函数,将C++函数的结果经过转换后传递给R。例:Rcpp提供了模板化的wrap() 函数把C++的函数返回值转换成R的SEXP数据类型;Rcpp提供了模板化的as()用来把SEXP类型转换成适当的C++类型。[75]
内存管理安全
在大数据时代,R语言还面临内存限制和单线程计算两大挑战。其中单线程问题是指在多核处理器上,R在执行某些操作时只能利用一个CPU内核,[76]这在R语言的2.14版本发布之后逐步解决,其增加了多个扩展包用来支持R在多线程方面的应用[77],如 parallel 包[76]。而对于R的内存管理,尽管推出了一些解决方案(如bigmemory包),仍然是困扰编程人员的一个大问题。升级硬件和改进算法是解决内存问题的永恒办法;调整内存分配上限、及时删除中间对象以及特别注意可变变量的内存管理可以解决内存不够的问题。同时,合理规划变量的增长,避免不必要的内存占用,也是解决内存问题的重要策略。[77]
异常处理
R 程序的异常情况严格来说有错误、警告和强行打断三种。R语言设置了 tryCatch 函数来捕获异常的情况并且进行针对性地处理。[78]
异常情况
错误信息:错误是最常见的异常,R程序在任何位置遇到错误后,都会立刻中断整个程序,向最上层的运行环境抛出错误。最直接的结果就是在控制台上显示错误的内容。示例如下:[78]
log("") ## 返回错误信息:Error in log(""):non-numeric argument to mathematical function
向 log函数中传入了一个字符型的向量,默认的错误提示只是告诉了用户对数值函数传入了非数值的参数。此外,R提供了stop这个函数可以中断程序的执行,并抛出一个自定义语句的错误。[78]
警告信息:除了引起程序中断的错误以外,对于一些轻微的错误,R不会中断整个程序,而是使用warning的方式来给出警告。示例如下:[78]
log(-1) ##给出警告信息:NaN
如果对log函数传入一个不合理的数值,并不会中断程序的运行,系统会返回一个特殊值NaN,同时抛出一个警告。如果要在自己的函数中自定义警告的话,可以使用warning函数,函数直接存下或者抛出警告信息,然后继续执行后续的代码。[78]
强制打断:除了错误和警告,R中还有一种常常被忽视的异常情况,就是强制打断。当一段程序在执行的时候如果非常占用系统资源,常常会有一段时间失去响应,使用Ctrl+C组合按键(或者按下Esc)可以中断程序,退出到控制台。[78]
tryCatch语句
在R中都可以使用tryCatch这个函数来捕获异常的情况并且有针对性地处理,其有助于增强程序的健壮性。在tryCatch函数中包含几个关键字,针对这些关键字编写不同的错误处理或者操作的函数可以实现异常处理。[78]
| 关键字 | 异常 |
|---|---|
| interrupt | 被用户强行中断后的操作 |
| error | 出现错误后的操作 |
| warning | 出现警告后的操作 |
| finally | 无论何种情况,在函数退出之前执行的操作 |
语言环境
R软件是一套由数据操作、计算和图形展示功能整合而成的套件,包括有效的数据存储和处理功能、一套完整的数组(特别是矩阵)计算操作符、拥有完整体系的数据分析工具。R软件的定位是一个完善统一的系统和简单有效的编程语言,而非其他数据分析软件那样作为一个专门、不灵活的附属工具。[79]
开发工具
| 名称 | 运行环境 | 简要说明 | 图标 |
|---|---|---|---|
| RStudio(R工作室) | Linux、Windows、macOS操作系统[80] | 专业的R语言IDE软件,具有内置的R控制台、代码编辑器、浏览器等;可以高亮显示代码、主动联想命令;提供了R 的图形设备、对象管理器、调试工具等高级功能[81] | ![]() [82] |
| Emacs+ESS | Linux、Windows、macOS操作系统[80] | Emacs是一个文本编辑工具,ESS是Emacs的一个“插件”,其定制Emacs的R语言编辑环境,实现代码加亮、补全和格式化等功能,并建立起Emacs和R程序间的通信[80] | ![]() [83] |
| Notepad++ | Windows操作系统[81] | 完全开源和免费;默认支持 R语言的高亮显示,对于中文编码和文本操作非常方便;容易加载第三方扩展包[81] | ![]() [84] |
| Tinn-R | Windows操作系统[85] | 一款免费的R编辑工具,使用颜色来显示匹配的括号、函数等,突出输入错误;执行程序时,可在编辑器内加亮文本,并将代码直接传送给R以执行[86] | ![]() [85] |
| RKWard | Ubuntu Linux、Windows操作系统[87] | 唯一的明确针对项目反应理论的R语言图形用户界面,且包含帕累托图;提供了大量的分析细节,特别是图表分析和分布分析;输出结果可以很容易地复制到微软 Office 文档[87] | ![]() [88] |
| Revolution R(现称为Microsoft R Open,MRO) | Windows、macOS、Ubuntu、CentOS/Red Hat Linux等[89] | 一个高效的环境,现有Revolution R的增强包括一个代码编辑器称为RPE,实现了语句着色突出显示;加入Code Snippets,实现代码补全功能,可自动插入clara聚类等代码[90] | ![]() [91] |
R语言资源和拓展
CRAN:CRAN即综合R存档网络,是R社区的主要包存储库。R包允许R社区使用包存储库中提供的一组丰富的包来扩展R提供的基本功能。CRAN是一个由世界各地的ftp和web服务器组成的网络,存储相同的、最新版本的R代码和文档。[12]
Qmd文件:Quarto(简称Qmd)是一种特殊的文件格式,文件中既有R程序,又有说明文字。通过R和RStudio软件,可以运行Qmd文件中的程序,并将说明文字、程序、程序的文字结果、图形结果统一地转换为一个研究报告。同时,在打开的Qmd源文件中,可以选择其中的某一段R程序单独运行,即Qmd文件也可以作为一种特殊的R源程序文件。[75]
相关应用
R语言的函数大部分以扩展包的形式存在,方便管理和扩展。由于代码的开源性,使得全世界优秀的程序员、统计学家和生物信息学家加入到 R 社区,为其编写了大量的R包来扩展其功能。这些R包涵盖了各行各业中数据分析的前沿方法,包括从统计计算到机器学习,从金融分析到生物信息,从社会网络分析到自然语言处理,从各种数据库语言接口到高性能计算模型等多种领域。[17]
数据科学
作为一套完整的数据处理、计算和绘图系统及操作环境,R语言有数据分析功能强大、整合能力强等优点,可以独立完成数据科学工作中的几乎所有任务,而且可以很好的配合其他工具进行数据交互。[17]
生命科学
R语言作为一个开源的统计和绘图系统,被广泛地应用到生命科学领域中的动物学、植物学、细胞学、生理学、生态学、神经科学等分支学科。例如,在生命科学领域常用的Bioconductor,是一个基于R语言的与生物信息相关的软件包,主要是以包的集成形式呈现,其提供了各种基因数据分析和注释工具和许多与DNA微阵列相关的数据包;在生物学和生态学方面广泛应用的vegan包,其包括一些常用的排序方法(PCA,CA,DCA,CCA,NMDS等),被用来做群落生态学分析。随着不断发展,R语言会渗透生命科学领域的各个分支学科,并使得原本复杂的数据分析过程变得简单易行。[18]
金融分析
在金融分析领域,利用R代码实际动手来计算,能更好地理解金融原理,并快速地搭建起计算原型,它提供了大量的金融分析函数,可用于金融分析的各个方面。其中包括了财务数据的获取和整理,例如,从Yahoo 网站获取上市公司的财务报表和历史报价,计算各类金融产品定价;对金融时间序列数据建模,如ARIMA 模型和GARCH模型;以及风险管理方面的定量风险模型和各类精算模型等。[92]
分子流行病学
R语言作为一种自由开源的编程语言,具有强大的数据处理和分析能力,适用于处理大规模和复杂的分子数据。其丰富的统计函数和数据包使得分子流行病学研究者可以进行高级统计建模和生物信息学分析,满足分子流行病学研究的需求。[93]
未来发展
跨平台和跨语言的集成:R语言的优势之一是能够与其他语言如Python、C++、Java等无缝集成。未来,R可能会进一步优化与其他流行语言和平台的集成,以满足多语言和多工具链开发的需求。[9]
深度学习框架整合:R语言需要进一步整合深度学习框架,以便更好地支持深度学习算法的开发和应用。随着计算机处理器速度越来越快、存储器容量越来越大以及数据表达的形式多样化,越来越多的事务使用深度学习进行实时数据分析。[94]
教育教学领域的应用:R语言的tm包和textmineR包提供了丰富的工具可用于完成教育统计的常规任务,但在处理性能密集型任务时可能显得不够高效,需要通过集成C语言、C++和 Fortran 来弥补这一不足。随着大数据和计算机技术的迅速发展,统计计算成为高等教育中不可或缺的一门课程。为了提高统计计算课程的教学质量和满足日益复杂的数据分析需求,选择合适的编程语言和工具显得尤为关键。[95]
生命科学领域的渗透:随着发展,R语言会渗透生命科学领域的各个分支学科,并使得原本复杂的数据分析过程变得简单易行。[96]互联网和生物信息学带来的海量数据分析和可视化的需求刺激了R的迅猛发展。随着下一代测序技术的高速发展,Bioconductor生物信息软件包的出现,开启了生物信息学的R语言时代。[97]
荣誉
2008年,新西兰皇家科学院向R语言创始人之一Ross Ihaka教授颁发皮克林勋章以纪念其对R语言的贡献。[20]同年,另一位创始人Robert Gentleman教授因其对R语言和Bioconductor的贡献获得本杰明·富兰克林奖。[21]2009年纽约时报发表了题为“Data Analysts Captivated by R'sPower”的社评,集中的讨论了R语言在数据分析领域的发展。[98][99]2010年,美国统计协会(American Statistical Association)将第一届“统计计算及图形奖”授予了R语言,用于表彰其在统计应用和统计研究广泛的影响。[99]
与其他编程语言相比较
| 名称 | R语言[100] | Python[100] | C++ | Java[101] |
|---|---|---|---|---|
| 执行方式 | 解释型 | 编译型 | 编译型 | 半解释型半编译型 |
| 设计原则 | R语言专为统计计算和图形展示而设计,[100]广泛应用于统计课程中,其设计初衷之一就是要让非计算机专业的人也能用计算机语言完成统计计算和数据分析工作[2] | Python 的设计原则是“优雅”、“明确”、“简单”,强调代码的可读性 | C++ 自始至终定义为一个静态类型系统,拒绝动态程序设计的理念[102] | Java 完全基于面向对象编程,具有跨平台性和动态性,其设计目标之一是适用于动态变化的环境 |
| 代码易读性 | R语言擅长于数据分析,提供了许多简洁的函数式命令,也允许个人编制函数式命令,但使用R语言需要些专业的统计学知识 | Python 语法更加通用,使用像 pandas 这样的库使得 Python 在数据操作上表现得十分简洁,易于学习和理解 | C++ 的语法非常复杂,提供了大量复杂的特性(如结构体、运算符重载、多重继承等),灵活但容易导致代码难以阅读和维护[101] | Java语法结构相对简单明了,代码风格一致,易于阅读和理解,面向对象编程的特点使得代码组织清晰 |
| 应用领域 | R语言更倾向于传统统计计算和研究及数据可视化 | Python 则更为灵活,在数据处理、机器学习和深度学习等领域更为出色 | C++ 是一种通用的编程语言,具有高效的运行效率,被广泛应用于嵌入式系统开发、游戏开发等接近系统底层且对运行效率要求高的领域[103] | Java 是开发企业级应用的首选,以及 Android 应用开发的主要语言,广泛应用于 于大数据处理和 Web 应用程序开发 |
与其他数据分析软件的特性对比
| 名称 | R语言 | SPSS | MATLAB |
|---|---|---|---|
| 语言特点[104][105] | 兼容性强,具有良好的可扩展性和可操作性,保留了程序设计语言的基础逻辑,容易入门 | 一种专用的统计软件,不需要进行语言编程,交互界面可以直接点击,有大量的统计分析算法,数据整理与统计分析具有易用性 | 矩阵计算等数学专用建模工具,有非常好的可移植性与可扩展性,侧重于数值计算和工程领域 |
| 图像处理功能[105] | 提供完善的绘图技术,具有图形数据可视化功能。能够绘制一些动态的图形,以及结合实际需求,自由灵活地进行复杂图形的组合绘图 | 有比较友好的界面,能够获得高质量的图形信息,可以在图像处理中使用编程语言 | 在实现数据可视化的同时,能够标注相应的图形,并完成图形打印。针对图形处理,可以实现顶层设计,并完成相应的图形计算与工程绘图 |
| 数据处理功能[105] | 能够从横向与纵向出发,自由进行数据变换,可以采用正则表达式,进行数据字符批量化操作 | 搭载有专门的数据编辑器,用户可以自主确定数据属性,但无法批量操作进行数据处理 | 有丰富的算法供用户选择,用户可以灵活选择相应的算法完成数据的处理 |
| 统计分析[105] | 有完整连贯的统计分析工具,可以使用绝大多数经典以及最新的统计方法。[29],同时具有丰富的扩展包资源,使数据分析更加简洁高效 | 本身包含着大量的统计分析算法,能够进行大规模的统计分析 | 有丰富的统计分析算法可供用户自由选择 |
参考资料 105
- 参考 1
- 参考 2
- The R Project for Statistical Computing — R:The R Project for Statistical Computing
- 参考 4
- The Comprehensive R Archive Network — r-project
- 参考 6
- 参考 7
- 参考 8
- 参考 9
- Academic unfazed by rock star status — NZ Herald
- 参考 11
- R Package Repositories — RStudio User Guide Release
- 参考 13
- 参考 14
- Available Packages — CRAN:Contributed Packages
- 参考 16
- 参考 17
- 参考 18
- TIOBE — TIOBE Index
- Our medals and awards — Royal Society of New Zealand
- Benjamin Franklin Award — Bioinformatics.org
- 参考 22
- 参考 23
- 参考 24
- 参考 25
- 参考 26
- 参考 27
- 参考 28
- 参考 29
- 参考 30
- 常量和变量 — R语言教程
- 参考 32
- 参考 33
- 参考 34
- 参考 35
- 参考 36
- 参考 37
- R因子类型 — R语言教程
- 参考 39
- 参考 40
- 参考 41
- 参考 42
- 工作空间和变量赋值 — R语言教程
- 参考 44
- 参考 45
- 参考 46
- 参考 47
- 表达式 — R语言教程
- 参考 49
- 参考 50
- 用逻辑下标代替分支结构 — R语言教程
- 参考 52
- 参考 53
- 参考 54
- while循环和repeat循环 — R语言教程
- R中判断条件 — R语言教程
- 管道控制 — R语言教程
- 参考 58
- 参考 59
- 参考 60
- 参考 61
- 参考 62
- 参考 63
- 参考 64
- 参考 65
- 参考 66
- 参考 67
- 参考 68
- 参考 69
- 参考 70
- 面向对象指南 — Advanced R in Chinese
- R语言面向对象编程
- R Language Definition — cran.r-project
- 参考 74
- R语言介绍 — R语言教程
- 参考 76
- 参考 77
- 参考 78
- 参考 79
- 参考 80
- 参考 81
- RSTUDIO IDE — posit
- GNU Emacs — GNU Project
- What is Notepad++ — Notepad++
- About Tinn-R — Tinn-R
- 参考 86
- 参考 87
- About RKWard — rkward
- Introducing Revolution R Open and Revolution R Plus — revolutionanalytics
- 参考 90
- Revolution Analytics — RevolutionAnalytics
- 参考 92
- 参考 93
- 参考 94
- 参考 95
- 参考 96
- 参考 97
- Data Analysts Captivated by R'sPower — The New York Times
- R You Ready?——大数据时代下优雅、卓越的统计分析及绘图环境 — Capital Of Statistics
- 参考 100
- 参考 101
- 参考 102
- 参考 103
- 参考 104
- 参考 105





