数据集的概念 数据集通常是由数据构成的一个矩形数组,行表示观测,列表示变量。表2-1提供了一个假想的病例数据集。
不同的行业对于数据集的行和列叫法不同。统计学家称它们为观测(observation)和变量
(variable),数据库分析师则称其为记录(record)和字段(field),数据挖掘和机器学习学科的研
究者则把它们叫作示例(example)和属性(attribute)。
我们在R中使用术语:观测和变量。可以清楚地看到此数据集的结构(本例中是一个矩形数组)以及其中包含的内容和数据类型。在表2-1所示的数据集中,PatientID是行/实例标识符,AdmDate是日期型变量,Age是连续型变量,Diabetes是名义型变量,Status是有序型变量。
R中有许多用于存储数据的结构,包括标量、向量、数组、数据框和列表。表2-1实际上对应
着R中的一个数据框。多样化的数据结构赋予了R极其灵活的数据处理能力。
R可以处理的数据类型(模式)包括数值型、字符型、逻辑型(TRUE/FALSE)、复数型(虚
数)和原生型(字节)。在R中,PatientID、AdmDate和Age为数值型变量,而Diabetes和Status
则为字符型变量。另外,你需要分别告诉R:PatientID是实例标识符,AdmDate含有日期数据,
Diabetes和Status分别是名义型和有序型变量。R将实例标识符称为rownames(行名),将类
别型(包括名义型和有序型)变量称为因子(factors)。
数据框(data frame)是R中用于存储数据的一种结构:列表示变量,行表示观测。在同一个数据框中可以存储不同类型(如数值型、字符型)的变量。数据框将是你用来存储数据集的主要数据结构。
因子(factor)是名义型变量或有序型变量。它们在R中被特殊地存储和处理。
向量是用于存储数值型、字符型或逻辑型数据的一维数组。执行组合功能的函数c()可用来
创建向量。各类向量如下例所示:
a <- c(1, 2, 5, 3, 6, -2, 4) print(a) b <- c("one", "two", "three") print(b) c <- c(TRUE, TRUE, TRUE, FALSE, TRUE, FALSE) print(c)
这里,a是数值型向量,b是字符型向量,而c是逻辑型向量。注意,单个向量中的数据必须
拥有相同的类型或模式(数值型、字符型或逻辑型)。同一向量中无法混杂不同模式的数据。
标量是只含一个元素的向量,例如f <- 3、g <- "US"和h <- TRUE。它们用于保存 常量。
通过在方括号中给定元素所处位置的数值,我们可以访问向量中的元素。例如,a[c(2, 4)]
用于访问向量a中的第二个和第四个元素。更多示例如下:
a <- c("k", "j", "h", "a", "c", "m") print(a) print(a[3]) a[c(1, 3, 5)] a[2:6]
最后一个语句中使用的冒号用于生成一个数值序列。例如,a <- c(2:6)等价于a <- c(2, 3, 4, 5, 6)
矩阵 矩阵是一个二维数组,只是每个元素都拥有相同的模式(数值型、字符型或逻辑型)。可通过函数matrix()创建矩阵。一般使用格式为: myymatrix <- matrix(vector,
nrow=number_of_rows,
ncol=number_of_columns, byrow=logical_value,
dimnames=list( char_vector_rownames, char_vector_colnames)
)
其中vector包含了矩阵的元素,nrow和ncol用以指定行和列的维数,dimnames包含了可选 的、以字符型向量表示的行名和列名。选项byrow则表明矩阵应当按行填充(byrow=TRUE) 还是按列填充(byrow=FALSE),默认情况下按列填充。
y <- matrix(1:20, nrow=5, ncol=4) y cells <- c(1,26,24,68) rnames <- c("R1", "R2") cnames <- c("C1", "C2") #按行填充的2×2矩阵 mymatrix <- matrix(cells, nrow=2, ncol=2, byrow=TRUE, dimnames=list(rnames, cnames)) mymatrix #按列填充的2×2矩阵 mymatrix <- matrix(cells, nrow=2, ncol=2, byrow=FALSE, dimnames=list(rnames, cnames)) mymatrix
可以使用下标和方括号来选择矩阵中的行、列或元素。X[i,]指矩阵X中的第i行,X[,j]指第j列,X[i, j]指第i行第j 个元素。选择多行或多列时,下标i和j可为数值型向量
x <- matrix(1:10, nrow=2) x x[2,] x[,2] x[1,4] x[1, c(4,5)]
创建了一个内容为数字1到10的2×5矩阵。默认情况下,矩阵按列填充。然后,
分别选择了第二行和第二列的元素。接着,又选择了第一行第四列的元素。最后选择了位于第
一行第四、第五列的元素。
矩阵都是二维的,和向量类似,矩阵中也仅能包含一种数据类型。当维度超过2时,使
用数组。当有多种模式的数据时,可以使用数据框。
数组 数组(array)与矩阵类似,但是维度可以大于2。数组可通过array函数创建,形式如下: myarray <- array(vector, dimensions, dimnames) 其中vector包含了数组中的数据,dimensions是一个数值型向量,给出了各个维度下标的最大 值,而dimnames是可选的、各维度名称标签的列表。
dim1 <- c("A1", "A2") dim2 <- c("B1", "B2", "B3") dim3 <- c("C1", "C2", "C3", "C4") z <- array(1:24, c(2, 3, 4), dimnames=list(dim1, dim2, dim3)) z
数组是矩阵的一个自然推广。它们在编写新的统计方法时可能很有用。像矩阵一
样,数组中的数据也只能拥有一种模式。从数组中选取元素的方式与矩阵相同
数据框 由于不同的列可以包含不同模式(数值型、字符型等)的数据,数据框的概念较矩阵来说更为一般。 病例数据集包含了数值型和字符型数据。由于数据有多种模式,无法将此数据 集放入一个矩阵。在这种情况下,使用数据框是最佳选择。 数据框可通过函数data.frame()创建: mydata <- data.frame(col1, col2, col3,...) 其中的列向量col1、col2、col3等可为任何类型(如字符型、数值型或逻辑型)。每一列的名 称可由函数names指定。
patientID <- c(1, 2, 3, 4) age <- c(25, 34, 28, 52) diabetes <- c("Type1", "Type2", "Type1", "Type1") status <- c("Poor", "Improved", "Excellent", "Poor") patientdata <- data.frame(patientID, age, diabetes, status) patientdata
每一列数据的模式必须唯一,不过你却可以将多个模式的不同列放到一起组成数据框。由于数据框与分析人员通常设想的数据集的形态较为接近,我们在讨论数据框时将交替使用术语列和变量。
选取数据框中元素的方式有若干种。你可以使用前述(如矩阵中的)下标记号,亦可直接指
定列名。
patientdata[1:2] patientdata[c("diabetes","status")] patientdata$age
函数attach()可将数据框添加到R的搜索路径中。R在遇到一个变量名以后,将检查搜索路 6 径中的数据框。以mtcars数据框为例,可以使用以下代码获取每加仑行驶英里数(mpg)变量的描述性统计量,并分别绘制此变量与发动机排量(disp)和车身重量(wt)的散点图:
summary(mtcars$mpg)
plot(mtcars$mpg, mtcars$disp)
plot(mtcars$mpg, mtcars$wt)
以上代码也可写成:
attach(mtcars)
summary(mpg)
plot(mpg, disp)
plot(mpg, wt)
detach(mtcars)
函数detach()将数据框从搜索路径中移除。值得注意的是,detach()并不会对数据框本身
做任何处理。这句是可以省略的,但其实它应当被例行地放入代码中,因为这是一个好的编程习惯。
当名称相同的对象不止一个时,这种方法的局限性就很明显了。
这里,在数据框mtcars被绑定(attach)之前,你们的环境中已经有了一个名为mpg的对象。
在这种情况下,原始对象将取得优先权,这与你们想要的结果有所出入。由于mpg中有3个元素
而disp中有32个元素,故plot语句出错。函数attach()和detach()最好在你分析一个单独的
数据框,并且不太可能有多个同名对象时使用。任何情况下,都要当心那些告知某个对象已被屏
蔽(masked)的警告。
除此之外,另一种方式是使用函数with()。可以这样重写上例:
with(mtcars, { print(summary(mpg)) plot(mpg, disp) plot(mpg, wt) })
在这种情况下,花括号{}之间的语句都针对数据框mtcars执行,这样就无需担心名称冲突
了。如果仅有一条语句(例如summary(mpg)),那么花括号{}可以省略。
如果你需要创建在with()结构以外存在的对象,使用特殊赋值符<<-替代标准赋值符(<-)
即可,它可将对象保存到with()之外的全局环境中。这一点可通过以下代码阐明:
实例标识符 在病例数据中,病人编号(patientID)用于区分数据集中不同的个体。在R中,实例标识 符(case identifier)可通过数据框操作函数中的rowname选项指定。例如,语句: patientdata <- data.frame(patientID, age, diabetes, status, row.names=patientID) 将patientID指定为R中标记各类打印输出和图形中实例名称所用的变量。
变量可归结为名义型、有序型或连续型变量。名义型变量是没有顺序之分的类别 变量。糖尿病类型Diabetes(Type1、Type2)是名义型变量的一例。即使在数据中Type1编码 为1而Type2编码为2,这也并不意味着二者是有序的。有序型变量表示一种顺序关系,而非数量 关系。病情Status(poor、improved、excellent)是顺序型变量的一个上佳示例。我们明 白,病情为poor(较差)病人的状态不如improved(病情好转)的病人,但并不知道相差多少。 连续型变量可以呈现为某个范围内的任意值,并同时表示了顺序和数量。年龄Age就是一个连续 型变量,它能够表示像14.5或22.8这样的值以及其间的其他任意值。很清楚,15岁的人比14岁的 人年长一岁。 类别(名义型)变量和有序类别(有序型)变量在R中称为因子(factor)。因子在R中非 的例子。 常重要,因为它决定了数据的分析方式以及如何进行视觉呈现。你将在本书中通篇看到这样 函数factor()以一个整数向量的形式存储类别值,整数的取值范围是[1...k](其中k是名义 型变量中唯一值的个数),同时一个由字符串(原始值)组成的内部向量将映射到这些整数上。 举例来说,假设有向量: diabetes <- c("Type1", "Type2", "Type1", "Type1") 语句diabetes <- factor(diabetes)将此向量存储为(1, 2, 1, 1),并在内部将其关联为 1=Type1和2=Type2(具体赋值根据字母顺序而定)。针对向量diabetes进行的任何分析都会将其 作为名义型变量对待,并自动选择适合这一测量尺度①的统计方法。 要表示有序型变量,需要为函数factor()指定参数ordered=TRUE。给定向量: status <- c("Poor", "Improved", "Excellent", "Poor") 语句status <- factor(status, ordered=TRUE)会将向量编码为(3, 2, 1, 3),并在内部 将这些值关联为1=Excellent、2=Improved以及3=Poor。另外,针对此向量进行的任何分析都会将 其作为有序型变量对待,并自动选择合适的统计方法。 对于字符型向量,因子的水平默认依字母顺序创建。这对于因子status是有意义的,因为 “Excellent”“Improved”“Poor”的排序方式恰好与逻辑顺序相一致。如果“Poor”被编码为 “Ailing”,会有问题,因为顺序将为“Ailing”“Excellent”“Improved”。如果理想中的顺序是“Poor” “Improved”“Excellent”,则会出现类似的问题。按默认的字母顺序排序的因子很少能够让人满意。 你可以通过指定levels选项来覆盖默认排序。例如: status <- factor(status, order=TRUE, levels=c("Poor", "Improved", "Excellent")) 各水平的赋值将为1=Poor、2=Improved、3=Excellent。请保证指定的水平与数据中的真实值 相匹配,因为任何在数据中出现而未在参数中列举的数据都将被设为缺失值。 数值型变量可以用levels和labels参数来编码成因子。如果男性被编码成1,女性被编码 成2,则以下语句: sex <- factor(sex, levels=c(1, 2), labels=c("Male", "Female")) 把变量转换成一个无序因子。注意到标签的顺序必须和水平相一致。在这个例子中,性别将被当 成类别型变量,标签“Male”和“Female”将替代1和2在结果中输出,而且所有不是1或2的性别 变量将被设为缺失值。
patientID <- c(1, 2, 3, 4) age <- c(25, 34, 28, 52) diabetes <- c("Type1", "Type2", "Type1", "Type1") status <- c("Poor", "Improved", "Excellent", "Poor") diabetes <- factor(diabetes) status <- factor(status, order=TRUE) patientdata <- data.frame(patientID, age, diabetes, status) str(patientdata) summary(patientdata)
首先,以向量的形式输入数据。然后,将diabetes和status分别指定为一个普通因子和
一个有序型因子。最后,将数据合并为一个数据框。函数str(object)可提供R中某个对象(本
例中为数据框)的信息。它清楚地显示diabetes是一个因子,而status是一个有序型因子,
以及此数据框在内部是如何进行编码的。注意,函数summary()会区别对待各个变量。它显示
了连续型变量age的最小值、最大值、均值和各四分位数,并显示了类别型变量diabetes和
status(各水平)的频数值。
列表 列表(list)是R的数据类型中最为复杂的一种。一般来说,列表就是一些对象(或成分, component)的有序集合。列表允许你整合若干(可能无关的)对象到单个对象名下。例如, 某个列表中可能是若干向量、矩阵、数据框,甚至其他列表的组合。可以使用函数list()创 建列表: mylist <- list(object1, object2, ...) 其中的对象可以是目前为止讲到的任何结构。你还可以为列表中的对象命名: mylist <- list(name1=object1, name2=object2, ...)
g <- "My First List" h <- c(25, 26, 18, 39) j <- matrix(1:10, nrow=5) k <- c("one", "two", "three") mylist <- list(title=g, ages=h, j, k) mylist
本例创建了一个列表,其中有四个成分:一个字符串、一个数值型向量、一个矩阵以及一个 字符型向量。可以组合任意多的对象,并将它们保存为一个列表。 你也可以通过在双重方括号中指明代表某个成分的数字或名称来访问列表中的元素。此例 中,mylist[[2]]和mylist[["ages"]]均指那个含有四个元素的向量。对于命名成分, mylist$ages也可以正常运行。由于两个原因,列表成为了R中的重要数据结构。首先,列表允 许以一种简单的方式组织和重新调用不相干的信息。其次,许多R函数的运行结果都是以列表的 形式返回的。需要取出其中哪些成分由分析人员决定。