R 语言简明教程
第二课、数据类型、结构和基础操作(第二部分)
张金龙
jinlongzhang01@[Link]
2022 年 2 月 6 日
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 1 / 88
《R 语言简明教程》内容安排(I)
第一课、R 语言及其编程环境
第二课、数据类型、结构和基础操作
第三课、用 graphics 包绘图
第四课、用 ggplot2 包绘图
第五课、tidydata 以及 tidyverse 系列程序包的使用
第六课、基础统计方法的实现
第七课、编写 R 函数
第八课、Rmarkdown 以及可重复性数据分析
第九课、git 与版本控制
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 2 / 88
《R 语言简明教程》内容安排(II)
第十课、R 程序包的编写、检查与发表
第十一课、生物多样性分析常用程序包
第十二课、空间数据处理和地图绘制
第十三课、系统发育研究的常用程序包
第十四课、课程总结
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 3 / 88
内容提要
1 对象的下标(index)与按照下标提取(subscripting)
2 逻辑向量以及逻辑运算
3 条件控制 if/else
4 for 和 while 循环
5 apply 家族
6 运算符的优先次序
7 字符串的匹配、拆分和替换
8 数据的去重复、排序、合并
9 R 工作空间的保存
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 4 / 88
1
对象的下标(index)与按照下标提取
(subscripting)
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 5 / 88
对象的下标(index)
下标一般是数值或者逻辑类型的向量,用来提取基本数据类型中符合条
件的值。
对于向量 vector, 下标放入 []
对于矩阵 matrix, 下标放入 [,]。放在逗号前表示按行,逗号后表
示按列
对于数据框 [Link], 使用 [,]
对于列表 list,下标放入 [[]] 中
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 6 / 88
按照下标提取(subscripting)
1 放置 1ᱨ2ᱨ3ᱨ4 等,表示要提取元素的位置。如果放数字,都是
从 1 开始。
2 放置 TRUE、FALSE 等,表示是否提取对应的元素,TRUE 则提取,
FALSE 不提取
aaa <- c("a", "C", "F")
ind <- aaa %in% letters
ind
## [1] TRUE FALSE FALSE
aaa[ind] # 㷶ⓞㅊ⢔㽶ㄾ㵀 letters 㦢⼋㺲
## [1] "a"
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 7 / 88
2
逻辑向量以及逻辑运算
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 8 / 88
生成逻辑向量:比较
比较数值的大小,结果为逻辑向量,由 TRUE 或者 FALSE 组成。
== 判断数值是否相等,是为 TRUE, 否为 FALSE
>: 判断左侧值是否大于右侧值
<: 判断左侧值是否小于右侧值
>= : 判断左侧值是否大于或等于右侧值
<= : 判断左侧值是否小于或等于右侧值
!= : 判断左侧值是否不等于右侧值
%in%: 判断某些向量的值是否出现在另一个向量中
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 9 / 88
举例
1 > 0
## [1] TRUE
1 == 1
## [1] TRUE
c(1, 2, 3) > 2
## [1] FALSE FALSE TRUE
1 %in% c(1, 2, 3)
## [1] TRUE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 10 / 88
生成逻辑向量:数据类型判断 [Link]
判断数据结构是否为指定的类型,返回结果为 TRUE 或者 FALSE
apropos("is.")
[Link]() # 㗁⟑㢜㽶⟛╔ᱻ
[Link]() # 㗁⟑㢜 [Link]ᱻ
[Link]() # 㗁⟑㢜⳪㸗ᱻ
[Link]() # 㗁⟑㢜㦢⼋ᱻ
[Link]() # 㗁⟑㢜⼜⍙ᱻ
[Link]() # 㗁⟑㢜⭃㨻ᱻ
[Link]() # 㗁⟑㢜㐯㖡㺗 NAᱻ
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 11 / 88
NA 类型的判断
注意,缺失值,即 NA 类型的数据,不能直接比较,否则结果仍然是 NA。
要判断一个值是否为 NA,需要用 [Link]()。
test <- c(runif(3), NA)
test == NA
## [1] NA NA NA NA
[Link](test)
## [1] FALSE FALSE FALSE TRUE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 12 / 88
类型转换 [Link]
转换为所需要的类型:
apropos("as.")
[Link]() # 㽊⪓㢜㽶⟛╔
[Link]() # 㽊⪓㢜 [Link]
[Link]() # 㽊⪓㢜 matrix
[Link]() # 㽊⪓㢜 vector
[Link]() # 㽊⪓㢜 list
[Link]() # 㽊⪓㢜⭃㨻
¬¬
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 13 / 88
数值类型转换为逻辑类型
数值类型,容易转换为逻辑类型,默认非零为 TRUE,零为 FALSE
dat <- c(2,3,5,7,0,9,0)
[Link](dat)
## [1] TRUE TRUE TRUE TRUE FALSE TRUE FALSE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 14 / 88
逻辑向量的运算(与、或、非)
若现有相互独立的事件 A 和 B,以下为常见的逻辑运算:
A 不发生,记为 “非 A”(!A)
B 不发生,记为 “非 B”(!B)
A、B 同时发生,“A 与 B”(A&B)
A、B 至少有一个发生,记为 “A 或 B” (A|B)
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 15 / 88
逻辑运算(取反,“非”)
逻辑运算的结果,还是逻辑向量
!: 取反,表示” 不是”
▶ !TRUE 结果为 FALSE
▶ !FALSE 结果为 TRUE
had_breakfast <- TRUE
!had_breakfast
## [1] FALSE
like_bread <- c(TRUE, TRUE, FALSE, TRUE, TRUE)
res_not <- !like_bread
res_not
## [1] FALSE FALSE TRUE FALSE FALSE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 16 / 88
逻辑运算(“与”)
& 或者 &&: 与, 表示同时发生,& 两侧的事件必须同时为真,结果
才为真 TRUE
▶ TRUE & TRUE 结果为 TRUE
▶ TRUE & FALSE 结果为 FALSE
▶ FALSE & FALSE 结果为 FALSE
like_bread <- c(TRUE, TRUE, FALSE, TRUE, TRUE) # 㥢⪎ギ⊪
like_egg <- c(TRUE, TRUE, FALSE, TRUE, FALSE) # 㥢⪎⬼☔
res_and <- like_bread & like_egg # ⼉㺸⛞㥢⪎
res_and
## [1] TRUE TRUE FALSE TRUE FALSE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 17 / 88
逻辑运算(“或”)
| 或者 ||: 或,| 两侧只要一个条件满足,返回结果就是真(TRUE)
▶ TRUE|TRUE, 结果为 TRUE
▶ TRUE|FALSE, 结果为 TRUE
▶ FALSE|FALSE, 结果为 FALSE
like_bread <- c(TRUE, TRUE, FALSE, TRUE, TRUE) # 㥢⪎ギ⊪
like_egg <- c(TRUE, TRUE, FALSE, TRUE, FALSE) # 㥢⪎⬼☔
res_or <- like_bread | like_egg # 㥢⪎ギ⊪⫊㸃⬼☔㑌㯌㮥ⶾ
res_or
## [1] TRUE TRUE FALSE TRUE TRUE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 18 / 88
&、&&、|、|| 的区别
& 和 | 支持向量化运算,返回值为一个向量
&& 和 || 只支持向量的第一个元素,返回值为一个逻辑值 TRUE 或
者 FALSE
如果编写函数,一般用 && 或者 ||
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 19 / 88
all() 和 any()
all: 判断是否全部元素为真
any: 判断是否任意一个元素为真
aaa <- c(T, T, T, T, F, F, F, T)
# T 㗁 TRUE ☨㚭㨢ᱨF 㗁 FALSE ☨㚭㨢
all(aaa)
## [1] FALSE
any(aaa)
## [1] TRUE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 20 / 88
用逻辑向量提取部分数据 (subset)
使用下标,或者 subset() 函数
library(vegan)
data([Link])
subset([Link], Use == "Haypastu")[1:3,]
## A1 Moisture Management Use Manure
## 1 2.8 1 SF Haypastu 4
## 2 3.5 1 BF Haypastu 2
## 3 4.3 2 SF Haypastu 4
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 21 / 88
用逻辑向量提取部分数据,用 [] 提取
用逻辑向量提取
[Link][[Link]$A1 > 6,]
## A1 Moisture Management Use Manure
## 5 6.3 1 HF Hayfield 2
## 14 9.3 5 NM Pasture 0
## 15 11.5 5 NM Haypastu 0
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 22 / 88
用逻辑向量提取部分数据 (示逻辑运算)
A1 > 3 同时 Use == "Haypastu"
[Link][[Link]$A1 > 3 & [Link]$Use == "Haypastu",]
## A1 Moisture Management Use Manure
## 2 3.5 1 BF Haypastu 2
## 3 4.3 2 SF Haypastu 4
## 4 4.2 2 SF Haypastu 4
## 6 4.3 1 HF Haypastu 2
## 12 5.8 4 SF Haypastu 2
## 13 6.0 5 SF Haypastu 3
## 15 11.5 5 NM Haypastu 0
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 23 / 88
随机抽取部分数据
sample() 实现(伪)随机抽取部分数据
sample(x, size, replace = FALSE, prob = NULL)
replace = TRUE 实现” 有放回抽样”,一般用于生成 bootstrap 样本。
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 24 / 88
随机抽样举例
[Link](133)
xxx <- sample(1:20+30, 10, replace = TRUE)
table(xxx) # ⭜㚛ょ⢔㗷㽶ⓞ㦆☨╴㗷
## xxx
## 32 34 36 38 39 43 47
## 1 2 1 1 1 2 2
[Link]() 设定随机数种子,以保证每次生成的随机数序列是一致的。
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 25 / 88
3
条件控制 if/else
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 26 / 88
流程控制 if()
if(⭃㺗) {
# 㑥⥗⭃㺗㢜 TRUE
# 㲗⫊㸃㲗ⶹ 1
} else {
# 㑥⥗⭃㺗㢜 FALSE
# 㲗⫊㸃㲗ⶹ 2
}
if 后的括号内只允许一个逻辑值,要么是 TRUE,要么是 FALSE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 27 / 88
程序员买包子
程序员的老婆给程序员打电话:“下班后买十个包子,如果看到卖西瓜
的,买一个。”
下班后,程序员买了一个包子回家了。
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 28 / 88
普通人理解
☾㮥⏧ᱨ㥸㖨⢔⊪㽳ᱷ
☾✠⏧ᱨ㑥⥗ゃ⮑☡㣩⤫☨ᱨ㖬ぼ⛞⏥㾖ᮣ
㑥⥗⮑☡㣩⤫☨ᱨ㮥⢔㣩⤫ᮣ
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 29 / 88
程序员为什么只买了一个包子回家?
if(⮑☡㣩⤫☨){
㮥⢔⊪㽳
}
if(ゃ⮑☡㣩⤫☨)
㖨⢔⊪㽳
}
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 30 / 88
流程控制 if() 和 else
if() 控制条件是否执行,如果为 TRUE,后面紧跟的语句就会执行
homework = TRUE
if(homework){
print("Do homework") # 㗁ᱨ㝫⮔〄㾃
} else {
print("Go shopping") # ⟑ᱨ㝫⮔⏥〄㾃
}
## [1] "Do homework"
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 31 / 88
以下两种写法有什么不同?
homework = TRUE
## 㨢➈ 1
if(homework) print("Do homework!") else print("Go shopping!")
## 㨢➈ 2
if(homework){
print("Do homework") # 㗁ᱨ㝫⮔〄㾃
} else {
print("Go shopping") # ⟑ᱨ㝫⮔⏥〄㾃
}
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 32 / 88
什么时候用 if() 和 else
如果条件是可能变化的,而且不同情况要执行不同的语句,就要用
if
如果 if() 中已经包括要满足的条件,不用考虑其他情况,就不用
else
如果要考虑所有的情况,就要用 else
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 33 / 88
什么时候用 if()
had_breakfast <- NA
had_bread <- TRUE # Ⓖ⥙ギ⊪
had_egg <- FALSE # ゃⒼ⥙⬼☔
had_milk <- FALSE # ⧢⥙ㅒ
if(had_bread){
had_breakfast <- TRUE
}
if(had_egg){
had_breakfast <- TRUE
}
if(had_milk){
had_breakfast <- TRUE
}
print(had_breakfast)
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 34 / 88
什么时候用 else?
had_breakfast <- NA
had_bread <- TRUE # Ⓖ⥙ギ⊪
had_egg <- FALSE # ゃⒼ⥙⬼☔
had_milk <- FALSE # ⧢⥙ㅒ
if(had_bread|had_egg|had_milk){
print("I have had breakfirst!")
had_breakfast <- TRUE
}else{
print("I haven't had breakfirst yet!")
had_breakfast <- FALSE
}
## [1] "I have had breakfirst!"
print(had_breakfast)
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 35 / 88
什么时候用花括号?
如果只执行 if 后的一条语句,花括号可有可无(optional)。
如果要执行多行语句,必须要用花括号 {} 括起来。
任何情况,都建议加 {},将要执行的语句与其余部分分隔开。
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 36 / 88
ifelse 语句
ifelse 是 if(){}else{} 的简化版,常用于语句中, 但在一定程度上降
低了程序的可读性
x <- 3:-1
sqrt(x) # ⡘㗷⏥ㅢ⭜㚛㊿➝⢗ᱨ㯜╱➕⪰ NaN
## Warning in sqrt(x): NaNs produced
## [1] 1.732051 1.414214 1.000000 0.000000 NaN
sqrt(ifelse(x >= 0,x,NA)) # 㥸⯿ <0 ☨㺗㽊⪓㢜 NAᱨ➕⪰ⰵ⥗㢜 NA
## [1] 1.732051 1.414214 1.000000 0.000000 NA
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 37 / 88
if 与多个逻辑值
注意:if 里面只能放一个 TRUE 或者 FALSE,如果放多个,只会按照第
一个 TRUE 或者 FALSE 执行,而且有 warning 出现。
如果要满足多个 TRUE 怎么办?
答案:
all()
any()
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 38 / 88
all 与 any 的使用
students <- c("Jinlong", "Jianping", "Xiaoming",
"Zhigang", "Zhiqiang")
attend <- c(FALSE, TRUE, TRUE, TRUE, TRUE)
if(all(attend)){
print(" 㟠㫓㐩⏩☡㋭ᱝ")
}
if(any(!attend)){
print(paste(paste(students[!attend],
collapse = ", "), " 㝉⼗"))
}
## [1] "Jinlong 㝉⼗ "
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 39 / 88
4
for 和 while 循环
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 40 / 88
for 循环
for(i in X 㦢⼋){㮔㺖㨾☨㲗}
功能:保证花括号 {} 中的内容重复一定的次数。
“X 向量” 一般为 1:length()、1:nrow() 或向量本身。
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 41 / 88
for 循环的 “变量”
循环一般用字母 i, j, k, m, n,这些字母,一般控制要执行语句
的次数,也常作为花括号内变量的下标。
R 中,循环一般” 较慢”,因此要尽量减少循环的使用 (其实也可能
循环比较难写),
多用向量计算,或者 tidyverse 的 dplyr 包、[Link] 包或
者 apply 家族的函数操作数据。
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 42 / 88
什么时候用 for 循环?
批量绘图,如森林监测样地,绘制每个物种的分布图
部分数据处理,需要提取数据的某一部分,重复提取指定的次数,
如随机抽样
批处理多个文件、数据集等,每个文件、数据集执行类似的操作,
例如将植物照片移动到对应的科、属文件夹中。
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 43 / 88
for 循环举例
aaa <- LETTERS[1:5]
for(i in 1:3){ # 㺺⡒▘㱉 aaa 3 ╴
print(aaa)
}
for(i in 1:length(aaa)){ # ょ╴ i ⛞㵀⍐⪇
print(i)
}
for(i in 1:length(aaa)){ # i 㮾㾗㢜 aaa ☨㥲⍖
print(aaa[i])
}
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 44 / 88
for 循环举例
i 可以遍历向量的每一个元素
for(i in c("A","B","C")){
print(i)
}
## [1] "A"
## [1] "B"
## [1] "C"
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 45 / 88
for 循环举例
循环结束之后,i 的值不再改变
aaa <- LETTERS[1:3]
for(i in aaa){
print(i) # ょ╴㫙⪏ i ☨㺗
}
## [1] "A"
## [1] "B"
## [1] "C"
print(i) # 㫙⪏㺐⨍ᱨi ☨㺗
## [1] "C"
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 46 / 88
for 循环举例
i 常作为下标使用
aaa <- LETTERS[1:5]
for(i in 1:length(aaa)){
print(aaa[i])
}
## [1] "A"
## [1] "B"
## [1] "C"
## [1] "D"
## [1] "E"
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 47 / 88
for 循环举例:print 放在 for 的 “作用域” 里面
可以在循环之前,先创建一个空白向量,每次循环,增加该次循环运算
出的值。
aaa <- LETTERS[1:4]
res <- c()
# print(i)
for(i in 1:length(aaa)){
res <- c(res, aaa[i])
print(res)
}
## [1] "A"
## [1] "A" "B"
## [1] "A" "B" "C"
## [1] "A" "B" "C" "D"
print(res)
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 48 / 88
for 循环 + if 判断举例
随机生成 3 个数字,如果 <0.5,打印” 小于 0.5”;如果 >=0.5,打印”
大于或等于 0.5”
[Link](123)
aaa <- runif(3) # 㔶⒱ 3 ⢔ 0-1 㺐⭺☨㚞⫒㗷
print(aaa)
## [1] 0.2875775 0.7883051 0.4089769
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 49 / 88
for 循环 + if 判断举例
for (i in 1:length(aaa)){
if(aaa[i] < 0.5){
print(paste(round(aaa[i], 3),
"is less than 0.5"))
} else {
print(paste(round(aaa[i], 3),
"is greater than or equal to 0.5"))
}
}
## [1] "0.288 is less than 0.5"
## [1] "0.788 is greater than or equal to 0.5"
## [1] "0.409 is less than 0.5"
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 50 / 88
for 循环举例
1 到 10,如果是奇数,打印” 奇数”,如果是偶数,打印” 偶数”
写法一
res <- character() # 㥸╚⯼㮥⢔ⶥ⊅㦢⼋㮾⌏▌ⰵ⥗
for(i in 1:10){
if(i %% 2 == 0){
res <- c(res, " ㈀")
} else {
res <- c(res, " ㋨")
}
}
res
## [1] " ㋨ " " ㈀ " " ㋨ " " ㈀ " " ㋨ " " ㈀ " " ㋨ " " ㈀ " " ㋨ " " ㈀ "
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 51 / 88
for 循环举例
写法二
dat <- 1:10
res <- rep(NA, length(dat))
for(i in 1:length(dat)){
if(dat[i] %% 2 == 0){
res[i] <- " ㈀"
} else {
res[i] <- " ㋨"
}
}
print(res)
## [1] " ㋨ " " ㈀ " " ㋨ " " ㈀ " " ㋨ " " ㈀ " " ㋨ " " ㈀ " " ㋨ " " ㈀ "
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 52 / 88
for 循环是否真的有必要?
R 是一种向量化的语言
dat <- 1:10
res <- rep(NA, length(dat))
res[dat%%2 == 0] <- " ㈀"
res[dat%%2 == 1] <- " ㋨"
res
## [1] " ㋨ " " ㈀ " " ㋨ " " ㈀ " " ㋨ " " ㈀ " " ㋨ " " ㈀ " " ㋨ " " ㈀ "
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 53 / 88
while 循环
while 循环用于不知道要进行多少次循环时,相比 for 循环,while 循
环有时候更加简洁,但也更加抽象 (所以 while 比 for 要少用):
res = 20
while(res > 10){
res = res - 2
print(res)
}
## [1] 18
## [1] 16
## [1] 14
## [1] 12
## [1] 10
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 54 / 88
switch 分支选择
绝大部分可以用 if(){} else{} 代替,但 switch 一般更简洁。
x <- " ギ⊪"
unit <- switch(x,
ギ⊪ = " ⶹ",
⬼☔ = " ⢔",
ㅒ = " ⌙")
unit
## [1] " ⶹ "
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 55 / 88
5
apply 家族
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 56 / 88
apply 函数家族
apply 可减少循环的使用,如计算矩阵每一列的和,每一列的中位数等。
library(vegan)
data(BCI) # BCI 㬥☼㗷⳯ᱨ㨾㢜㬥➝ッᱨ⼜㢜㣡㺸ッᱨ㺗⍙㖸⢔㝛㗷
head(apply(BCI,MARGIN = 1, sum )) # ょ⢔㬥➝☨⢔㝛㗷
## 1 2 3 4 5 6
## 448 435 463 508 505 412
head(apply(BCI,MARGIN = 2, sum ), 4) # ょ⢔㺸☨⢔㝛㗷
## [Link] [Link] [Link]
## 1 3
## [Link]
## 1
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 57 / 88
已知成绩单,求男生和女生的平均分
records <- [Link](c("John","Fred","George","Tonny",
"Daisy","Jane"),
c(100,85,60,72,90,95),
c("M", "M", "M", "M", "F", "F"))
colnames(records) <- c("name", "score", "gender")
head(records, 3)
## name score gender
## 1 John 100 M
## 2 Fred 85 M
## 3 George 60 M
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 58 / 88
tapply 按照 gender 求平均成绩
# ⢕㯜㽳ょ⢔㙦㊿㥲㴱㨾 sum ⧉㗷
tapply(records$score, records$gender, mean)
## F M
## 92.50 79.25
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 59 / 88
6
运算符的优先次序
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 60 / 88
运算符的优先次序
类似于四则运算优先次序
()[]:最高
^:平方、立方、幂其次
*, /, +, -, %%, %/% :再次
==, != :低
|, & :最低
任何不清楚优先等级的,都需要用 () 控制
(2 + 3)^2 - (5 + 12)/9 == 20
## [1] FALSE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 61 / 88
7
字符串的匹配、拆分和替换
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 62 / 88
操作字符串的函数
nchar(): 字符串中的字符数
cat(): 连接字符串,并输送到设备中
paste()/paste0(): 合并字符串
substr(): 按照下标提取字符串的一部分
substring(): 按照下标提取字符串的一部分
strsplit(): 按照匹配规则拆分字符串
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 63 / 88
操作字符串的函数
gsub(): 替换
grepl(): 对字符串元素,匹配返回 TRUE,不匹配返回 FALSE
grep(): 返回匹配字符串向量的” 下标”
toupper(): 全部转换为大写
tolower(): 全部转换为小写
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 64 / 88
操作字符串的函数
nchar("USA")
## [1] 3
paste("Group", 1:3)
## [1] "Group 1" "Group 2" "Group 3"
paste0("Group", 1:3)
## [1] "Group1" "Group2" "Group3"
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 65 / 88
操作字符串的函数
substr("ABCDEFG", start = 1, stop = 3)
## [1] "ABC"
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 66 / 88
gsub 替换
现有四名参赛选手,分别来自不同班级,-之前是姓名,-之后是所属班
级,问一共有几个班?每组里面有多少人?
aaa <- c("Zhang Jin-Class01", "Wang Tao-Class01",
"Zhao Lin-Class02", "Li Shuo-Class03")
# 㝜⪓♘㚱㱸㽶ㄾ㮾⭆-
res <- gsub("[a-zA-Z-]", "", aaa)
res
## [1] " 01" " 01" " 02" " 03"
print(paste0("Number of classes: ",length(unique(res))))
## [1] "Number of classes: 3"
table(res) # ょ⢔⊎⭌㺺⡒☨╴㗷
## res
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 67 / 88
grepl 匹配字段
找出姓 Zhang 同学相关的数据
aaa <- c("Zhang Jin-Class01", "Wang Tao-Class01",
"Zhao Lin-Class02", "Li Shuo-Class03")
with_zhang <- grepl("Zhang", aaa)
with_zhang
## [1] TRUE FALSE FALSE FALSE
aaa[with_zhang]
## [1] "Zhang Jin-Class01"
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 68 / 88
字符串处理举例
百家姓前几名的拼音中,各字母出现的频率
family_names <- c("Zhao", "Qian", "Sun", "Li",
"Zhou", "Wu", "Zheng", "Wang")
all_chars <- paste(family_names, collapse = "")
sort(table(strsplit(all_chars, split = "")))
##
## e L Q S g i o W a h u Z n
## 1 1 1 1 2 2 2 2 3 3 3 3 4
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 69 / 88
正则表达式 (Regular Expression)
?regex
正则表达式用于字符串的查找与替换。
能够按照一定规则匹配所需要的字符。
正则表达式中区分大小写。
在 Perl、Python、Ruby、JavaScript 等语言中都已实现。
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 70 / 88
常用的特殊符号
\\n \n # ⪓㨾
\\t \t # 㺨⍙⟛
\\s \s # 㚱㱸ⶥ⢏
\\d \d # 㚱㱸㗷㽶
\\D \D # 㚱㱸➧㗷㽶
\\w \w # 㑌㯌☉╰ㅠ☨㽶⟛
\\b \b # ☉╰⍋☨㽶⟛
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 71 / 88
常用正则表达式
[:digit:] # 㗷㽶
[:alpha:] # 㽶ㄾ
[:lower:] # 㨏㨢㽶ㄾ
[:upper:] # ▙㨢㽶ㄾ
[:alnum:] # 㗷㽶⧧㽶ㄾ
[:punct:] # ⍖♇⟛⧟
... ...
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 72 / 88
进一步学习正则表达式:stringr 包
常用字符串操作,用 stringr 包更为方便。
下载 stringr 包的 cheatsheet:
[Link]
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 73 / 88
8
数据的去重复、排序、合并
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 74 / 88
去重复 unique
用于向量,去除重复元素
用于数据框,删除重复的行
b1 <- sample(1:20, 20, replace = TRUE)
table(b1)
## b1
## 3 4 5 7 8 9 10 11 14 17 18 19 20
## 2 1 2 1 1 2 2 1 3 1 1 2 1
unique(b1)
## [1] 14 3 10 18 11 5 20 19 9 8 7 4 17
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 75 / 88
数据的排序:sort
直接排序
library(vegan)
data([Link])
sort([Link]$A1) # 㺓Ⱗ⛶㦢⼋㈉㩠
## [1] 2.8 2.8 3.3 3.5 3.5 3.5 3.7 3.7 4.0 4.2 4.2
## [16] 5.8 6.0 6.3 9.3 11.5
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 76 / 88
数据的排序:order
生成排序用的下标
# ≢㷹 A1 ☨㺗㈉㩠ᱨorder ➕⪰☨㗁㦢⼋ⓞ㦆☨ index
[Link][order([Link]$A1),]
## A1 Moisture Management Use Manure
## 1 2.8 1 SF Haypastu 4
## 7 2.8 1 HF Pasture 3
## 10 3.3 2 BF Hayfield 1
## 2 3.5 1 BF Haypastu 2
## 11 3.5 1 BF Pasture 1
## 20 3.5 5 NM Hayfield 0
## 9 3.7 4 HF Hayfield 1
## 19 3.7 5 NM Hayfield 0
## 17 4.0 2 NM Hayfield 0
## 4 4.2 2 SF Haypastu 4
## 8 4.2 5 HF Pasture 3
## jinlongzhang01@[Link]
张金龙 3 4.3 2 SF Haypastu
R 语言简明教程 4 年2月6日
2022 77 / 88
数据的合并:merge
merge,用来合并两个 [Link]()
records <- [Link](c("John","Fred","George","Tonny",
"Daisy","Jane"),
c(100,85,60,72,90,95),
c("M", "M", "M", "M", "F", "F"))
colnames(records) <- c("name", "score", "gender")
head(records, 3)
## name score gender
## 1 John 100 M
## 2 Fred 85 M
## 3 George 60 M
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 78 / 88
数据的合并:merge
attend_dat 数据
attend_dat <- [Link](name = c("Jane", "George", "Fred",
head(attend_dat)
## name attend
## 1 Jane TRUE
## 2 George TRUE
## 3 Fred FALSE
## 4 Tonny TRUE
## 5 Daisy FALSE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 79 / 88
数据的合并:merge
merge(x = records, y = attend_dat, by = "name", all = TRUE)
## name score gender attend
## 1 Daisy 90 F FALSE
## 2 Fred 85 M FALSE
## 3 George 60 M TRUE
## 4 Jane 95 F TRUE
## 5 John 100 M NA
## 6 Tonny 72 M TRUE
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 80 / 88
9
R 工作空间的保存
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 81 / 88
将 R 工作空间保存为 RData 文件
save() 除了将 R 工作空间内特定的对象保存为.RData 文件,
[Link]() 将当前工作空间内所有对象 (working space) 保存
为.RData 文件。
x <- stats::runif(20)
y <- list(a = 1, b = TRUE, c = "oops")
save(x, y, file = "[Link]")
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 82 / 88
读取 RData 文件
RData 文件是二进制文件,可以存储 R 工作空间的所有对象。
一般用 load() 读取。
?load
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 83 / 88
save() 函数要多用
最简单,最常用的存储结果的方式就是 save(),这个函数在工作目录
下生成.Rdata 的文件,下回你直接打开这个文件,用 ls() 就能直接看
到有哪些对象了,方便又简单,效率高,又不容易出错……
以后凡是让我看数据的,一律是要这种.Rdata 的文件,别给我 csv 了。
᮪᮪ ⹃Ⰱ㓹
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 84 / 88
内容回顾
1 下标、逻辑运算和数据提取
2 类型判断和转换:is 和 as
3 条件控制 if/else
4 for 和 while 循环
5 apply 家族
6 运算符的优先次序
7 字符串的匹配、拆分和替换
8 数据的去重复与排序
9 工作空间的保存
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 85 / 88
课程信息
完整课程视频和代码敬请关注:
BioONE 生物多样性与生态安全大数据平台:[Link]
[Link]/App/VideoClass/[Link]?guid=R-in-brief
微信公众号:ecoinformatics 及 HelloBD
Bilibili:[Link]
课程材料和源代码:[Link]
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 86 / 88
致谢
感谢提出意见的各位老师、同学(以下排名不分次序),特别是:
赖江山、赵宇莹、刘璐妹、余光创、向小果、胡文浩、安瑞志、杨拓、
朱慧玲、乔慧捷、文香英、葛学军、陈建平、曾思金、刘景欣、杨雪飞、
胡小丽、李勤、崔煜文等
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 87 / 88
信息反馈
图 1: 敬请关注 ecoinformatics
如有任何问题、意见或者建议,欢迎联系本人
Email: jinlongzhang01@[Link]
本人微信 jinlongzhang01
张金龙 jinlongzhang01@[Link] R 语言简明教程 2022 年 2 月 6 日 88 / 88