第5章 R 语言基 础 5.1 R 语言介绍 5.1 R语言的特点与资源 1. R语言是一种用于统计分析以及图形绘制的编程语言和操作环境。其前身是1976年美国贝尔实 验室开发的S语言。R语言在20世纪90年代由两位主要研发者RobertGentleman和RosIhaka正 式发布使用,以两位开发者名字的首字母命名。目前R语言由一个R核心开发团队进行升级和维护, 同时遍布世界各地的R语言使用者也一同参与到R语言的提升与改进中。从最初的统计计算语言到 如今覆盖几乎所有数据分析行业,R语言展现出其独特的数据分析和问题解决能力。与其他流行的统 计和制图软件相比,R语言有着许多独特的优势,例如: .R语言是免费开源的软件。如今,很多普遍使用的统计软件属于商业软件且价格不菲,同时,大 多数学术期刊对数据分析软件也有相应的版权要求。而R语言是一个完全免费并且开源的软 件,用户无须担心其版权问题。 .R语言是一个全面的统计分析平台,提供了各种各样的数据分析方式和技术。与此同时,数量 众多的第三方包也极大地丰富了R语言的统计分析功能。 .强大的绘图功能。R语言内置的基础绘图功能以及数量众多的高级绘图包为用户提供了强大 的数据可视化解决方案。 .支持目前所有主流的计算平台,包括Windows、Linux和MacOSX 。这意味着R语言可以运行 在绝大部分计算机上进行数据分析和处理 。 读者可以从CRAN官网(hs:carpoetog) tp//rn.-rjc.r上下载相应的R语言系统安装包进行安装。 国内的用户可以从中国地区镜像,如清华大学的镜像(mir.ua.snu.dc/CRAN/)下载相应 的安装包。 rostntighaeu.n 5.1.2 RStudio使用简介 RStudio是一款基于R语言的集成开发环境软件,是在个人计算机上使用R语言的首选。RStudio 可以在其官网(htps://sudicom)上根据自己的系统下载安装。要注意的是,在安装RStdo之前 rto.ui 需要先安装R语言,再通过RStudio来使用R语言。 如图5-1-1所示,RStudio包括4个工作区域,它们的大小可以自由调节。其中,左下角的区域称为 控制台,是输入命令以及R语言显示运行结果的区域,也是最主要的工作区域;左上角的区域用于编写 R语言的脚本文件(如.并能通过快捷键Crtr将当前或选中代码传输到控制台中 R语言文件), tl+Ene 运行;右上角的区域可以显示当前环境下的变量及其内容以及控制台命令的历史记录;右下角区域则主 要用于显示当前文件夹下的文件、R语言脚本绘制的图以及R语言的帮助文档等。 1 64 图5-1-1 RStudio工作界面 5. 2 R 语言的基本规则 首先介绍一些R语言最基本的知识,以便使读者对R语言的特点有一个直观的认识。 R语言是一个交互性很强的语言,用户输入命令后可以得到即时的反馈。R 语言从设计上十分便 于进行数据分析,例如,可以直接像计算器一样使用R语言进行数学计算: 1 + 2*3 / 4 ##[1]2.5 ( sin(3) ^ 2 +pi / log(2e-5) ) * exp(1.2) ##[1]-0.8978978 每当输入换行符(按Enter键),R语言就会尝试运行当前的命令并给出计算结果;而如果当前的命 令不完整,R语言会继续等待之后的命令来一起运行。如果输入的命令会产生结果,R语言会在接收命 令后输出计算结果;而如果输入的命令没有输出结果,那么R语言在成功执行后并不会给出任何反馈 信息。 1 * #不完整的命令,乘号后需要数字 ( #不完整的命令,缺少对应的括号 2 + 2 ) #完整的命令,给出计算结果 ##[1]4 Sys.sleep(1) #让R 语言暂停1s,该命令不产生结果 通过上例可以看出,R语言对空白字符不敏感,可以通过加入空格或制表符来使代码更为整齐有 1 65 序。此外,R语言会将#及其后面的内容当作注释并跳过执行。在本章的代码里,##用来表示后面是 R语言命令执行的结果。合理地添加注释能使代码的功能更加清晰,有助于自己和他人阅读和理解。 5.2.1 对象 在前一个例子,演示了用R语言进行数学计算。接下来将介绍如何记录计算的结果,以便后续使 用。在R语言中,用对象(object)来保存各种数据,以便进行后续的运算。通常,使用<-将右边的内 容赋值给左边的对象,尽管等号(=)也可以用来赋值,但在本书中统一使用<-。如果被赋值的对象此 时不存在,R语言会创建这个对象并赋值;若对象已存在,则会覆盖对象已有的值。直接输入对象名作 为命令即可显示对象的内容。执行赋值命令时不会显示赋值的内容。若要在赋值的同时显示赋值的内 容,可以在赋值语句外加上括号。另外,在RStudio中可以用快捷键alt+-来快速输入<-。 r < -1 #创建对象并赋值 r #显示对象值 ##[1]1 r <- 10 #给对象赋另一个值 r #对象已有的值被新值所覆盖 ##[1]10 (s <- pi * r ^ 2) #赋值并显示计算结果 ##[1]314.1593 对象的名称只能包含字母、数字、点(.)和下画线(_),且必须包含字母。对象必须以字母或点开头, 且区分字母的大小写。例如: #正确的对象名 a_ <- a. <- .a1 <- .A1 <- 1 #可以同时给多个变量赋相同的值 #错误的对象名 _a <- 1a <- .1a <- _1 <- 1 5.2.2 函数使用基础 对象可以用来存储数据,也可以用来存储函数(function)。本节简单介绍R 语言中函数的使用。 对于数据的分析处理甚至R语言中几乎所有的操作都是由各种不同的函数来完成的。绝大多数情况 下,可以用function(parameter=argument),即函数名(形式参数=实际参数)的方式调用函数。形式 参数简称形参,实际参数简称实参。若函数有多个参数,需要在括号内用逗号分隔。此外,如果只输入 函数名,R语言将显示该函数的内容,因为函数名本身就是一种存储函数的对象。下面是几个函数使用 的示例。 setwd("~") #更改当前工作文件夹至用户主目录 ls() #显示当前环境下的所有对象 ##[1]"r" "s" 1 66 str(cars) #显示对象结构,多用于复杂的对象 ##'data.frame': 50 obs. of 2 variables: ##$speed: num 4 4 7 7 8 9 10 10 10 11 ... ##$dist: num 2 10 4 22 16 10 18 26 34 17 ... seq(from = 0, to = 10, by = 2) #生成从0 到10、间隔为2 的数列 ##[1]0 2 4 6 8 10 seq(0, 10, b = 2) #命令同上,但省略和简化了形参 ##[1]0 2 4 6 8 10 从上例可以看出,并不是所有函数运行后都会输出结果。另外,有的函数不需要输入任何参数即可 运行,因此括号内为空。在不引起歧义的情况下,函数的形参可以简化或省略。若省略形参,实参会按 顺序被导入形参。但为了代码清晰易读,不推荐简化或省略形参。 为方便使用,一些实现基础功能的函数通常不用函数名加括号的方法来调用。这些函数的名称往 往包含特殊符号,用户可能经常使用它们,却没有意识到它们也是函数,如加法运算符号+以及赋值符 号<-。尽管没有必要,这些函数仍然能用函数名加括号的方式调用它们,此时可以用反引号`来引用 这些特殊符号函数。在后文中介绍特殊符号函数时都用反引号来引用。例如: `<-`(a, `+`(1, 3)) #等同于a <-1 + 3 a# #[1]4 `$` #加反引号得到特殊符号函数的函数名 ##.Primitive("$") 从这个例子还可以看出,函数可以嵌套在其他函数中使用,内部函数的运行结果会被当作外部函数 的参数。 5.2.3 扩展包 R语言作为数据处理软件,其最大的优势就是拥有极其丰富的扩展包(package,简称包)资源,调用 合适的包能达到事半功倍的效果。R语言自带了许多基础包,其中的一部分在R语言启动时就被自动 加载。而若要使用其他的包,则需要先下载安装再加载它们。绝大多数R 语言包都由开发者上传到 CRAN 网站统一托管,可以很方便地在R语言里用函数install.package安装需要的包。在安装成功后, 可以加载包并直接使用包里提供的所有函数和数据。有时,为了使程序阅读者能清楚地知道所用函数 来自哪个扩展包,可以使用package::function的方式使用函数。 install.package("ggplot2") #从CRAN 上搜索并安装ggplot2 library(ggplot2) #加载ggplot2 ggplot2::qplot() #qplot 函数来自ggplot2 包 目前R语言有大量的包资源供用户免费使用,很多时候用户想解决的问题早已有人给出了解决方 法。但是,包的维护和更新依赖于包的作者无偿地自发进行,因而包的质量良莠不齐。另外,在一些热 门领域常会有很多功能相似的包。对此,CRAN 汇集了一些热门方向的包并给出推荐(cran.r-project 1 67 .org/web/views)。需要注意的是,在使用一些不那么常见的R语言包时,不能无条件地相信其正确性。 还有许多优秀的R语言包被上传到Bioconductor、Github等网站上。若想从这些网站下载、安装R 语 言包,需要用到这些网站开发的包和函数,具体详见各网站的安装指南。 5.2.4 帮助 在实际使用中,用户往往需要十分频繁地查看R 语言的帮助文档。因而,如何阅读R 语言帮助文 档是一项十分重要的技能。可以在查询目标前加问号或使用help函数来查看帮助,如? lm、help(lm)。 对于特殊符号的函数,可以使用反引号来查看帮助,如?`[`。此外,还可以用双问号?? 在帮助文档中查 询关键词,再从中选择相关函数的帮助文档,例如用?? wd查找与工作路径相关的函数。在帮助文档 中,能看到函数的功能简介、所需参数、参数的类型及默认值、函数返回值等信息。在帮助文档的最后, 通常会有作者给出的实例。运行这些实例可以帮助用户直观地理解函数的功能及使用技巧。 5. 3 数据类型 对于现实中各式各样的数据类型,R语言利用不同类别的对象进行存储。本节介绍基本的数据类 型以及它们在R语言中的操作方法,包括vector、factor、date、matrix、list、data.frame和formula。对一 个未知的对象,可以使用class函数判断其类别,并用str函数查看其结构。 5.3.1 vector vector(向量)用来存储一维数据,常用于存储一个随机变量。vector存储的数据可以是数字 (numeric或integer)、字符(character)或逻辑值(logical)中的一种。其中字符类数据带有引号(")以区 别对象名。当多种类型的数据被放在一个vector中时,它们会被强行转化为同一种类型。另外,vector 中可以包括一些特殊值,如缺失值(NA)和非数字(NaN)。一般用函数c将多个数据结合在一起来创建 一个vector。例如: c(1, -3, .1, 3e2) #数字类vector ##[1]1.0 -3.0 0.1 300.0 c("one", "three", "two", "three") #字符带引号 ##[1]"one" "three" "two" "three" c(TRUE, FALSE, T, F) #逻辑值必须大写,不加引号,可用首字母缩写 ##[1]TRUE FALSE TRUE FALSE c(1, "2", 3) #数字被转换为字符 ##[1]"1" "2" "3" c(TRUE, F, 2, NA) #逻辑值转换为0 或1,而NA 不变 ##[1]1 0 2 NA 对vector的内容进行操作时,需要用到方括号函数。方括号也是一种特殊函数,在使用时需将参数 放入一对方括号中。在方括号内,可以用数字或逻辑值(也称为布尔值)来选择vector的内容。因为 vector是一维的数据,方括号内一般只有一个参数。当需要选择多个内容,可以在方括号内建立一个 1 68 vector。当需要生成连续整数时,可以用冒号(:)来连接数列的首尾值。若需要修改vector的内容,需 将修改好的内容重新赋值给原来的对象。例如: abcd <- LETTERS[1:4] #LETTERS 是R 语言自带的一个包含26 个字母的vector abcd ##[1]"A" "B" "C" "D" class(abcd) #字符型vector ##[1]"character" length(abcd) #vector 长度 ##[1]4 abcd[c(3, 1, 2)] #用数字来选择其中的内容 ##[1]"C" "A" "B" abcd[-2] #负数代表去除vector 中指定的值 ##[1]"A" "C" "D" abcd[c(T, F, T, F)] #用逻辑值来选择内容 ##[1]"A" "C" abcd <- abcd[4:1] #通过重新赋值来修改对象 abcd #对象内容被逆转 ##[1]"D" "C" "B" "A" abcd <- abcd[4:1] #再一次逆转内容 abcd #在修改对象时需注意当前对象内容 ##[1]"A" "B" "C" "D" abcd[2]<- "Z" #修改vector 中的部分内容 abcd ##[1]"A" "Z" "C" "D" 还可以对vector的内容命名,并通过名字来获取这些内容。用c(name=data)的形式可以生成带 名字的vector。通过使用names函数可以显示vector内容的名称。而要对vector已有的名称进行修 改,需使用names<-函数,在使用时相当于将名称赋值给names的结果。例如: #创建vector 时命名 a <- c(A =1, B =2) #名称=内容 a# #A B ##1 2 #显示名称 names(a) 1 69 ##[1]"A" "B" #修改vector 的命名 abcd ##[1]"A" "Z" "C" "D" names(abcd) <- letters[1:4] #用前4 个小写字母对vector 中的内容命名 abcd ##a b c d ##"A" "Z" "C" "D" names(abcd)[2]<- "z" #修改部分名称 abcd ##a z c d ##"A" "Z" "C" "D" #用名称选择vector 的内容 abcd[c("c", "a")] ##c a ##"C" "A" #去除名称 abcd <- unname(abcd) #或者names(abcd) <-NULL abcd ##[1]"A" "Z" "C" "D" 5.3.2 factor factor(因子)在R语言中通常用于存储分类变量,其本质是在vector的基础上添加顺序属性,从而 用数字来代表各种变量值。通常用factor函数将字符型vector转换成factor,其中变量值自动按照字 母顺序来与整数关联。如果需要,可以通过设定levels参数来自定义factor的变量值所对应的数字的 顺序。 myvector <- c("one", "three", "two", "three") #vector 自动转换为factor myfactor1 <- factor(myvector) myfactor1 ##[1]one three two three ##Levels: one three two class(myfactor1) ##[1]"factor" 1 70 as.numeric(myfactor1) #1-one, 2-three, 3-two ##[1]1 2 3 2 #转换时规定变量值的顺序 myfactor2 <- factor(myvector, levels = c("one", "two", "three") ) myfactor2 ##[1]one three two three ##Levels: one two three as.numeric(myfactor2) #1-one, 2-two, 3-three ##[1]1 3 2 3 #用labels 参数在转换时修改内容 myfactor3 <- factor(myvector, levels = c("one", "two", "three"), labels = c("ONE", "TWO", "THREE") ) myfactor3 ##[1]ONE THREE TWO THREE ##Levels: ONE TWO THREE #通过修改levels 来合并类别 myfactor4 <- myfactor3 levels(myfactor4) <- list("odd" = c("ONE", "THREE"), "even" ="TWO") myfactor4 ##[1]odd odd even odd ##Levels: odd even 反过来,可以用as.vector或as.character函数将factor转换为vector。而使用as.numeric函数,则 会显示factor中用来代表顺序的整数。因此,如果factor中的变量值为数字,应先转换为字符型vector 后再转换为数字。 #将factor 转换为vector (myfactor4 <- factor(c(.5, 4, 2))) ##[1]0.5 4 2 ##Levels: 0.5 2 4 as.numeric(myfactor4) #得到失去顺序信息的整数 ##[1]1 3 2 as.character(myfactor4) #得到字符型vector ##[1]"0.5" "4" "2" 1 71 as.vector(myfactor4) #和上一个操作相同 ##[1]"0.5" "4" "2" as.numeric(as.vector(myfactor4)) #将字符转换为数字 ##[1]0.5 4.0 2.0 虽然同样是一维的数据类型,但是factor的合并和内容提取要比vector复杂一些。如果要合并多 个factor,需要先将它们都转换为vector,执行合并,再转换回factor。而提取部分factor内容可以选择 是否保留空白的顺序信息。 #合并多个factor myfactor5 <- factor(c( as.character(myfactor2), as.character(myfactor3) )) myfactor5 ##[1]one three two three ONE THREE TWO THREE ##Levels: one ONE three THREE two TWO #提取部分factor myfactor5[1:2] #保留原factor 的顺序信息 ##[1]one three ##Levels: one ONE three THREE two TWO myfactor5[1:2, drop =TRUE #drop 是[]函数的参数 ] #只保留剩下的顺序 ##[1]one three ##Levels: one three 5.3.3 date 日期类型的数据在R语言中以date格式来存储和计算。通常用as.Date函数将字符型的日期转换 为date类型。在转换时,需通过format参数设定字符型日期数据的格式。更多的日期格式所对应的代 码可以在as.Date帮助文档的实例中查阅。date类型的数据实际上记录的是一个初始日期(在R 语言 中为1970-01-01)和在此基础上增减的天数。对date类型的数据使用as.vector或as.numeric函数,可 以得到其对应的天数。因此,可以对date类型的数据进行简单的数学运算。 #将字符型日期转换为date 类型 myDate1 <- as.Date("2020/01/01", format ="%Y/%m/%d" #%Y 代表4 位数的年,%m 代表2 位数的月,%d 代表2 位数的日 ) myDate1 ##[1]"2020-01-01" class(myDate1) 1 72 ##[1]"Date" as.Date("2020-01-02") #默认的日期格式 ##[1]"2020-01-02" #根据初始日期增减天数 myDate2 <- as.Date(2, origin = myDate1) #myDate1 后两天 myDate2 ##[1]"2020-01-03" #date 类型的数据记录了初始日期和变化的天数 as.vector(myDate1) ##[1]18262 as.numeric(as.Date("1900-06-29")) ##[1]-25388 #R 语言默认的初始日期为1970 年7 月1 日 as.vector(as.Date("1970-01-01")) ##[1]0 as.Date(as.vector(myDate1), origin = as.Date("1970-01-01")) ##[1]"2020-01-01" #简单的日期运算 myDate1 + 2 ##[1]"2020-01-03" myDate2 - myDate1 ##Time difference of 2 days min(myDate1, myDate2) ##[1]"2020-01-01" #当前系统日期 Sys.Date() ##[1]"2020-02-28" 5.3.4 matrix matrix(矩阵)类型在R语言中多用于存储矩阵。matrix类型是在vector的基础上增加了两个维 度的信息。因此,matrix类型同样只能包含数字、字符或逻辑值中的一种。通常,用matrix函数将一个 vector对象转换成matrix对象。