2.1 R语言
R提供了一种完善的编程语言。类似计算机的高级语言,R用户只需要熟悉其命令、语句及简单的语法规则,就可以做数据管理和分析处理工作。因此,掌握R编程技术是学习R的关键环节。在R中,把大部分常用的复杂数据计算的算法作为标准函数调用,用户仅需要指出函数名及其必要的参数即可。这一特点使得R编程十分简单。
R是一种解释性语言,输入后可直接给出结果。R功能靠函数实现。函数形式如下:
函数(输入数据,参数=)
如果没有指定,则参数以默认值为准。
例如:平均值mean(x, trim=0, na.rm=FALSE, ...),线性模型lm(y~x, data=test)。
每一个函数执行特定的功能,后面紧跟括号,例如:平均值mean()、求和sum()、绘图plot()、排序sort()。
除了基本的运算之外,R的函数又分为“高级”和“低级”函数,高级函数可调用低级函数,这里的“高级”函数习惯上称为泛型函数。如plot()就是泛型函数,可以根据数据的类型,调用底层的函数,应用相应的方法绘制相应的图形。这就是面向对象编程的思想。
2.1.1 数据集的概念
创建含有研究信息的数据集,这是任何数据分析的第一步。在R中,这个任务包括以下两步。
·选择一种数据结构来存储数据。
·将数据输入或导入这个数据结构中。
数据集通常是由数据构成的一个矩形数组,行表示观测,列表示变量。不同的行业对于数据集的行和列叫法不同,包括观测和变量、记录和字段、示例和属性。
R可以处理的数据类型包括数值型、字符型、逻辑型(TRUE/FALSE)、复数型(虚数)和因子型,实例如下。
·数值型:如100,0,−4.335。
·字符型:如“China”。
·逻辑型:如TRUE,FALSE。
·复数型:如2+3i。
·因子型:表示不同类别。因子是名义型变量或有序型变量,它们在R中被特殊地存储和处理。
R中有许多用于存储数据的结构,包括标量、向量、数组、数据框和列表。多样化的数据结构赋予了R极其灵活的数据处理能力,各种类型的数据是由各元素组成的。
注意:标量是只含一个元素的向量,例如f <−3、g <−"US"和h <−TRUE。它们用于保存常量。
重点提示:与其他标准统计软件中的数据集类似,数据框是R中用于存储数据集的一种主要数据结构:列表示变量,行表示观测。在同一个数据框中可以存储不同类型(如数值型、字符型)的变量。
(1)向量。
向量为一系列元素的组合,用于存储数值型、字符型或逻辑型数据的一维数组。执行组合功能的函数c()可用来创建向量,各类向量如下所示:
a <- c(1, 2, 3, 4, 10, -9, 20) b <- c("one", "two", "three") c <- c(TURE, FALSE, TRUE, TRUE, FALSE, FALSE) d <- c("a", "a", "b", "b", "c")
其中,a是数值型向量,b和d是字符型向量,而c是逻辑型向量。
重点提示:单个向量中的数据必须拥有相同的类型或模式(数值型、字符型或逻辑型),同一向量中无法混杂不同模式的数据。
通过在方括号中给定元素所处位置的数值访问向量中的元素。例如,a[c(1, 4)]用于访问向量a中的第1个和第4个元素。更多示例如下:
> d <- c(1, 3, 5, 9,7, 10, 23, 21, 17) > d[2] [1] 3 > d[2:5] [1] 3 5 9 7 > d[c(1,2,6,7)] [1] 1 3 10 23
第2个语句中使用的冒号用于生成一个数值序列,d[2:5]相当于d[c(2, 3, 4, 5)]。
(2)矩阵。
矩阵是一个二维数组,只是每个元素都拥有相同的模式(数值型、字符型或逻辑型),可通过函数matrix创建矩阵。一般使用格式如下:
mymatrix <- matrix (vector, nrow=, ncol=, byrow=, dimnames=list() )
其中,vector包含了矩阵的元素,nrow和ncol用以指定行和列的维数,dimnames包含了可选的、以字符型向量表示的行名和列名。选项byrow则表明矩阵应当按行填充(byrow=TRUE)还是按列填充(byrow=FALSE),默认情况下按列填充。
> x <- matrix(21:40, nrow=4, ncol=5, byrow=FALSE) > x [,1] [,2] [,3] [,4] [,5] [1,] 21 25 29 33 37 [2,] 22 26 30 34 38 [3,] 23 27 31 35 39 [4,] 24 28 32 36 40 > fourcell <- c(1,2,3,10,20,30) > rnames <- c("R1", "R2") > cnames <- c("C1", "C2", "C3") > mymatrix <- matrix (fourcell, nrow=2, ncol=3, byrow=TRUE, dimnames=list(rnames, cnames)) > mymatrix C1 C2 C3 R1 1 2 3 R2 10 20 30 > mymatrix1 <- matrix (fourcell, nrow=2, ncol=3, byrow=FALSE, dimnames=list(rname s, cnames)) > mymatrix1 C1 C2 C3 R1 1 3 20 R2 2 10 30
我们首先创建了一个4×5的矩阵,接着创建了一个2×3的含列名标签的矩阵并按行进行填充,最后创建了一个2×3的矩阵并按列进行了填充。
我们可以使用下标和方括号来选择矩阵中的行、列或元素。X[i,]指矩阵X中的第i行,X[,j]指第j列,X[i, j]指第i行第j个元素。选择多行或多列时,下标i和j可为数值型向量。
> aa <-matrix(1:20, nrow=5) > aa [,1] [,2] [,3] [,4] [1,] 1 6 11 16 [2,] 2 7 12 17 [3,] 3 8 13 18 [4,] 4 9 14 19 [5,] 5 10 15 20 > aa[3,] [1] 3 8 13 18 > aa[,3] [1] 11 12 13 14 15 > aa[3,3] [1] 13 > aa[3,c(3,4)] [1] 13 18 > aa[,c(3,4)] [,1] [,2] [1,] 11 16 [2,] 12 17 [3,] 13 18 [4,] 14 19 [5,] 15 20
首先,我们创建了一个内容为数字1~20的5×4矩阵。默认情况下,矩阵按列填充。然后分别选择了第3行和第3列的元素。接着,又选择了第3行第3列的元素。之后选择了位于第3行第3、第4列的元素。最后选择了第3列和第4列的元素。
矩阵都是二维的,与向量类似,矩阵中也仅能包含一种数据类型。当维度超过2时,需要使用数组;当有多种模式的数据时,需要使用数据框。
(3)数组。
数组与矩阵类似,但其维度可大于2。数组可通过array函数创建,形式如下:
setarray <- array (vector, dimensions, dimnames)
其中,vector包含了数组中的数据;dimensions是一个数值型向量,给出了各个维度下标的最大值;而dimnames是可选的、各维度名称标签的列表。
> dim1 <- c("X1", "X2") > dim2 <- c("Y1", "Y2", "Y3") > dim3 <- c("Z1", "Z2", "Z3", "Z4") > xyz <- array(1:24, c(4,3,2), dimnames=list(dim3, dim2, dim1)) > xyz , , X1 Y1 Y2 Y3 Z1 1 5 9 Z2 2 6 10 Z3 3 7 11 Z4 4 8 12 , , X2 Y1 Y2 Y3 Z1 13 17 21 Z2 14 18 22 Z3 15 19 23 Z4 16 20 24
数组是矩阵的一个自然推广,它们在编写新的统计方法时可能很有用。像矩阵一样,数组中的数据也只能拥有一种模式。
从数组中选取元素的方式与矩阵相同。
> xyz[1,2,] X1 X2 5 17 > xyz[1,3,] X1 X2 9 21 > xyz[,2,2] Z1 Z2 Z3 Z4 17 18 19 20 > xyz[3,2,1] [1] 7
(4)数据框。
与通常在SAS、SPSS和STATA中看到的数据集类似,不同的列可以包含不同模式(数值型、字符型等)的数据,也将是R中最常处理的数据结构。如果数据有多种模式,无法将此数据集放入一个矩阵,在这种情况下,使用数据框是最佳选择。数据框可通过函数data.frame()创建:
mydata <- data.frame(col1, col2, col3, …)
其中,列向量col1, col2, col3,…可为任何类型(如字符型、数值型或逻辑型)。
> IDnumber <- c(101, 102, 103, 104) > age <- c(24, 78, 56, 45) > hypertention <- c("yes", "no", "no","yes") > severity <- c("high", "middle", "low", "middle") > patientdata <- data.frame(IDnumber, age, hypertention, severity) > patientdata IDnumber age hypertention severity 1 101 24 yes high 2 102 78 no middle 3 103 56 no low 4 104 45 yes middle
选取数据框中元素的方式有若干种,既可以使用前述下标记号,也可以直接指定列名。
> patientdata[1] IDnumber 1 101 2 102 3 103 4 104 > patientdata[1:2] IDnumber age 1 101 24 2 102 78 3 103 56 4 104 45 > patientdata["age"] age 1 24 2 78 3 56 4 45 > patientdata[c("age", "severity")] age severity 1 24 high 2 78 middle 3 56 low 4 45 middle > patientdata$age [1] 24 78 56 45
记号$是新出现的使用方法,它被用来选取一个给定数据框中的某个特定变量。在每个变量名前都输入一次数据框名可能会让人生厌,所以不妨走一些捷径,可以联合使用函数attach()和detach(),或单独使用函数with()来简化代码。
函数attach()可将数据框添加到R的搜索路径中。R在遇到一个变量名以后,将检查搜索路径中的数据框,以定位到这个变量。使用以下代码获取年龄(age)变量的描述性统计量,并分别绘制此变量与收缩压(hypertension)的散点图。
> systolic <- c(120, 130, 140, 150, 160) > age <- c(20, 30, 40, 50, 55) > hypertension <- data.frame(systolic, age) > hypertension systolic age 1 120 20 2 130 30 3 140 40 4 150 50 5 160 55 > summary(hypertension$age) > summary(hypertension$systolic) > plot(hypertension$systolic, hypertension$age)
上述代码也可以改写成:
> attach(hypertension) > summary(age) > summary(systolic) > plot(systolic, age) > detach(hypertension)
函数detach()将数据框从搜索路径中移除。detach()并不会对数据框本身做任何处理,这句是可以省略的。
当名称相同的对象不止一个时,这种方法的局限性就很明显了,原始对象将进行优先运算。函数attach()和detach()最好在分析一个单独的数据框,并且不太可能有多个同名对象时使用。
除此之外,另一种方式是使用函数with()。可以这样重写上例:
> with(hypertension,{ summary(age) summary(systolic) plot(systolic, age) })
大括号{}之间的语句都针对数据框hypertension执行,这样就不用担心名称冲突了。如果仅有一条语句,那么大括号{}可以省略。函数with()的局限性在于赋值仅在此函数的括号内生效。如下代码所示:
> with (hypertension, {stat <-summary(age) +stat}) Min. 1st Qu. Median Mean 3rd Qu. Max. 20 30 40 39 50 55 > stat 错误:找不到对象'stat'
重点提示:如果你需要创建在with()结构以外存在的对象,使用特殊赋值符“<<−”替代标准赋值符“<−”即可,它可将对象保存到with()之外的全局环境中。
以下代码较好地阐述了这个原因:
> with (hypertension, {nonstat <-summary(systolic) stat <<-summary(systolic) }) > nonstat 错误: 找不到对象'nonstat' > stat Min. 1st Qu. Median Mean 3rd Qu. Max. 120 130 140 140 150 160
(5)因子。
变量可分为名义型、有序型或连续型变量。名义型变量是没有顺序之分的类别变量;有序型变量表示一种顺序关系,而非数量关系;连续型变量可以呈现为某个范围内的任意值并同时表示了顺序和数量。年龄就是一个连续型变量。类别(名义型)变量和有序类别(有序型)变量在R中称为因子。因子在R中非常重要,因为它决定了数据的分析方式以及如何进行结果展示。因子在R语言中具有许多强大运算的基础,包括许多针对表格数据的运算。因子的设计思想来源于统计学中的名义变量或分类变量,这些变量本质上不是数字,而是对应分类。例如血型,尽管可以用数字对它们进行编码。
函数factor()以一个整数向量的形式存储类别值,将一个由字符串(原始值)组成的内部向量映射到这些整数上。
> hypertention <- c("yes", "no", "no","yes") > hypertention <- factor(hypertention ) > hypertention [1] yes no no yes Levels: no yes > str(hypertention) Factor w/ 2 levels "no","yes": 2 1 1 2
语句hypertention <−factor(hypertention )将此向量存储为(2, 1, 1, 2),并在内部将其关联为1=no和2=yes(具体赋值根据字母顺序而定)。针对向量hypertention进行的任何分析都会将其作为名义型变量对待并自动选择合适的统计方法。
在R中,因子可以简单地看作一个附加更多信息的向量(尽管它们内部机理是不同的)。这额外的信息包括向量中不同值的记录,称为“水平”。
> x <-c(5,12,13,12) > x <-factor(x) > x [1] 5 12 13 12 Levels: 5 12 13 > str(x) Factor w/ 3 levels "5","12","13": 1 2 3 2 > length(x) [1] 4
x中的不同数值(5, 12, 13)就是水平。x的核心是(1,2,3,2),意味着我们的数据是由水平1、水平2和水平3的值构成的。因此数据已经重新编码为水平,当然水平本身也被记录。因子的长度定义为数据的长度,而不是水平的个数。
要表示有序型变量,需要为函数factor()指定参数ordered=TRUE。
> severity <- c("high", "middle", "low", "middle") > severity <- factor(severity, order=TRUE) > severity [1] high middle low middle Levels: high < low < middle > str(severity) Ord.factor w/ 3 levels "high"<"low"<"middle": 1 3 2 3
语句severity <− factor(severity, order=TRUE)将向量编码为(1, 3, 2, 3),并在内部将这些值关联为1=high、2=low以及3=middle。另外,针对此向量进行的任何分析都会将其作为有序型变量对待,并自动选择合适的统计分析方法。
对于字符型向量,因子的水平默认依字母顺序创建。这对于因子severity是没有意义的,因为“high”“low”“middle”的排序方式与逻辑顺序不一致。按默认的字母顺序排序的因子很少能够让人满意。
可以通过指定levels选项来覆盖默认排序。
> severity <- factor(severity, order=TRUE, levels=c("low", "middle", "high"))
以下代码展现了因子如何影响数据分析结果。
> IDnumber <- c(101, 102, 103, 104) > age <- c(24, 78, 56, 45) > hypertention <- c("yes", "no", "no","yes") > severity <- c("high", "middle", "low", "middle") > hypertention <- factor(hypertention) > severity <- factor(severity, order=TRUE) > patientdata <- data.frame(IDnumber, age, hypertention, severity) > str(patientdata) 'data.frame': 4 obs. of 4 variables: $ IDnumber : num 101102 103104 $ age : num 24 78 56 45 $ hypertention: Factor w/ 2 levels "no","yes": 2 1 1 2 $ severity : Ord.factor w/ 3 levels "high"<"low"<"middle": 1 3 2 3 > summary(patientdata) IDnumber age hypertention severity Min. :101.0 Min. :24.00 no :2 high :1 1st Qu.:101.8 1st Qu.:39.75 yes:2 low :1 Median :102.5 Median :50.50 middle:2 Mean :102.5 Mean :50.75 3rd Qu.:103.2 3rd Qu.:61.50
Max. :104.0 Max. :78.00
(6)列表。
列表就是一些对象(或成分)的有序集合,是R数据类型中最为复杂的一种。列表允许整合若干(可能无关的)对象到单个对象名下。例如,某个列表中可能是若干向量、矩阵、数据框,甚至其他列表的组合。用户可以使用函数list()创建列表:
Mylist <- list(object1, object2, …)
以下为创建列表的一个示例:
> a <- "list example" > x <- c(1,2,3,4,5) > matrix <- matrix(1:20, nrow=5, byrow=FALSE) > k <- c("one", "two", "four") > mylist <- list(a, x, matrix, k) > mylist [[1]] [1] "list example" [[2]] [1] 1 2 3 4 5 [[3]] [,1] [,2] [,3] [,4] [1,] 1 6 11 16 [2,] 2 7 12 17 [3,] 3 8 13 18 [4,] 4 9 14 19 [5,] 5 10 15 20 [[4]] [1] "one" "two" "four"
本例创建了一个列表,其中有4个成分:1个字符串、1个数值型向量、1个矩阵以及1个字符型向量。用户可以组合任意多的对象,并将它们保存为一个列表。
用户也可以通过在双重方括号中指明代表某个成分的数字或名称来访问列表中的元素。
> mylist[[3]] [,1] [,2] [,3] [,4] [1,] 1 6 11 16 [2,] 2 7 12 17 [3,] 3 8 13 18 [4,] 4 9 14 19 [5,] 5 10 15 20
在此例中,mylist[[3]]指矩阵。由于两个原因,列表成为了R中的重要数据结构。首先,列表允许以一种简单的方式组织和重新调用不相干的信息。其次,许多R函数的运行结果都是以列表的形式返回的,由分析人员决定需要取出其中哪些成分。
2.1.2 R运算符
R运算符是一些符号,它们要求作比较,进行算术运算、比较运算或逻辑运算等。
1.算术算符
指数学运算中常用的5种运算符号。算术算符的表示方法及其含义如表2-1所示。
表2-1 算术算符
2.比较算符
建立两个量之间的一种关系,并要求R确定这种关系是否成立。如果成立,输出的运算结果是1;如果不成立,运算结果为0。比较算符的表示方法及其含义如表2-2所示。
表2-2 比较算符
如表达式X<Y。如果X为5,Y为2,那么表达式X<Y的值为0(不成立)。如果X为5,Y为9,那么X<Y的值为1(成立)。
3.逻辑算符
通常用来连接一系列比较式。逻辑算符包括:& AND(与)、|OR(或)和!NOT(非)。逻辑算符的表示方法及其含义如表2-3所示。
表2-3 逻辑算符
如果“&”左右两个量都为真,那么AND运算产生的结果为1,否则为0。例如表达式:X<Y and C>0为真,仅当X<Y为真且C>0为真时,也就是当X<Y且C>0为真时,结果为1。
如果“|”两边的量至少有一个为真,那么“|”运算的结果是1,否则是0。例如,表达式X<Y | C>0为真,仅当X<Y为真而不必管C的值,或者C>0为真而不管X<Y是否为真,也就是说,这两个关系式中有一个或两个都成立时,这个表达式为真。
“!”也是一个逻辑算符。在一个值为0的量前面放上“!”的结果是1。也就是否定一个假的结果为真。例如,如果A=B为假,那么!(A=B)为真。在一个缺失值的量前面放上“!”结果也为真。相反,否定一个真的结果就是假的。
R语言表面上没有标量的类型,因为标量可以看作是含有一个元素的向量,但如表2-3所示,逻辑运算符对标量和向量有着不同的形式。下面以一个简单的例子阐述这种区别的必要性。
> x <- c(TRUE, FALSE, TRUE) > y <-c (TRUE,TRUE,FALSE) > x & y [1] TRUE FALSE FALSE > x[1 ]&& y[1] [1] TRUE > x && y [1] TRUE > if (x[1 ]&& y[1]) +print("both TURE") [1] "both TURE" > if (x & y) +print("both TURE") [1] "both TURE" Warning message:
if (x & y) print("both TURE"):条件的长度大于一,因此只能用其第一元素。
if结构条件判断语句的取值,只能是一个逻辑值,而不是逻辑值的向量,这也是为什么会出现警告提示。因此,“&”和“&&”这两种运算符的存在是必要的。
重点提示:逻辑值TRUE和FALSE可以缩写为T和F(必须大写),而在算术表达式中它们会转换为1和0。
> 1<2 [1] TRUE > (1<2) *(3<4) [1] 1 > (1<2) *(3<4) *(5<1) [1] 0 > (1<2) *(3<4) *(5<1) *(5<1) [1] 0 > (3<4)==TRUE [1] TRUE > (3<4)==1 [1] TRUE
4.运算次序
下面给出复杂表达式运算次序的准则。
(1)括号里的表达式先计算。
(2)较高优先级的运算先被执行。优先级的顺序如表2-4所示。
(3)对于相同优先级的算符,先做左边的运算。
表2-4 R中各种算符的优先顺序