R语言系列1:数据结构、数据导入和常用函数
此文内容为《R语言实战》的笔记,人民邮电出版社出版。
从高中电脑课学VB开始,大一课内开始学习C++,到后来大二为了数模学习Matlab,到大三为了搞深度学习自学Python,到研究生之初学习Stata——选择一门语言对我来说就像是小时候玩冒险岛,到10级的时候是转战士好还是弓箭手好一般的纠结。我查阅了很多B乎的文章,最后觉得可能R比较合适现在的我。
作为从Python转进来R的新手,我把可能会用经常需要用到或经常需要查阅的代码贴上来,主要是为了日后方便查找,就像“字典”一样。推文的顺序与教材不同,为了简洁,我还会删除一些我个人认为不太重要的章节。我还会按照自己的学习进度发布文章,请读者见谅。
本文章仅供学习参考,请勿转载,侵删!
目录
- 第2章 创建数据集
- 2.1 数据集的概念
- 2.2 数据结构
- 2.2.1 向量
- 2.2.2 矩阵
- 2.2.3 数组
- 2.2.4 数据框
- A. attach(), detach(), with()
- B. 实例标识符
- 2.2.5 因子
- 2.2.6 列表
- 2.3 数据的输入
- 2.3.1 从分隔符文件导入数据
- 2.3.2 导入Excel数据
- 2.3.3 导入Stata数据
- 2.5 处理对象的常用函数
第2章 创建数据集
按照个人要求的格式创建含有研究信息的数据集。在R中,这个任务包括两步:
- 选择一种数据结构来储存数据
- 将数据输入或导入到这个数据结构中
2.1 数据集的概念
数据集是由数据构成的一个矩形数组,行表示观测,列表示变量。
2.2 数据结构
R拥有的数据结构有:
- 标量
- 向量
- 矩阵
- 数组
- 数据框
- 列表
在R中,对象(object)是指可以赋值给变量的任何事物;数据框(data frame)是R中用于储存数据的一种结构:列表示标量,行表示观测;因子(factor)是名义型标量或有序变量。
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)
标量是只含一个元素的向量,例如
f <- 3
g <- "US"
h <- TRUE
通过在方括号中给定元素所处的位置的数值,可以访问向量中的元素,例如:
a <- c("k", "j", "h", "a", "c", "m")
a[3]
## [1] "h"
最后一个语句中使用的冒号用于生成一个数值序列,例如a <- c(2:6)
等价于a <- c(2, 3, 4, 5, 6)
2.2.2 矩阵
矩阵是一个二维数组,只是每个元素都有相同的模式(数值型、字符型或逻辑型)。可以通过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
用以指定行和列的维数,dimnames
包含了可选的、以字符型向量表示的行名和列名。选项byrow
则表明矩阵以行填充还是以列填充,默认情况下按行填充(TRUE)。
y <- matrix(1:20, nrow = 5)
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,28)
rnames <- c("R1", "R2")
cnames <- c("C1", "C2")
mymatrix <- matrix(cells, nrow = 2, dimnames = list(rnames, cnames))
mymatrix
## C1 C2
## R1 1 24
## R2 26 28
我们可以用下标和方括号来选择矩阵中的行和列。X[i,]
指定X中的第i行,X[,j]
指定X中的第j列。X[i,j]
指定第i行第j列个元素。选择多个行和列时,下标i和j可以为数值型向量。
x <- matrix(1:10, nrow = 2, ncol = 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[,3]
## [1] 5 6
x[1, c(4,5)]
## [1] 7 9
矩阵都是二维的,和向量类似,矩阵也只能包含一种数据结构。当维度超过2时,可以考虑使用数组;当数据类型超过1种时,可以考虑使用data frame。
2.2.3 数组
数组与矩阵类似,但维度可以大于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
## , , 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
可见,数组只是矩阵的自然推广,而且数据结构也只能有一种。
2.2.4 数据框
由于不同列可以包含不同模式的数据,数据框的概念比矩阵更为一般。数据框是你会在R中最常见的数据结构。、
数据框可以通过命令data.frame()
创建:
mydata <- data.frame(col1, col2, col3,...)
其中的列向量col1
、col2
、col3
可以为任何类型(字符、数值、逻辑)。每一列的列名可以用函数names
指定:
patientID <- c(1, 2, 3, 4)
age <- c(24, 34, 28, 52)
diabetes <- c("Type1", "Type2", "Type1", "Type1")
status <- c("Poor", "Improve", "Excellent", "Poor")
patientdata <- data.frame(patientID, age, diabetes, status)
patientdata
## patientID age diabetes status
## 1 1 24 Type1 Poor
## 2 2 34 Type2 Improve
## 3 3 28 Type1 Excellent
## 4 4 52 Type1 Poor
其中,每一列的数据类型必须一样,但不同列的可以不一样。为了方便讨论,数据框的列有时候被称为变量。
选取数据框的元素有很多种。你可以使用前面提到的方括号的方法,也可以直接指定列名:
patientdata[1:2,]
## patientID age diabetes status
## 1 1 24 Type1 Poor
## 2 2 34 Type2 Improve
patientdata[,1:2]
## patientID age
## 1 1 24
## 2 2 34
## 3 3 28
## 4 4 52
patientdata[c("diabetes", "status")]
## diabetes status
## 1 Type1 Poor
## 2 Type2 Improve
## 3 Type1 Excellent
## 4 Type1 Poor
你也可以使用记号 $
来选取一个给定数据框中的某个特定的变量:
patientdata$age
## [1] 24 34 28 52
如果想生成糖尿病类型diabetes
和病情status
的列联表,可以使用下面的命令:
table(patientdata$diabetes, patientdata$status)
##
## Excellent Improve Poor
## Type1 1 0 2
## Type2 0 1 0
A. attach()、detach()和with()
每个变量名前面都键入一次patientdata
非常麻烦,所以可以使用attach()
、detach()
、with()
来简化你的代码。
1. attach 函数。 attach()
可以将数据框添加到R的搜索路径中。R遇到一个变量名后,会检查搜索路径中的数据框,例如:
summary(patientdata$age)
plot(patientdata$patientID, patientdata$age)
就等同于
attach(patientdata)
summary(age)
plot(patientID, age)
detach(patientdata)
其中,detach()
用于将搜索框从搜索路径中移除。需要注意的是,detach()
是可以省略的,但在写程序的时候加上是良好的习惯。
重要的是,如果原始文件中已经存在名为age
或者patientID
的变量,那么原变量会优先于数据框中的列取得优先权。
2. with 函数。另外一种方法是使用with()
函数。可以这么写:
with(patientdata, {
print(summary(age))
plot(patientID, age)
})
这种情况下,{}
之间的语句都针对patientdata
运行,就不许担心变量名和列名冲突了。
with()
的局限性在于,赋值仅在函数的括号内生效。例如:
with(patientdata, {
stats <- summary(age)
stats
})
stats
是会报错的,因为stats
仅仅存在于with()
环境中。这时候需要使用特殊赋值 <<-
代替标准的赋值符 <-
,就可以把对象保存到 with()
外:
with(patientdata, {
stats <<- summary(age)
stats
})
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 24.0 27.0 31.0 34.5 38.5 52.0
stats
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 24.0 27.0 31.0 34.5 38.5 52.0
相对于attach()
,更多的教材推荐使用with()
,这只是个人习惯问题。
B. 实例标识符
在数据框中,病人编号(patientID
)用于区分不同的个体。在R中,实例标识符(case identifier)可通过数据框操作函数中的rowname
选项指定,例如:
patientdata <- data.frame(patientID, age, diabetes, status, row.names = patientID)
那么R就会将patientID
作为R标记各类打印输出所用的变量。
2.2.5 因子
变量了可以归结为名义型、有序型或连续型。
名义型变量是没有顺序之分的类别变量,例如糖尿病类型
Diabetes(Type1, Type2)
,即使在数据中前者编码为1、后者编码为2,也不意味着二者是递进关系。而病情
Status(poor, improved, excellent)
则是顺序型的。连续型变量可以呈现为一种某个范围的任意值。
在R中,类别(名义型)变量和有序类别(有序型)变量均称为因子(factor)。因子非常重要,它决定了数据的分析方式和视觉呈现效果。
函数factor()
以一个整数向量的形式存储类别值,整数的取值范围为[1,...,k],同时一个由字符串组成的内部向量将映射到这些整数上。例如:
diabetes <- c("Type1", "Type2", "Type1", "Type1")
diabetes <- facor(diabetes)
将此向量储存为(1,2,1,1)
,并在内部将其关联为“Type1=1”、“Type2=2”。针对diabetes
的任何分析都会将其作为名义型变量对待。
要表示有序变量,则需要使用factor()
函数内的ordered=TRUE
,例如:
status <- c("Poor", "Improve", "Excellent", "Poor")
status <- c(status, ordered=TRUE)
会把status
编码为(3, 2, 1, 3)。对于字符型向量,因子水平默认按照字母顺序创建,即“Poor=3”、“Improved=2”、“Excellent=1”。你也可以通过levels
改变因子的顺序:
status <- c("Poor", "Improve", "Excellent", "Poor")
status <- c(status, ordered=TRUE, levels=c("Poor", "Improved", "Excellent"))
那么就会将status
编码为:“Poor=1”、“Improved=2”、“Excellent=3”
数值型变量可以用levels
和labels
来编码因子,例如男性编码为1,女性编码为2,那么:
sex <- facotr(sex, levels=c(1,2), labels=c("Male", "Female"))
把变量了转换成一个无序因子。
总的来说:
patientID <- c(1, 2, 3, 4)
age <- c(24, 34, 28, 52)
diabetes <- c("Type1", "Type2", "Type1", "Type1")
status <- c("Poor", "Improve", "Excellent", "Poor")
diabetes <- factor(diabetes)
status <- factor(status, ordered = TRUE, levels = c("Poor", "Improved", "Excellent"))
patientdata <- data.frame(patientID, age, diabetes, status)
str(patientdata)
## 'data.frame': 4 obs. of 4 variables:
## $ patientID: num 1 2 3 4
## $ age : num 24 34 28 52
## $ diabetes : Factor w/ 2 levels "Type1","Type2": 1 2 1 1
## $ status : Ord.factor w/ 3 levels "Poor"<"Improved"<..: 1 NA 3 1
2.2.6 列表
列表(list)是R数据类型中最为复杂的一种。列表就是一些对象的有序结合,允许你整合若干对象到单个对象名下。可以使用list()
创建列表:
mylist <- list(object1, object2, ...)
其对象可以是目前为止提到的任何结构。还可以为列表中的对象命名:
mylist <- list(name1=object1, name2=object2, ...)
例如:
g <- "My First List"
h <- c(25:30)
j <- matrix(c(1:10), nrow = 2)
k <- c("one", "two", "three")
mylist <- list(title=g, h, matrix=j, English=k)
mylist
## $title
## [1] "My First List"
##
## [[2]]
## [1] 25 26 27 28 29 30
##
## $matrix
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 3 5 7 9
## [2,] 2 4 6 8 10
##
## $English
## [1] "one" "two" "three"
可以通过双重括号指明某个成分的数字或名称来访问列表中的元素,例如mylist[[3]]
和mylist[["matirx"]]
均表示mylist
的第三个元素。对于命名的成分,也可以用mylist$matrix
来进行引用,例如:
mylist[[3]]
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 3 5 7 9
## [2,] 2 4 6 8 10
mylist[["matrix"]]
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 3 5 7 9
## [2,] 2 4 6 8 10
mylist$matrix
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 3 5 7 9
## [2,] 2 4 6 8 10
R中有很多函数的运行结果都是以列表的形式返回的,这是一个十分重要的数据结构。
2.3 数据的输入
2.3.1 从带分隔符的文本文件中导入数据
可以使用read.table()
从带分隔符的文本中导入数据。此函数可以读入一个表格格式的文件并将其保存为一个数据框,语法为:
mydataframe <- read.table(file, options)
其中,options是控制如何处理数据的选项,请查看help。
2.3.2 导入Excel数据
使用xlsx包可以读取Excel数据,首先在Console运行:
install.packages("xlsx")
然后运行:
library(xlsx)
read.xlsx(file, sheetIndex, header=TRUE)
其中,file
是对应的xlsx文件路径;sheetIndex
指定第几张工作表;header
指定第一行是否为变量名。详细见help。
2.3.3 导入Stata数据
可以使用readstata13
包,然后运行:
library(readstata13)
read.dta13(file)
即可。具体的选项请看help。
2.5 处理对象的实用函数
处理对象的常用函数有:
length(object) # 显示对象中元素/成分的数量
dim(object) # 显示对象的维度
str(object) # 显示某个对象的结构
class(object) # 显示对象的类或类型
mode(object) # 显示对象的模式
names(object) # 显示对象中各成分的名称
c(object1,...) # 将对象合并为一个向量
cbind(object1,...) # 按列合并对象
rbind(object1,...) # 按行合并对象
object # 输出某个对象
head(object) # 列出某个对象的开始部分
tail(object) # 列出某个对象的最后部分
ls() # 显示当前对象列表