R语言学习笔记-2

181 阅读10分钟

第二章:创建数据集

一、 数据集的概念

数据集通常是由数据构成的一个矩形数组,行表示观测,列表示变量

R中有许多用于存储数据的结构,包括标量向量数组数据框列表

R可以处理的数据类型(模式)包括数值型字符型逻辑型TRUE/FALSE)、复数型(虚数)和原生型(字节)

二、 数据结构

R拥有许多用于存储数据的对象类型,包括标量向量矩阵数组数据框列表

下面就让我们逐个来学习吧!

1. 向量

向量是用于存储数值型、字符型或逻辑型数据的一维数组

a. 创建向量

执行组合功能的函数c()可用来创建向量

a <- c(1, 2, 5, 3, 6, -2, 4)     # 数值型向量
b <- c("one", "two", "three")     # 字符型向量
c <- c(TRUE, TRUE, TRUE, FALSE, TRUE, FALSE)     # 逻辑型向量

注意:

  • 单个向量中的数据必须拥有相同的类型或模式(数值型、字符型或逻辑型),同一向量中无法混杂不同模式的数据
  • 标量是只含一个元素的向量,例如f <- 3g <- "US"h <- TRUE,它们用于保存常量

b. 访问向量中的元素

通过在方括号中给定元素所处位置的数值,我们可以访问向量中的元素

> a <- c("k", "j", "h", "a", "c", "m") 
> a[3]      # 访问向量a中的第三个元素
[1] "h" 
> a[c(1, 3, 5)]       # 访问向量a中的第一、三、五个元素
[1] "k" "h" "c" 
> a[2:6]       # 等价于a <- c(2, 3, 4, 5, 6)
[1] "j" "h" "a" "c" "m"

R中向量元素的索引是从1开始的

2. 矩阵

矩阵是一个二维数组,只是每个元素都拥有相同的模式(数值型、字符型或逻辑型)

a. 创建矩阵

可通过函数matrix()创建矩阵,一般使用格式为:

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

参数含义

  • vector为要存储到矩阵中的元素,一般为向量
  • nrow为行数
  • ncol为列数
  • byrow 为逻辑值,byrow=TRUE 按行填充,byrow=FALSE 按列填充,默认情况下按列填充
  • dimnames表示包含了行名和列名的字符型向量
> 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, dimnames=list(rnames, cnames))  # 按行填充的2×2矩阵
> mymatrix 
   C1 C2
R1  1 26
R2 24 68 
> mymatrix <- matrix(cells, nrow=2, ncol=2, byrow=FALSE, dimnames=list(rnames, cnames)) # 按列填充的2×2矩阵
> mymatrix 
   C1 C2
R1  1 24
R2 26 68

b. 矩阵下标的使用

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

> x <- matrix(1:10, nrow=2)      # 创建了一个内容为数字1到10的2×5矩阵。默认情况下,矩阵按列填充
> 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

3. 数组

数组(array)与矩阵类似,但是维度可以大于2

a. 创建数组

数组可通过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))  # 创建4个两行三列的矩阵
> 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]   # 输出第三个矩阵中第一行第二列的元素
[1] 15

4. 数据框

数据框不同的列可以包含不同模式(数值型、字符型等)的数据,使用更为广泛

a. 创建数据框

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

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

其中的列向量col1col2col3等可为任何类型(如字符型、数值型或逻辑型)。每一列的名称可由函数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
  patientID age diabetes    status
1         1  25    Type1      Poor
2         2  34    Type2  Improved
3         3  28    Type1 Excellent
4         4  52    Type1      Poor

b. 选取数据框中的元素

选取数据框中元素的方式有多种。可以使用矩阵中的下标记号,也可直接指定列名

  • 以上面创建的patientdata数据框为例
> patientdata[1:2]    # 输出第一列和第二列的元素
  patientID age
1         1  25
2         2  34
3         3  28
4         4  52
> patientdata[c("diabetes", "status")]    # 输出列名为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
> table(patientdata$diabetes, patientdata$status)   # 生成糖尿病类型变量diabetes和病情变量status的列联表
       
        Excellent Improved Poor
  Type1         1        0    2
  Type2         0        1    0

c. attach()detach()with()

函数attach()可将数据框添加到R的搜索路径中。R在遇到一个变量名以后,将检查搜索路径中的数据框,以mtcars数据框为例:

> summary(mtcars$mpg)   # 获取mpg变量的描述性统计量
> plot(mtcars$mpg, mtcars$disp)    # 绘制mpg变量与发动机排量(disp)的散点图
> plot(mtcars$mpg, mtcars$wt)    # 绘制mpg变量与车身重量(wt)的散点图
# 以上代码也可写成:
> attach(mtcars) 
    summary(mpg) 
    plot(mpg, disp) 
    plot(mpg, wt) 
> detach(mtcars)

函数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语句出错

除此之外,另一种方式是使用函数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(mtcars, { 
   nokeepstats <- summary(mpg) 
   keepstats <<- summary(mpg)    # 特殊赋值符可将对象保存到with()之外的全局环境中
  }) 
> 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

d. 实例标识符

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

> patientdata <- data.frame(patientID, age, diabetes, status, row.names=age)
> patientdata
   patientID age diabetes    status
25         1  25    Type1      Poor
34         2  34    Type2  Improved
28         3  28    Type1 Excellent
52         4  52    Type1      Poor

5. 因子

变量可归结为名义型有序型连续型变量

  • 名义型变量是没有顺序之分的类别变量。如糖尿病类型Diabetes(Type1、Type2)
  • 有序型变量表示一种顺序关系,而非数量关系。如病情Status(poor、improved、excellent)
  • 连续型变量可以呈现为某个范围内的任意值,并同时表示了顺序和数量。年龄Age就是一个连续型变量

名义型变量有序型变量R中称为因子(factor)

  • 因子的转换一般使用factor()函数

a. 名义型变量转换为普通因子

函数factor()以一个整数向量的形式存储类别值,整数的取值范围是[1...k](其中k是名义型变量中唯一值的个数),同时一个由字符串(原始值)组成的内部向量将映射到这些整数上

> diabetes <- c("Type1", "Type2", "Type1", "Type1")
> diabetes <- factor(diabetes)
> diabetes
[1] Type1 Type2 Type1 Type1
Levels: Type1 Type2

b. 有序型变量转换为有序型因子

要表示有序型变量,需要为函数factor()指定参数ordered=TRUE

> status <- c("Poor", "Improved", "Excellent", "Poor")
> status <- factor(status, ordered=TRUE)
> status
[1] Poor      Improved  Excellent Poor     
Levels: Excellent < Improved < Poor

对于字符型向量,因子的水平默认依字母顺序创建,有时默认的顺序并不是我们想要的,这时可以通过指定levels选项来覆盖默认排序

> status <- factor(status, order=TRUE, levels=c("Poor", "Improved", "Excellent"))
> status
[1] Poor      Improved  Excellent Poor     
Levels: Poor < Improved < Excellent

c. 数值型变量转化为因子

数值型变量可以用levelslabels参数来编码成因子

> sex <- c(1,1,2,1)
> sex <- factor(sex, levels=c(1, 2), labels=c("Male", "Female"))
> sex
[1] Male   Male   Female Male  
Levels: Male Female

d. 因子的使用

> 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)    # 显示对象的结构
'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

6. 列表

列表R的数据类型中最为复杂的一种。一般来说,列表就是一些对象(或成分, component)的有序集合。某个列表中可能是若干向量、矩阵、数据框,甚至其他列表的组合

  • 可以使用函数list()创建列表
mylist <- list(object1, object2, ...)
mylist <- list(name1=object1, name2=object2, ...)    # 为列表中的对象命名

a. 创建一个列表

> 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

三、 数据的输入

1. 使用键盘输入数据

有两种常见的方式:用R内置的文本编辑器和直接在代码中嵌入数据

a. 文本编辑器

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

  1. 创建一个空数据框(或矩阵),其中变量名和变量的模式需与理想中的最终数据集一致;
  2. 针对这个数据对象调用文本编辑器,输入你的数据,并将结果保存回此数据对象中
> mydata <- data.frame(age=numeric(0), gender=character(0), weight=numeric(0)) 
> mydata <- edit(mydata)

如下图所示

image.png

可以通过单击,填充数据、修改行和列的名称。编辑器关闭后,结果会保存到之前赋值的对象中。再次调用mydata <- edit(mydata),就能够编辑已经输入的数据并添加新的数据。语句mydata <- edit(mydata)的一种简捷的等价写法是fix(mydata)

b. 直接在代码中嵌入数据

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

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

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

mydataframe <- read.table(file, options)

file是一个带分隔符的ASCII文本文件options是控制如何处理数据的选项

  • 函数read.table()的选项
选项描述
header表示文件是否在第一行包含了变量名的逻辑型变量
sep分开数据值的分隔符。默认是sep="",这表示了一个或多个空格、制表符、换行或回车。使用sep=","来读取用逗号来分隔行内数据的文件,使用sep="\t"来读取使用制表符来分割行内数据的文件
row.names用于指定行标记符的可选参数向量
col.names如果数据文件的第一行不包括变量名header=FASLE,可以用col.names去指定一个包含变量名的字符向量。如果header=FALSE以及col.names选项被省略了,变量会被分别命名为 V1、V2,以此类推
na.strings可选的用于表示缺失值的字符向量。比如说na.strings=c("-9", "?")-9?值在读 取数据的时候转换成NA
colClasses可选的分配到每一列的类向量。比如说colClasses=c("numeric", "numeric", "character", "NULL", "numeric")把前两列读取为数值型变量,把第三列读取为字符型向量,跳过第四 列,把第五列读取为数值型向量。如果数据有多余五列,colClasses的值会被循环。
quote用于对有特殊字符的字符串划定界限的自负床。默认值是双引号"或单引号'
skip读取数据前跳过的行的数目。这个选项在跳过头注释的时候比较有用
stringsAsFactors一个逻辑变量,标记处字符向量是否需要转化成因子。默认值是TRUE,除非它被colClases所覆盖。当你在处理大型文本文件的时候,设置成stringsAsFactors=FALSE可以提升处理速度
text一个指定文字进行处理的字符串。如果text被设置了,file应该被留空

下面举个例子

  • 先在工作目录下新建一个txt或者csv文件,getwd()可以查看当前工作目录,在文件中输入以下内容:
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.txt", 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         : chr  "Bob" "Jane" "Dan" "Mary"
 $ Last          : chr  "Smith" "Weary" "Thornton, III" "O'Leary"
 $ Math          : int  90 75 65 90
 $ Science       : int  80 NA 75 95
 $ Social.Studies: num  67 80 70 92
------------------------------------------------------------------------------------------
> grades <- read.table("studentgrades.csv", header=TRUE, row.names="StudentID", sep=",",
                         colClasses=c("character", "character", "character", "numeric", 
                         "numeric", "numeric"))       # 可使用colClasses选项指定每列的类型
> 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

R语言中,支持导入的文件类型有许多,例如常见的excel文件、XML文件、统计数据文件SPSSSASStata以及数据库管理系统等等,都可以找到相应的R包,对其进行处理,这里就不再详细介绍,一般比较常用的就是带分隔符的文本文件,以上的文件也可以通过一些手段转换成带分隔符的文本文件,具体可自行在网上搜索一下

四、 数据集的标注

有时我们可能会想要对一些变量名称进行更为详细的修改或者是为类别型变量创建值标签,下面就分别介绍下该如何操作

1. 变量标签

R处理变量标签的能力有限。一种解决方法是将变量标签作为变量名

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

2. 值标签

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

patientdata$gender <- factor(patientdata$gender, levels = c(1,2), labels = c("male", "female"))
  • 这里levels代表变量的实际值,而labels表示包含了理想值标签的字符型向量

五、 处理数据对象的实用函数

最后介绍一些处理数据对象的实用函数 | 函数 | 用途 | | :---: | :---: | | 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())将删除当前工作环境中的几乎所有对象 | | newobject <- edit(object) | 编辑对象并另存为 newobject | | fix(object) | 直接编辑对象 |

六、 小结

我们在本章中学习了R中用于存储数据的多种数据结构,以及从键盘和外部来源导入数据的许多可能方式,下一章我们将学习如何用这些数据去进行图形的构建,这也是R语言最具有魅力的地方!!!