第 2 章 创建数据集

第 2 章 创建数据集

本章内容

  • 探索R中的数据结构

  • 输入数据

  • 导入数据

  • 标注数据

按照个人要求的格式来创建含有研究信息的数据集,这是任何数据分析的第一步。在R中,这个任务包括以下两步:

  • 选择一种数据结构来存储数据;

  • 将数据输入或导入到这个数据结构中。

本章的第一部分(2.1~2.2节)叙述了R中用于存储数据的多种结构。其中,2.2节描述了向量、因子、矩阵、数据框以及列表的用法。熟悉这些数据结构(以及访问其中元素的表述方法)将十分有助于了解R的工作方式,因此你可能需要耐心消化这一节的内容。

本章的第二部分(2.3节)涵盖了多种向R中导入数据的可行方法。可以手工输入数据,亦可从外部源导入数据。数据源可为文本文件、电子表格、统计软件和各类数据库管理系统。举例来说,我在工作中使用的数据往往来自于SQL数据库。偶尔,我也会接受从DOS时代遗留下的数据,或是从现有的SAS和SPSS中导出的数据。通常,你仅仅需要本节中描述的一两种方法,因此根据需求有选择地阅读即可。

创建数据集后,往往需要对它进行标注,也就是为变量和变量代码添加描述性的标签。本章的第三部分(2.4节)将讨论数据集的标注问题,并介绍一些处理数据集的实用函数(2.5节)。下面我们从基本知识讲起。

2.1 数据集的概念

数据集通常是由数据构成的一个矩形数组,行表示观测,列表示变量。表2-1提供了一个假想的病例数据集。

表 2-1 病例数据

病人编号
(PatientID)

入院时间
(AdmDate)

年龄
(Age)

糖尿病类型
(Diabetes)

病情
(Status)

1

10/15/2009

25

Type 1

Poor

2

11/01/2009

34

Type 2

Improved

3

10/21/2009

28

Type 1

Excellent

4

10/28/2009

52

Type 1

Poor

不同的行业对于数据集的行和列叫法不同。统计学家称它们为观测(observation)和变量(variable),数据库分析师则称其为记录(record)和字段(field),数据挖掘和机器学习学科的研究者则把它们叫作示例(example)和属性(attribute)。我们在本书中通篇使用术语观测变量

你可以清楚地看到此数据集的结构(本例中是一个矩形数组)以及其中包含的内容和数据类型。在表2-1所示的数据集中,PatientID是行/实例标识符,AdmDate是日期型变量,Age是连续型变量,Diabetes是名义型变量,Status是有序型变量。

R中有许多用于存储数据的结构,包括标量、向量、数组、数据框和列表。表2-1实际上对应着R中的一个数据框。多样化的数据结构赋予了R极其灵活的数据处理能力。

R可以处理的数据类型(模式)包括数值型、字符型、逻辑型(TRUE/FALSE)、复数型(虚数)和原生型(字节)。在R中,PatientIDAdmDateAge为数值型变量,而DiabetesStatus则为字符型变量。另外,你需要分别告诉R:PatientID是实例标识符,AdmDate含有日期数据,DiabetesStatus分别是名义型和有序型变量。R将实例标识符称为rownames(行名),将类别型(包括名义型和有序型)变量称为因子(factors)。我们会在下一节中讲解这些内容,并在第3章中介绍日期型数据的处理。

2.2 数据结构

R拥有许多用于存储数据的对象类型,包括标量、向量、矩阵、数组、数据框和列表。它们在存储数据的类型、创建方式、结构复杂度,以及用于定位和访问其中个别元素的标记等方面均有所不同。图2-1给出了这些数据结构的一个示意图。

图 2-1 R中的数据结构

让我们从向量开始,逐个探究每一种数据结构。

一些定义

R中有一些术语较为独特,可能会对新用户造成困扰。

在R中,对象(object)是指可以赋值给变量的任何事物,包括常量、数据结构、函数,甚至图形。对象都拥有某种模式,描述了此对象是如何存储的,以及某个,像print这样的泛型函数表明如何处理此对象。

与其他标准统计软件(如SAS、SPSS和Stata)中的数据集类似,数据框(data frame)是R中用于存储数据的一种结构:列表示变量,行表示观测。在同一个数据框中可以存储不同类型(如数值型、字符型)的变量。数据框将是你用来存储数据集的主要数据结构。

因子(factor)是名义型变量或有序型变量。它们在R中被特殊地存储和处理。你将在2.2.5节中学习因子的处理。

其他多数术语你应该比较熟悉了,它们基本都遵循统计和计算中术语的定义。

2.2.1 向量

向量是用于存储数值型、字符型或逻辑型数据的一维数组。执行组合功能的函数c()可用来创建向量。各类向量如下例所示:

a <- c(1, 2, 5, 3, 6, -2, 4)
b <- c("one", "two", "three")
c <- c(TRUE, TRUE, TRUE, FALSE, TRUE, FALSE)

这里,a是数值型向量,b是字符型向量,而c是逻辑型向量。 注意,单个向量中的数据必须拥有相同的类型或模式(数值型、字符型或逻辑型)。同一向量中无法混杂不同模式的数据。

注意 标量是只含一个元素的向量,例如f <- 3g <- "US"h <- TRUE。它们用于保存常量。

通过在方括号中给定元素所处位置的数值,我们可以访问向量中的元素。例如,a[c(2, 4)]用于访问向量a中的第二个和第四个元素。更多示例如下:

> a <- c("k", "j", "h", "a", "c", "m")
> a[3]
[1] "h"
> a[c(1, 3, 5)]
[1] "k" "h" "c"
> a[2:6]
[1]  "j" "h" "a" "c" "m"

最后一个语句中使用的冒号用于生成一个数值序列。例如,a <- c(2:6)等价于a <- c(2, 3, 4, 5, 6)

2.2.2 矩阵

矩阵是一个二维数组,只是每个元素都拥有相同的模式(数值型、字符型或逻辑型)。可通过函数matrix()创建矩阵。一般使用格式为:

myymatrix <- matrix(vector, nrow=number_of_rows, ncol=number_of_columns,
                    byrow=logical_value, dimnames=list(
                    char_vector_rownames, char_vector_colnames))

其中vector包含了矩阵的元素,nrowncol用以指定行和列的维数,dimnames包含了可选的、以字符型向量表示的行名和列名。选项byrow则表明矩阵应当按行填充(byrow=TRUE)还是按列填充(byrow=FALSE),默认情况下按列填充。代码清单2-1中的代码演示了matrix函数的用法。

代码清单2-1 创建矩阵

> y <- matrix(1:20, nrow=5, ncol=4)     <-----❶创建一个5×4的矩阵
> y
     [,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
> cells    <- c(1,26,24,68)
> rnames   <- c("R1", "R2")
> cnames   <- c("C1", "C2")
> mymatrix <- matrix(cells, nrow=2, ncol=2, byrow=TRUE,  (以下2行)❷按行填充的2×2矩阵
                     dimnames=list(rnames, cnames))       
> mymatrix
   C1 C2
R1  1 26
R2 24 68
> mymatrix <- matrix(cells, nrow=2, ncol=2, byrow=FALSE,  (以下2行)❸按列填充的2×2矩阵
                     dimnames=list(rnames, cnames))          
> mymatrix
  C1 C2
R1  1 24
R2 26 68

我们首先创建了一个5×4的矩阵❶,接着创建了一个2×2的含列名标签的矩阵,并按行进行填充❷,最后创建了一个2×2的矩阵并按列进行了填充❸。

我们可以使用下标和方括号来选择矩阵中的行、列或元素。X[i,]指矩阵X中的第i行,X[,j]指第j列,X[i, j]指第 i 行第 j 个元素。选择多行或多列时,下标 ij 可为数值型向量,如代码清单2-2所示。

代码清单2-2 矩阵下标的使用

> x <- matrix(1:10, nrow=2)
> x
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    3    5    7    9
[2,]    2    4    6    8   10
> x[2,]
  [1]  2  4  6  8 10
> x[,2]
[1] 3 4
> x[1,4]
[1] 7
> x[1, c(4,5)]
[1] 7 9

首先,我们创建了一个内容为数字1到10的2×5矩阵。默认情况下,矩阵按列填充。然后,我们分别选择了第二行和第二列的元素。接着,又选择了第一行第四列的元素。最后选择了位于第一行第四、第五列的元素。

矩阵都是二维的,和向量类似,矩阵中也仅能包含一种数据类型。当维度超过2时,不妨使用数组(2.2.3节)。当有多种模式的数据时,你们可以使用数据框(2.2.4节)。

2.2.3 数组

数组(array)与矩阵类似,但是维度可以大于2。数组可通过array函数创建,形式如下:

myarray <- array(vector, dimensions, dimnames)

其中vector包含了数组中的数据,dimensions是一个数值型向量,给出了各个维度下标的最大值,而dimnames是可选的、各维度名称标签的列表。代码清单2-3给出了一个创建三维(2×3×4)数值型数组的示例。

代码清单2-3 创建一个数组

> 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
, , C1
   B1 B2 B3
A1  1  3  5
A2  2  4  6

, , C2
   B1 B2 B3
A1  7  9 11
A2  8 10 12

, , C3
   B1 B2 B3
A1 13 15 17
A2 14 16 18

, , C4
   B1 B2 B3
A1 19 21 23
A2 20 22 24

如你所见,数组是矩阵的一个自然推广。它们在编写新的统计方法时可能很有用。像矩阵一样,数组中的数据也只能拥有一种模式。从数组中选取元素的方式与矩阵相同。上例中,元素z[1,2,3]为15。

2.2.4 数据框

由于不同的列可以包含不同模式(数值型、字符型等)的数据,数据框的概念较矩阵来说更为一般。它与你通常在SAS、SPSS和Stata中看到的数据集类似。数据框将是你在R中最常处理的数据结构。

表2-1所示的病例数据集包含了数值型和字符型数据。由于数据有多种模式,无法将此数据集放入一个矩阵。在这种情况下,使用数据框是最佳选择。

数据框可通过函数data.frame()创建:

mydata <- data.frame(col1, col2, col3,...)

其中的列向量col1col2col3等可为任何类型(如字符型、数值型或逻辑型)。每一列的名称可由函数names指定。代码清单2-4清晰地展示了相应用法。

代码清单2-4 创建一个数据框

> 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
  patientID age diabetes    status
1         1  25    Type1      Poor
2         2  34    Type2  Improved
3         3  28    Type1 Excellent
4         4  52    Type1      Poor

每一列数据的模式必须唯一,不过你却可以将多个模式的不同列放到一起组成数据框。由于数据框与分析人员通常设想的数据集的形态较为接近,我们在讨论数据框时将交替使用术语变量

选取数据框中元素的方式有若干种。你可以使用前述(如矩阵中的)下标记号,亦可直接指定列名。代码清单2-5使用之前创建的patientdata数据框演示了这些方式。

代码清单2-5 选取数据框中的元素

> patientdata[1:2]
  patientID age
1         1  25
2         2  34
3         3  28
4         4  52
> patientdata[c("diabetes", "status")]
  diabetes    status
1    Type1      Poor
2    Type2  Improved
3    Type1 Excellent
4    Type1      Poor
 > patientdata$age     <----❶表示patientdata数据框中的变量age
[1] 25 34 28 52

第三个例子中的记号$是新出现的❶。它被用来选取一个给定数据框中的某个特定变量。例如,如果你想生成糖尿病类型变量diabetes和病情变量status的列联表,使用以下代码即可:

> table(patientdata$diabetes, patientdata$status)

        Excellent Improved Poor
  Type1         1        0    2
  Type2         0        1    0

在每个变量名前都键入一次patientdata$可能会让人生厌,所以不妨走一些捷径。可以联合使用函数attach()detach()或单独使用函数with()来简化代码。

1. attach()detach()with()

函数attach()可将数据框添加到R的搜索路径中。R在遇到一个变量名以后,将检查搜索路径中的数据框。以第1章中的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()并不会对数据框本身做任何处理。这句是可以省略的,但其实它应当被例行地放入代码中,因为这是一个好的编程习惯。(接下来的几章中,为了保持代码片段的简约和简短,我可能会不时地忽略这条良训。)

当名称相同的对象不止一个时,这种方法的局限性就很明显了。考虑以下代码:

> mpg <- c(25, 36, 47)
> attach(mtcars)
The following object(s) are masked _by_ '.GlobalEnv':   mpg
> plot(mpg, wt)
Error in xy.coords(x, y, xlabel, ylabel, log) :
  'x' and 'y' lengths differ
> mpg
[1] 25 36 47

这里,在数据框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(mtcars, {
   stats <- summary(mpg)
   stats
  })
   Min. 1st Qu.  Median    Mean 3rd Qu.   Max.
  10.40   15.43   19.20   20.09   22.80  33.90
> stats
Error: object 'stats' not found

如果你需要创建在with()结构以外存在的对象,使用特殊赋值符<<-替代标准赋值符(<-)即可,它可将对象保存到with()之外的全局环境中。这一点可通过以下代码阐明:

> with(mtcars, {
   nokeepstats <- summary(mpg)
   keepstats <<- summary(mpg)
})
> nokeepstats
Error: object 'nokeepstats' not found
> keepstats
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
    10.40   15.43   19.20   20.09   22.80   33.90

相对于attach(),多数的R书籍更推荐使用with()。个人认为从根本上说,选择哪一个是自己的偏好问题,并且应当根据你的目的和对于这两个函数含义的理解而定。本书中你们会交替使用这两个函数。

2. 实例标识符

在病例数据中,病人编号(patientID)用于区分数据集中不同的个体。在R中,实例标识符(case identifier)可通过数据框操作函数中的rowname选项指定。例如,语句:

patientdata <- data.frame(patientID, age, diabetes,
                          status, row.names=patientID)

patientID指定为R中标记各类打印输出和图形中实例名称所用的变量。

2.2.5 因子

如你所见,变量可归结为名义型、有序型或连续型变量。名义型变量是没有顺序之分的类别变量。糖尿病类型DiabetesType1Type2)是名义型变量的一例。即使在数据中Type1编码为1而Type2编码为2,这也并不意味着二者是有序的。有序型变量表示一种顺序关系,而非数量关系。病情Statuspoorimprovedexcellent)是顺序型变量的一个上佳示例。我们明白,病情为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进行的任何分析都会将其作为名义型变量对待,并自动选择适合这一测量尺度1的统计方法。

1这里的测量尺度是指定类尺度、定序尺度、定距尺度、定比尺度中的定类尺度。——译者注

要表示有序型变量,需要为函数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。请保证指定的水平与数据中的真实值相匹配,因为任何在数据中出现而未在参数中列举的数据都将被设为缺失值。

数值型变量可以用levelslabels参数来编码成因子。如果男性被编码成1,女性被编码成2,则以下语句:

sex <- factor(sex, levels=c(1, 2), labels=c("Male", "Female"))

把变量转换成一个无序因子。注意到标签的顺序必须和水平相一致。在这个例子中,性别将被当成类别型变量,标签“Male”和“Female”将替代1和2在结果中输出,而且所有不是1或2的性别变量将被设为缺失值。

代码清单2-6演示了普通因子和有序因子的不同是如何影响数据分析的。

代码清单2-6 因子的使用

> patientID <- c(1, 2, 3, 4)    (以下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)               <----❷显示对象的结构
‘data.frame’:   4 obs. of  4 variables:
 $ patientID: num  1 2 3 4
 $ age      : num  25 34 28 52
 $ diabetes : Factor w/ 2 levels "Type1","Type2": 1 2 1 1
 $ status   : Ord.factor w/ 3 levels "Excellent"<"Improved"<..: 3 2 1 3
> summary(patientdata)          <------❸显示对象的统计概要
   patientID         age         diabetes       status
 Min.   :1.00   Min.   :25.00   Type1:3   Excellent:1
 1st Qu.:1.75   1st Qu.:27.25   Type2:1   Improved :1
 Median :2.50   Median :31.00             Poor     :2
 Mean   :2.50   Mean   :34.75
 3rd Qu.:3.25   3rd Qu.:38.50
 Max.   :4.00   Max.   :52.00

首先,以向量的形式输入数据❶。然后,将diabetesstatus分别指定为一个普通因子和一个有序型因子。最后,将数据合并为一个数据框。函数str(object)可提供R中某个对象(本例中为数据框)的信息❷。它清楚地显示diabetes是一个因子,而status是一个有序型因子,以及此数据框在内部是如何进行编码的。注意,函数summary()会区别对待各个变量❸。它显示了连续型变量age的最小值、最大值、均值和各四分位数,并显示了类别型变量diabetesstatus(各水平)的频数值。

2.2.6 列表

列表(list)是R的数据类型中最为复杂的一种。一般来说,列表就是一些对象(或成分,component)的有序集合。列表允许你整合若干(可能无关的)对象到单个对象名下。例如,某个列表中可能是若干向量、矩阵、数据框,甚至其他列表的组合。可以使用函数list()创建列表:

mylist <- list(object1, object2, ...)

其中的对象可以是目前为止讲到的任何结构。你还可以为列表中的对象命名:

mylist <- list(name1=object1, name2=object2, ...)

代码清单2-7展示了一个例子。

代码清单2-7 创建一个列表

> 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             <-----输出整个列表
$title
[1] "My First List"

$ages
[1] 25 26 18 39

[[3]]
     [,1] [,2]
[1,]    1    6
[2,]    2    7
[3,]    3    8
[4,]    4    9
[5,]    5   10

[[4]]
[1] "one"   "two"   "three"

> mylist[[2]]            <-----输出第二个成分
[1] 25 26 18 39
> mylist[["ages"]]
[1] 25 26 18 39

本例创建了一个列表,其中有四个成分:一个字符串、一个数值型向量、一个矩阵以及一个字符型向量。可以组合任意多的对象,并将它们保存为一个列表。

你也可以通过在双重方括号中指明代表某个成分的数字或名称来访问列表中的元素。此例中,mylist[[2]]mylist[["ages"]]均指那个含有四个元素的向量。对于命名成分,mylist$ages也可以正常运行。由于两个原因,列表成为了R中的重要数据结构。首先,列表允许以一种简单的方式组织和重新调用不相干的信息。其次,许多R函数的运行结果都是以列表的形式返回的。需要取出其中哪些成分由分析人员决定。你将在后续各章发现许多返回列表的函数示例。

提醒程序员注意的一些事项

经验丰富的程序员通常会发现R语言的某些方面不太寻常。以下是这门语言中你需要了解的一些特性。

  • 对象名称中的句点(.)没有特殊意义,但美元符号($)却有着和其他语言中的句点类似的含义,即指定一个数据框或列表中的某些部分。例如,A$x是指数据框A中的变量x

  • R不提供多行注释或块注释功能。你必须以#作为多行注释每行的开始。出于调试目的,你也可以把想让解释器忽略的代码放到语句if(FALSE){... }中。将FALSE改为TRUE即允许这块代码执行。

  • 将一个值赋给某个向量、矩阵、数组或列表中一个不存在的元素时,R将自动扩展这个数据结构以容纳新值。举例来说,考虑以下代码:

    > x <- c(8, 6, 4)
    > x[7] <- 10
    > x
    [1]  8  6  4 NA NA NA 10
    
    

通过赋值,向量x由三个元素扩展到了七个元素。x <- x[1:3]会重新将其缩减回三个元素。

  • R中没有标量。标量以单元素向量的形式出现。

  • R中的下标不从0开始,而从1开始。在上述向量中,x[1]的值为8。

  • 变量无法被声明。它们在首次被赋值时生成。

要了解更多,参阅John Cook的优秀博文“R programming for those coming from other languages”(www.johndcook.com/Rlanguagefor_programmers.html)。

那些正在寻找编码风格指南的程序员不妨看看“Google's R Style Guide”2http://google-styleguide.googlecode.com/svn/trunk/google-r-style.html)。

2搜索“来自Google的R语言编码风格指南”可以找到这份文档的中文版。——译者注

2.3 数据的输入

现在你已经掌握了各种数据结构,可以放一些数据进去了。作为一名数据分析人员,你通常会面对来自多种数据源和数据格式的数据,你的任务是将这些数据导入你的工具,分析数据,并汇报分析结果。R提供了适用范围广泛的数据导入工具。向R中导入数据的权威指南参见可在http://cran.r-project.org/doc/manuals/R-data.pdf下载的 R Data Import/Export 手册3

3此手册对应的中译名为《R数据的导入和导出》,可在网上找到。——译者注

如图2-2所示,R可从键盘、文本文件、Microsoft Excel和Access、流行的统计软件、特殊格式的文件、多种关系型数据库管理系统、专业数据库、网站和在线服务中导入数据。由于我们无从得知你的数据将来自何处,故会在下文论及各种数据源。读者按需参阅即可。

图 2-2 可供R导入的数据源

2.3.1 使用键盘输入数据

也许输入数据最简单的方式就是使用键盘了。有两种常见的方式:用R内置的文本编辑器和直接在代码中嵌入数据。我们首先考虑文本编辑器。

R中的函数edit()会自动调用一个允许手动输入数据的文本编辑器。具体步骤如下:

(1) 创建一个空数据框(或矩阵),其中变量名和变量的模式需与理想中的最终数据集一致;

(2) 针对这个数据对象调用文本编辑器,输入你的数据,并将结果保存回此数据对象中。

在下例中,你将创建一个名为mydata的数据框,它含有三个变量:age(数值型)、gender(字符型)和weight(数值型)。然后你将调用文本编辑器,键入数据,最后保存结果。

mydata <- data.frame(age=numeric(0),
  gender=character(0), weight=numeric(0))
mydata <- edit(mydata)

类似于age=numeric(0)的赋值语句将创建一个指定模式但不含实际数据的变量。注意,编辑的结果需要赋值回对象本身。函数edit()事实上是在对象的一个副本上进行操作的。如果你不将其赋值到一个目标,你的所有修改将会全部丢失!

在Windows上调用函数edit()的结果如图2-3所示。如图2-3所示,我已经自主添加了一些数据。单击列的标题,你就可以用编辑器修改变量名和变量类型(数值型、字符型)。你还可以通过单击未使用列的标题来添加新的变量。编辑器关闭后,结果会保存到之前赋值的对象中(本例中为mydata)。再次调用mydata <- edit(mydata),就能够编辑已经输入的数据并添加新的数据。语句mydata <- edit(mydata)的一种简捷的等价写法是fix(mydata)

{%}

图 2-3 通过Windows上内建的编辑器输入数据

此外,你可以直接在你的程序中嵌入数据集。比如说,参见以下代码:

mydatatxt <- "
age gender weight
25 m 166
30 f 115
18 f 120
"
mydata <- read.table(header=TRUE, text=mydatatxt)

以上代码创建了和之前用edit()函数所创建的一样的数据框。一个字符型变量被创建于存储原始数据,然后read.table()函数被用于处理字符串并返回数据框。函数read.table()将在下一节描述。

键盘输入数据的方式在你在处理小数据集的时候很有效。对于较大的数据集,你所期望的也许是我们接下来要介绍的方式:从现有的文本文件、Excel电子表格、统计软件或数据库中导入数据。

2.3.2 从带分隔符的文本文件导入数据

你可以使用read.table()从带分隔符的文本文件中导入数据。此函数可读入一个表格格式的文件并将其保存为一个数据框。表格的每一行分别出现在文件中每一行。其语法如下:

mydataframe <- read.table(file, options)

其中,file是一个带分隔符的ASCII文本文件,options是控制如何处理数据的选项。表2-2列出了常见的选项。

表 2-2 函数read.table()的选项

选项

描述

header

一个表示文件是否在第一行包含了变量名的逻辑型变量

sep

分开数据值的分隔符。默认是sep="",这表示了一个或多个空格、制表符、换行或回车。使用sep=","来读取用逗号来分隔行内数据的文件,使用sep="\t"来读取使用制表符来分割行内数据的文件

row.names

一个用于指定一个或多个行标记符的可选参数

col.names

如果数据文件的第一行不包括变量名(header=FASLE),你可以用col.names去指定一个包含变量名的字符向量。如果header=FALSE以及col.names选项被省略了,变量会被分别命名为V1V2,以此类推

na.strings

可选的用于表示缺失值的字符向量。比如说,na.strings=c("-9", "?")-9?值在读取数据的时候转换成NA

colClasses

可选的分配到每一列的类向量。比如说,colClasses=c("numeric", "numeric", "character", "NULL", "numeric")把前两列读取为数值型变量,把第三列读取为字符型向量,跳过第四列,把第五列读取为数值型向量。如果数据有多余五列,colClasses的值会被循环。当你在读取大型文本文件的时候,加上colClasses选项可以可观地提升处理的速度

quote

用于对有特殊字符的字符串划定界限的字符串。默认值是双引号(")或单引号('

skip

读取数据前跳过的行的数目。这个选项在跳过头注释的时候比较有用

stringsAsFactors

一个逻辑变量,标记处字符向量是否需要转化成因子。默认值是TRUE,除非它被colClases所覆盖。当你在处理大型文本文件的时候,设置成stringsAsFactors=FALSE可以提升处理速度

text

一个指定文字进行处理的字符串。如果text被设置了,file应该被留空。2.3.1节给出了一个例子

考虑一个名为studentgrades.csv的文本文件,它包含了学生在数学、科学和社会学习的分数。文件中每一行表示一个学生,第一行包含了变量名,用逗号分隔。每一个单独的行都包含了学生的信息,它们也是用逗号进行分隔的。文件的前几行如下:

StudentID,First,Last,Math,Science,Social Studies
011,Bob,Smith,90,80,67
012,Jane,Weary,75,,80
010,Dan,"Thornton, III",65,75,70
040,Mary,"O'Leary",90,95,92

这个文件可以用以下语句来读入成一个数据框:

grades <- read.table("studentgrades.csv", header=TRUE,
    row.names="StudentID", sep=",")

结果如下:

> grades

   First             Last Math Science Social.Studies
11   Bob            Smith   90      80             67
12  Jane            Weary   75      NA             80
10   Dan    Thornton, III   65      75             70
40  Mary          O'Leary   90      95             92

> str(grades)
'data.frame':   4 obs. of  5 variables:
 $ First         : Factor w/ 4 levels "Bob","Dan","Jane",..: 1 3 2 4
 $ Last          : Factor w/ 4 levels "O'Leary","Smith",..: 2 4 3 1
 $ Math          : int  90 75 65 90
 $ Science       : int  80 NA 75 95
 $ Social.Studies: int  67 80 70 92

如何导入数据有很多有趣的要点。变量名Social Studies被自动地根据R的习惯所重命名。列StudentID现在是行名,不再有标签,也失去了前置的0。Jane的缺失的科学课成绩被正确地识别为缺失值。我不得不在Dan的姓周围用引号包围住,从而能够避免Thornton和III之间的空格。否则,R会在那一行读出七个值而不是六个值。我也在O'Leary左右用引号包围住了,负载R会把单引号读取为分隔符(而这不是我想要的)。最后,姓和名都被转化成为因子。

默认地,read.table()把字符变量转化为因子,这并不一定都是我们想要的情况。比如说,很少情况下,我们才会把回答者的评论转化成为因子。你可用多种方法去掉这个行为。加上选项stringsAsFactors=FALSE对所有的字符变量都去掉这个行为。此外,你可以用colClasses选项去对每一列都指定一个类(比如说,逻辑型、数值型、字符型或因子型)。

用以下代码导入同一个函数:

grades <- read.table("studentgrades.csv", header=TRUE,
    row.names="StudentID", sep=",",
    colClasses=c("character", "character", "character",
                 "numeric", "numeric", "numeric"))

得到以下数据框:

> grades

    First             Last Math Science Social.Studies
011   Bob            Smith   90      80             67
012  Jane            Weary   75      NA             80
010   Dan    Thornton, III   65      75             70
040  Mary          O'Leary   90      95             92

> str(grades)

'data.frame':   4 obs. of  5 variables:
 $ First         : chr  "Bob" "Jane" "Dan" "Mary"
 $ Last          : chr  "Smith" "Weary" "Thornton, III" "O'Leary"
 $ Math          : num  90 75 65 90
 $ Science       : num  80 NA 75 95
 $ Social.Studies: num  67 80 70 92

注意,行名保留了前缀0,而且First和Last不再是因子。此外,grades作为实数而不是整数来进行排序。

函数read.table()还拥有许多微调数据导入方式的追加选项。更多详情,请参阅help(read.table)

用连接来导入数据

本章中的许多示例都是从用户计算机上已经存在的文件中导入数据。R也提供了若干种通过连接(connection)来访问数据的机制。例如,函数file()gzfile()bzfile()xzfile()unz()url()可作为文件名参数使用。函数file()允许你访问文件、剪贴板和C级别的标准输入。函数gzfile()bzfile()xzfile()unz()允许你读取压缩文件。

函数url()能够让你通过一个含有http://、ftp://或file://的完整URL访问网络上的文件,还可以为HTTP和FTP连接指定代理。为了方便,(用双引号围住的)完整的URL也经常直接用来代替文件名使用。更多详情,参见help(file)

2.3.3 导入Excel数据

读取一个Excel文件的最好方式,就是在Excel中将其导出为一个逗号分隔文件(csv),并使用前文描述的方式将其导入R中。此外,你可以用xlsx包直接地导入Excel工作表。请确保在第一次使用它之前先进行下载和安装。你也需要xlsxjarsrJava包,以及一个正常工作的Java安装(http://java.com)。

xlsx包可以用来对Excel 97/2000/XP/2003/2007文件进行读取、写入和格式转换。函数read.xlsx()导入一个工作表到一个数据框中。最简单的格式是read.xlsx(file, n),其中file是Excel工作簿的所在路径,n则为要导入的工作表序号。举例说明,在Windows上,以下代码:

library(xlsx)
workbook <- "c:/myworkbook.xlsx"
mydataframe <- read.xlsx(workbook, 1)

从位于C盘根目录的工作簿myworkbook.xlsx中导入了第一个工作表,并将其保存为一个数据框mydataframe

函数read.xlsx()有些选项可以允许你指定工作表中特定的行(rowIndex)和列(colIndex),配合上对应每一列的类(colClasses)。对于大型的工作簿(比如说,100 000+个单元格),你也可以使用read.xlsx2()函数。这个函数用Java来运行更加多的处理过程,因此能够获得可观的质量提升。请查阅help(read.xlsx)获得更多细节。

也有其他包可以帮助你处理Excel文件。替代的包包含了XLConnectopenxlsx包;XLConnect依赖于 Java,不过openxlsx并不是。所有这些软件包都可以做比导入数据更加多的事情——它们也可以创建和操作Excel文件。那些需要创建R和Excel之间的接口的程序员应该要仔细查看这些软件包中的一个或多个。

2.3.4 导入XML数据

以XML格式编码的数据正在逐渐增多。R中有若干用于处理XML文件的包。例如,由Duncan Temple Lang编写的XML包允许你读取、写入和操作XML文件。XML格式本身已经超出了本书的范围。对使用R存取XML文档感兴趣的读者可以参阅www.omegahat.org/RSXML,从中可以找到若干份优秀的软件包文档。

2.3.5 从网页抓取数据

网络上的数据,可以通过所谓Web数据抓取(Webscraping)的过程,或对应用程序接口(application programming interface,API)的使用来获得。

一般地说,在Web数据抓取过程中,用户从互联网上提取嵌入在网页中的信息,并将其保存为R中的数据结构以做进一步的分析。比如说,一个网页上的文字可以使用函数readLines()来下载到一个R的字符向量中,然后使用如grep()gsub()一类的函数处理它。对于结构复杂的网页,可以使用RCurl包和XML包来提取其中想要的信息。更多信息和示例,请参考网站Programming with Rwww.programmingr.com)上的“Webscraping using readLines and RCurl”一文。

API指定了软件组件如何互相进行交互。有很多R包使用这个方法来从网上资源中获取数据。这些资源包括了生物、医药、地球科学、物理科学、经济学,以及商业、金融、文学、销售、新闻和运动等的数据源。

比如说,如果你对社交媒体感兴趣,可以用twitteR来获取Twitter数据,用 Rfacebook来获取Facebook数据,用Rflickr来获取Flicker数据。其他软件包允许你连接上如Google、Amazon、Dropbox、Salesforce等所提供的广受欢迎的网上服务。可以查看CRAN Task View中的子版块Web Technologies and Serviceshttps://cran.r-project.org/web/views/WebTechnologies.html)来获得一个全面的列表,此列表列出了能帮助你获取网上资源的各种R包。

2.3.6 导入SPSS数据

IBM SPSS数据集可以通过foreign包中的函数read.spss()导入到R中,也可以使用Hmisc包中的spss.get()函数。函数spss.get()是对read.spss()的一个封装,它可以为你自动设置后者的许多参数,让整个转换过程更加简单一致,最后得到数据分析人员所期望的结果。

首先,下载并安装Hmisc包(foreign包已被默认安装):

install.packages("Hmisc")

然后使用以下代码导入数据:

library(Hmisc)
mydataframe <- spss.get("mydata.sav", use.value.labels=TRUE)

这段代码中,mydata.sav是要导入的SPSS数据文件,use.value.labels=TRUE表示让函数将带有值标签的变量导入为R中水平对应相同的因子,mydataframe是导入后的R数据框。

2.3.7 导入SAS数据

R中设计了若干用来导入SAS数据集的函数,包括foreign包中的read.ssd()Hmisc包中的sas.get(),以及sas7bdat包中的 read.sas7bdat()。如果你安装了SAS,sas.get()是一个好的选择。

比如说,你想导入一个名为clients.sas7bdat的SAS数据集文件,它位于一台Windows机器上的C:/mydata文件夹中,以下代码导入了数据,并且保存为一个R数据框:

library(Hmisc)
datadir <- "C:/mydata"
sasexe <- "C:/Program Files/SASHome/SASFoundation/9.4/sas.exe"
mydata <- sas.get(libraryName=datadir, member="clients", sasprog=sasexe)

libraryName是一个包含了SAS数据集的文件夹,member是数据集名字(去除掉后缀名sas7bdat),sasprog是到SAS可运行程序的完整路径。有很多可用的选项;查看help(sas.get)获得更多细节。

你也可以在SAS中使用PROC EXPORT将SAS数据集保存为一个逗号分隔的文本文件,并使用2.3.2节中叙述的方法将导出的文件读取到R中。下面是一个示例:

SAS程序:

libname datadir "C:\mydata";
proc export data=datadir.clients
     outfile="clients.csv"
     dbms=csv;
run;

R程序:

mydata <- read.table("clients.csv", header=TRUE, sep=",")

前面两种方法要求你安装了一套完整的可运行的SAS程序。如果你没有连接SAS的途径,函数read.sas7dbat()也许是一个好的候选项。这个函数可以直接读取sas7dbat格式的SAS数据集。这个例子的对应代码是:

library(sas7bdat)
mydata <- read.sas7bdat("C:/mydata/clients.sas7bdat")

不像sas.get()read.sas7dbat()忽略了SAS用户自定义格式。此外,这个函数用了明显更多的时间来进行处理。尽管我使用这个包的时候比较好运,它依然应该被认为是实验性质的。

最后,一款名为Stat/Transfer的商业软件(在2.3.12节介绍)可以完好地将SAS数据集(包括任何已知的变量格式)保存为R数据框。与read.sas7dbat()一样,它也不要求安装SAS。

2.3.8 导入Stata数据

要将Stata数据导入R中非常简单直接。所需代码类似于:

library(foreign)
mydataframe <- read.dta("mydata.dta")

这里,mydata.dta是Stata数据集,mydataframe是返回的R数据框。

2.3.9 导入NetCDF数据

Unidata项目主导的开源软件库NetCDF(Network Common Data Form,网络通用数据格式)定义了一种机器无关的数据格式,可用于创建和分发面向数组的科学数据。NetCDF格式通常用来存储地球物理数据。ncdf包和ncdf4包为NetCDF文件提供了高层的R接口。

ncdf包为通过Unidata的NetCDF库(版本3或更早)创建的数据文件提供了支持,而且在Windows、Mac OS X和Linux上均可使用。ncdf4包支持NetCDF 4或更早的版本,但在Windows上尚不可用。

考虑如下代码:

library(ncdf)
nc <- nc_open("mynetCDFfile")
myarray <- get.var.ncdf(nc, myvar)

在本例中,对于包含在NetCDF文件mynetCDFfile中的变量myvar,其所有数据都被读取并保存到了一个名为myarray的R数组中。

值得注意的是,ncdf包和ncdf4包最近进行了重大升级,使用方式可能与旧版本不同。另外,这两个包中的函数名称也不同。请阅读在线帮助以了解详情。

2.3.10 导入HDF5数据

HDF5(Hierarchical Data Format,分层数据格式)是一套用于管理超大型和结构极端复杂数据集的软件技术方案。rhdf5包为R提供了一个HDF5的接口。这个包在Bioconductor网站上而不是CRAN上提供。你可以用以下代码对之进行安装:

source("http://bioconductor.org/biocLite.R")
biocLite("rhdf5")

像XML一样,HDF5格式超出了本书的内容范围。如果想学习更多相关知识,可访问HDF Group网站(http://www.hdf5group.org/)。由Bernd Fischer编写的http://www.bioconductor.org/packages/release/bioc/vignettes/rhdf5/inst/doc/rhdf5.pdf是一个rhdf5包的优秀指南。

2.3.11 访问数据库管理系统

R中有多种面向关系型数据库管理系统(DBMS)的接口,包括Microsoft SQL Server、Microsoft Access、MySQL、Oracle、PostgreSQL、DB2、Sybase、Teradata以及SQLite。其中一些包通过原生的数据库驱动来提供访问功能,另一些则是通过ODBC或JDBC来实现访问的。使用R来访问存储在外部数据库中的数据是一种分析大数据集的有效手段(参见附录F),并且能够发挥SQL和R各自的优势。

1. ODBC接口

在R中通过RODBC包访问一个数据库也许是最流行的方式,这种方式允许R连接到任意一种拥有ODBC驱动的数据库,这包含了前文所列的所有数据库。

第一步是针对你的系统和数据库类型安装和配置合适的ODBC驱动——它们并不是R的一部分。如果你的机器尚未安装必要的驱动,上网搜索一下应该就可以找到。

针对选择的数据库安装并配置好驱动后,请安装RODBC包。你可以使用命令install.packages("RODBC")来安装它。RODBC包中的主要函数列于表2-3中。

表 2-3 RODBC中的函数

函数

描述

odbcConnect(dsn,uid="",pwd="")

建立一个到ODBC数据库的连接

sqlFetch(channel,sqltable)

读取ODBC数据库中的某个表到一个数据框中

sqlQuery(channel,query)

向ODBC数据库提交一个查询并返回结果

sqlSave(channel,mydf,tablename=sqtable,append=FALSE)

将数据框写入或更新(append=TRUE)到ODBC数据库的某个表中

sqlDrop(channel,sqtable)

删除ODBC数据库中的某个表

close(channel)

关闭连接

RODBC包允许R和一个通过ODBC连接的SQL数据库之间进行双向通信。这就意味着你不仅可以读取数据库中的数据到R中,同时也可以使用R修改数据库中的内容。假设你想将某个数据库中的两个表(Crime和Punishment)分别导入为R中的两个名为crimedatpundat的数据框,可以通过如下代码完成这个任务:

library(RODBC)
myconn <-odbcConnect("mydsn", uid="Rob", pwd="aardvark")
crimedat <- sqlFetch(myconn, Crime)
pundat <- sqlQuery(myconn, "select * from Punishment")
close(myconn)

这里首先载入了RODBC包,并通过一个已注册的数据源名称(mydsn)和用户名(rob)以及密码(aardvark)打开了一个ODBC数据库连接。连接字符串被传递给sqlFetch(),它将Crime表复制到R数据框crimedat中。然后我们对Punishment表执行了SQL语句select并将结果保存到数据框pundat中。最后,我们关闭了连接。

函数sqlQuery()非常强大,因为其中可以插入任意的有效SQL语句。这种灵活性赋予了你选择指定变量、对数据取子集、创建新变量,以及重编码和重命名现有变量的能力。

2. DBI相关包

DBI包为访问数据库提供了一个通用且一致的客户端接口。构建于这个框架之上的RJDBC包提供了通过JDBC驱动访问数据库的方案。使用时请确保安装了针对你的系统和数据库的必要JDBC驱动。其他有用的、基于DBI的包有RMySQLROracleRPostgreSQLRSQLite。这些包都为对应的数据库提供了原生的数据库驱动,但可能不是在所有系统上都可用。详情请参阅CRAN(http://cran.r-project.org)上的相应文档。

2.3.12 通过Stat/Transfer导入数据

在我们结束数据导入的讨论之前,值得提到一款能让上述任务的难度显著降低的商业软件。Stat/Transfer(www.stattransfer.com)是一款可在34种数据格式之间作转换的独立应用程序,其中包括R中的数据格式(见图2-4)。

{%}

图 2-4 Windows上Stat/Transfer的主对话框

此软件拥有Windows、Mac和Unix版本,并且支持我们目前讨论过的各种统计软件的最新版本,也可通过ODBC访问如Oracle、Sybase、Informix和DB/2一类的数据库管理系统。

2.4 数据集的标注

为了使结果更易解读,数据分析人员通常会对数据集进行标注。这种标注包括为变量名添加描述性的标签,以及为类别型变量中的编码添加值标签。例如,对于变量age,你可能想附加一个描述更详细的标签“Age at hospitalization (in years)”(入院年龄)。对于编码为1或2的性别变量gender,你可能想将其关联到标签“male”和“female”上。

2.4.1 变量标签

遗憾的是,R处理变量标签的能力有限。一种解决方法是将变量标签作为变量名,然后通过位置下标来访问这个变量。考虑之前病例数据框的例子。名为age的第二列包含着个体首次入院时的年龄。代码:

names(patientdata)[2] <- "Age at hospitalization (in years)"

age重命名为"Age at hospitalization (in years)"。很明显,新的变量名太长,不适合重复输入。作为替代,你可以使用patientdata[2]来引用这个变量,而在本应输出age的地方输出字符串"Age at hospitalization (in years)"。很显然,这个方法并不理想,如果你能尝试想出更好的命名(例如,admissionAge)可能会更好一点。

2.4.2 值标签

函数factor()可为类别型变量创建值标签。继续上例,假设你有一个名为gender的变量,其中1表示男性,2表示女性。你可以使用代码:

patientdata$gender <- factor(patientdata$gender,
                             levels = c(1,2),
                             labels = c("male", "female"))

来创建值标签。

这里levels代表变量的实际值,而labels表示包含了理想值标签的字符型向量。

2.5 处理数据对象的实用函数

在本章末尾,我们来简要总结一下实用的数据对象处理函数(参见表2-4)。

表 2-4 处理数据对象的实用函数

函数

用途

length(object)

显示对象中元素/成分的数量

dim(object)

显示某个对象的维度

str(object)

显示某个对象的结构

class(object)

显示某个对象的类或类型

mode(object)

显示某个对象的模式

names(object)

显示某对象中各成分的名称

c(object, object,...)

将对象合并入一个向量

cbind(object, object, ...)

按列合并对象

rbind(object, object, ...)

按行合并对象

object

输出某个对象

head(object)

列出某个对象的开始部分

tail(object)

列出某个对象的最后部分

ls()

显示当前的对象列表

rm(object, object, ...)

删除一个或更多个对象。语句rm(list = ls())将删除当前工作环境中的几乎所有对象4

newobject <- edit(object)

编辑对象并另存为newobject

fix(object)

直接编辑对象

4以句点.开头的隐藏对象将不受影响。——译者注

我们已经讨论过其中的大部分函数。函数head()tail()对于快速浏览大数据集的结构非常有用。例如,head(patientdata)将列出数据框的前六行,而tail(patientdata)将列出最后六行。我们将在下一章中介绍length()cbind()rbind()等函数。我们将其汇总于此,仅作参考。

2.6 小结

数据的准备可能是数据分析中最具挑战性的任务之一。我们在本章中概述了R中用于存储数据的多种数据结构,以及从键盘和外部来源导入数据的许多可能方式,这是一个不错的起点。特别是,我们将在后续各章中反复地使用向量矩阵数据框列表的概念。掌握通过括号表达式选取元素的能力,对数据的选择、取子集和变换将是非常重要的。

如你所见,R提供了丰富的函数用以访问外部数据,包括普通文本文件、网页、统计软件、电子表格和数据库的数据。虽然本章的焦点是将数据导入到R中,你同样也可以将数据从R导出为这些外部格式。数据的导出在附录C中论及,处理大数据集(GB级到TB级)的方法在附录F中讨论。

将数据集读入R之后,你很有可能需要将其转化为一种更有助于分析的格式(事实上,我发现处理数据的紧迫感有助于促进学习)。在第4章,我们将会探索创建新变量、变换和重编码已有变量、合并数据集和选择观测的方法。

在转而探讨数据管理之前,让我们先花些时间在R的绘图上。许多读者都是因为对R绘图怀有强烈的兴趣而开始学习R的,为了不让你们久等,我们在下一章将直接讨论图形的创建。关注的重点是管理和定制图形的通用方法,它们在本书余下章节都会用到。

目录

  • 版权声明
  • 对第1版的赞誉
  • 致谢
  • 前言
  • 关于本书
  • 关于封面图片
  • 第一部分 入门
  • 第 1 章 R语言介绍
  • 第 2 章 创建数据集
  • 第 3 章 图形初阶
  • 第 4 章 基本数据管理
  • 第 5 章 高级数据管理
  • 第二部分 基本方法
  • 第 6 章 基本图形
  • 第 7 章 基本统计分析
  • 第三部分 中级方法
  • 第 8 章 回归
  • 第 9 章 方差分析
  • 第 10 章 功效分析
  • 第 11 章 中级绘图
  • 第 12 章 重抽样与自助法
  • 第四部分 高级方法
  • 第 13 章 广义线性模型
  • 第 14 章 主成分分析和因子分析
  • 第 15 章 时间序列
  • 第 16 章 聚类分析
  • 第 17 章 分类
  • 第 18 章 处理缺失数据的高级方法
  • 第五部分 技能拓展
  • 第 19 章 使用ggplot2进行高级绘图
  • 第 20 章 高级编程
  • 第 21 章 创建包
  • 第 22 章 创建动态报告
  • 第 23 章 使用lattice进行高级绘图
  • 附录 A 图形用户界面
  • 附录 B 自定义启动环境
  • 附录 C 从R中导出数据
  • 附录 D R中的矩阵运算
  • 附录 E 本书中用到的扩展包
  • 附录 F 处理大数据集
  • 附录 G 更新R
  • 后记:探索R的世界
  • 参考文献