2  R语言编程入门

对于初学者而言,编程有时候就像一座不可翻过的大山,以为其知识犹如无底洞,无法探知其有多深。但事实上,在基本的数据分析中所需要用得的编程基础并没有那么多、那么难,本章将试图以最简洁的方法来把读者引入R程序编写的世界。如果已经具备R语言编程基础的读者可以直接跳过本章。

2.1 基本数据类型

R语言是一门面向数据的语言,因此用户必须熟悉R体系中的基本数据类型。R中常用数据类型包括数值型、逻辑型、字符型和因子型四种,下面我们会一一进行介绍。

2.1.1 数值型

数值型,顾名思义就是数字,如20220124。我们可以用class函数来查看数据的类型。

class(20220124)
[1] "numeric"

我们可看到,这是一个数值型。其实数值还有更深层的分类,就是整数型和双精度型,可以用来表示整数和正整数。如果要表示整数,一般在数字后面加入“L”。我们可以用typeof函数来看到细分的数据差别。

typeof(20220124L) #整数型
[1] "integer"
typeof(2022.0124) #双精度型
[1] "double"

R中还有一种数据类型叫做复合型,可以表示数学中的虚数,表示方法如下:

class(1 + 1i)
[1] "complex"

由于在文本挖掘中不常用,这里不展开介绍这种数据类型。

2.1.2 逻辑型

逻辑型的数据,一般是指非黑即白的两种:真(TRUE)与假(FALSE)。

class(FALSE)
[1] "logical"
class(TRUE)
[1] "logical"

TRUE和FALSE都是R中的保留字符,它们还可以分别简写为T和F。

class(F)
[1] "logical"
class(T)
[1] "logical"

值得注意的是,R中表示缺失值的保留字NA也是逻辑型数据。

class(NA)
[1] "logical"

2.1.3 字符型

字符型就是字符串,在文本挖掘中所有文本格式的数据都属于这种类型,如“R语言”、“数据分析”。

class("R语言")
[1] "character"
class("数据分析")
[1] "character"

2.1.4 因子型

因子型是R中独特的数据结构,它代表了字符与数字的映射关系,可以表示离散型的数据。

a = factor("Ding") # 构造一个因子型数据赋值给a
class(a)
[1] "factor"

使用level函数可以看到因子变量的等级。

levels(a)
[1] "Ding"

2.2 常用数据结构

在实际应用中,数据总是以一定的形式组织起来,在R中也有对应的数据结构来表达这些组织形式。在本节中,我们将会对R语言中常用的数据结构(向量、矩阵、列表、数据框)进行介绍。

2.2.1 向量

在上一节中,我们提到了数据类型,包括数值型、字符型、因子型等。这些具有相同数据类型的多个数据单位组合到一起,可以构成一个向量(Vector)。在R中,我们可以利用c函数来构造一个向量。

num_vec = c(1,3,5,7)
char_vec = c("A","B","C")
logl_vec = c(T,F,T)

num_vec
[1] 1 3 5 7
char_vec
[1] "A" "B" "C"
logl_vec
[1]  TRUE FALSE  TRUE

我们可以用is.vector来判断变量是否是一个向量。

is.vector(num_vec)
[1] TRUE

2.2.2 矩阵

矩阵(Matrix)的本质是一个二维数组,具有行和列两个维度。在R中,可以使用matrix函数来构造一个矩阵。比如,我们构造一个名为mdat的矩阵,其中行名称为row1和row2,列名称为C.1、C.2和C.3。需要注意的是,行列的名称其实是可以缺省的。

mdat <- matrix(c(1,2,3, 11,12,13), nrow = 2, ncol = 3, byrow = TRUE,
               dimnames = list(c("row1", "row2"),
                               c("C.1", "C.2", "C.3")))
mdat
     C.1 C.2 C.3
row1   1   2   3
row2  11  12  13

我们可以使用is.matrix函数来判断数据是否是一个矩阵。

is.matrix(mdat)
[1] TRUE

2.2.3 列表

列表(List)是R中最为灵活的数据结构,它就像一列火车,每个车厢中可以放任意类型的数据。下面我们举个例子:

a_list = list(T,1,"hello")
a_list
[[1]]
[1] TRUE

[[2]]
[1] 1

[[3]]
[1] "hello"

使用is.list函数可以判断一个数据是否是一个列表。

is.list(a_list)
[1] TRUE

2.2.4 数据框

数据框(Data Frame)是R中重要的数据结构,能够表达传统数据库中的二维表结构。它是一种特殊的列表,它每一列是一个向量(具有数据类型同质性),每一行是一个列表(单个样本可以有不同数据类型的属性)。一般而言,数据框一定会有列名称来描述属性,而行名称则可有可无,因为行名称可以新增一列来进行表示。在R中,可以使用data.frame函数来构建一个数据框。

df = data.frame(a = 1:3, b = 4:6)
df
  a b
1 1 4
2 2 5
3 3 6

可以使用names函数来获得其列名称。

names(df)
[1] "a" "b"

如果想要获知它的维度(它有几行几列),可以使用dim函数。

dim(df)
[1] 3 2

与之前类似,我们可以用is.data.frame函数来判断一个数据是否是数据框结构。

is.data.frame(df)
[1] TRUE

2.3 编程知识介绍

R语言与C语言等其他编程语言相似,有自身的一套编程体系。尽管这个体系非常庞杂,但是对于入门者而言只需要掌握其中一些核心的内容就可以完成大部分简单的数据操作和计算。本节将会针对R语言编程的部分核心内容进行简要介绍,从而让初学者快速掌握一些基本概念。

2.3.1 赋值

在前面的介绍中,我们已经用到了赋值操作。赋值就是把计算好的结果赋予一个变量的过程。在R中,可以使用等号(“=”)或箭头(“<-”和“->”)来对变量进行赋值。

a = 1
# 等价于
a <- 1
# 等价于
1 -> a

尽管在R中可以灵活地使用以上三种方法进行赋值,但是有时候作为项目管理,应该统一编程风格。比如有的规范中建议在所有函数定义的时候用“=”,而在数值保存的时候使用“<-”。而日常使用中,因为编写代码总是有从左到右的习惯,则可以灵活地使用“->”来进行赋值。 在R中,还可以使用assign函数来为一个变量名进行赋值,也就是说我们上面的复制,还可以这么写:

assign("a",1)

这里,“a”是一个字符,它代表了变量的名称。

2.3.2 函数

函数式编程是R的一大特色,在R中我们无时无刻不在调用函数来实现不同的算法。比如,我们想要求得一个数值型向量的均值,我们可以使用R内置的mean函数。

a = c(1,2,3)
mean(a)
[1] 2

sum函数则可以求得数值型向量的总和。

sum(a)
[1] 6

在日常工作中,我们常常需要自定义函数来完成特定的任务,比如我们想利用勾股定理来求直角三角形斜边的长度。下面,我们尝试构造一个名为“get_length”的函数来完成这个计算。

get_length = function(a,b){
  sqrt(a^2 + b^2)  #sqrt是R内置的开方函数
}

get_length(3,4)
[1] 5

2.3.3 强制类型转换

我们已经知道R中的基本数据类型,这些数据类型在一定条件下,可以进行相互转化。举一个例子,在R中认为,逻辑型的函数,TRUE是1,FALSE是0,通过强制类型转换,我们能够看到这个关系。

as.numeric(TRUE)
[1] 1
as.numeric(FALSE)
[1] 0

这里,我们用as.numeric把逻辑型数据转化为了数值型。在这个步骤中,操作时可逆的,我们可以把数值1和0重新转化为逻辑型数据。

as.logical(1)
[1] TRUE
as.logical(0)
[1] FALSE

逻辑型和数值型的数据都可以转化为字符型数据。

as.character(TRUE)
[1] "TRUE"
as.character(1990)
[1] "1990"

在R中,可以使用以“as.”为前缀的函数,对数据进行强制类型转换。

2.3.4 条件判断

在R中经常要使用条件判断来实现分支结构,如果满足某一条件就执行A操作,否则执行B操作,if语句和else语句可以轻松地实现这个过程。

a = 3
if(a > 3) print("a大于3") else print("a不大于3")
[1] "a不大于3"

我们还可以用ifelse语句直接实现这个结构:

ifelse(a > 3,"a大于3","a不大于3")
[1] "a不大于3"

2.3.5 循环操作

在批处理过程中,我们往往需要利用循环来对数据做遍历,以计算所有的情况。在R中使用循环非常灵活,比如我们要打印1到10的所有正整数,我们可以利用for循环来编码。

for (i in 1:10) {
  print(i)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10

如果我们要利用条件判断,那么可以使用while语句来实现上面的操作。

i = 1
while(i <= 10){
  print(i)
  i = i+1
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10

需要注意的是,在上面的操作中,我们给i定义了初始值1,并在每一步运算结束后加上了1来推进遍历操作。 最后,还要介绍repeat语句,它相当于“while(1)”,也就是没有遇到终止操作break,它就会一直运行下去。下面,我们尝试利用repeat语句来实现以上操作。

i = 1
repeat{
  print(i)
  i = i+1
  if(i > 10) break #如果i大于10,结束循环
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10

2.4 小结

本章介绍了R语言中最基础的编程概念。要开展数据分析,就需要了解R语言中最基本的数据类型和数据结构,因此本章首先对此进行了讲解介绍。随后,我们还引入了一些最基础的编程概念,包括赋值、函数、循环等。掌握这些基本概念后,在后面的实践中将会慢慢体会如何利用这些知识来解决各种实际问题。