0% found this document useful (0 votes)
5 views88 pages

02 R Basics 02

Uploaded by

Ying Cao
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views88 pages

02 R Basics 02

Uploaded by

Ying Cao
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

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

You might also like