R语言的数据结构与转换
文章和代码已经归档至【Github仓库:github.com/timerring/d… 】或者公众号【AIShareLab】回复 R语言 也可获取。
任何数据分析的第一步都是按照所需要的格式创建数据集。在 R 中,这个任务包括两个步骤:首先选择一种数据结构来存储数据,然后将数据输入或者导入这个数据结构中。下面介绍 R 中用于存储数据的多种数据结构。
R 的数据结构
- 在大多数情况下,结构化的数据是一个由很多行和很多列组成的数据集。在 R 中,这种数据集被称为数据框。
- 在学习数据框之前,我们先来认识一些用于存储数据的数据结构:向量、因子、矩阵、数组和列表。
1.1 向量
向量(vector)是用于存储数值型、字符型、逻辑型数据的一维数组。标量可以看作是只含有一个元素的向量。函数 c( )
可用来创建向量,例如:
x1 <- c(2, 4, 1, -2, 5)
x2 <- c("one", "two", "three")
x3 <- c(TRUE, FALSE, TRUE, FALSE)
这里 x1 是数值型向量,x2 是字符型向量,而 x3 是逻辑型向量。每一个向量中的数据类型必须一致。如果想创建有规律的向量,R 提供了一些简便的操作和函数,例如:
x4 <- 1:5 # 等价于x4 <- c(1, 2, 3, 4, 5)
x5 <- seq(from = 2, to = 10, by = 2) # 等价于x5 <- c(2, 4, 6, 8, 10)
x6 <- rep("a", times = 4) # 等价于x6 <- c("a", "a", "a", "a")
有时候我们只想使用向量中的某个部分,即选取向量的子集。假设有一个从 3 到 100 的步长为 7 的整数向量,那么第 5 个数的值是多少呢?
x <- seq(from = 3, to = 100, by = 7)
# 显示第5个元素
x[5]
# 显示第4,6,7个元素
x[c(4, 6, 7)]
在方括号“[ ]”中的数字被称为 下标
,它指定向量的索引位置。在上面的命令里,x[5] 表示向量的第 5 个元素,其值为 31。
下标中的向量可以取负值,表示去除指定位置上的元素。例如,要去掉 x 的前4 个元素,可以输入下面的代码(注意命令里的括号):
x[-(1:4)]
R 中的运算都是向量化的,例如:
weight <- c(68, 72, 57, 90, 65, 52)
height <- c(1.75, 1.80, 1.65, 1.90, 1.72, 1.65)
bmi <- weight / height ^ 2
bmi
在上面计算 bmi 的过程中,运算符“^”被循环使用了,所以计算的结果仍然是一个向量。如果参与运算的向量的长度不一致,R 会自动补全后计算,补全的规则是循环短的向量,同时给出警告信息。
a <- 1:5
b <- 1:3
a + b
# Warning message in a + b:
# “longer object length is not a multiple of shorter object length”
# 2 4 6 5 7
常用的统计函数
length(x) | 求 x 中元素的个数 |
mean(x) | 求 x 的算术平均值 |
median(x) | 求 x 的中位数 |
var(x) | 求 x 的样本方差 |
sd(x) | 求 x 的样本标准差 |
range(x) | 求 x 的全距 |
min(x) | 求 x 的最小值 |
max(x) | 求 x 的最大值 |
quantile(x) | 求 x 的分位数 |
sum(x) | 求 x 中所有元素的和 |
scale(x) | 将 x 标准化 |
1.2 因子
一般来说,变量有数值型、名义型和有序型之分。
名义型变量是没有顺序关系的分类变量,例如人的性别、血型、民族等。而有序型变量是有层级和顺序关系的分类变量,如患者的病情(较差、好转、很好)。名义型变量和有序型变量在 R 中称为因子(factor)。
因子在 R 中非常重要,它决定了数据的展示和分析方式。数据存储时因子经常以整数向量形式存储。所以在进行数据分析之前,经常需要将它们用函数 factor( )
转换为因子。
# 先定义了一个变量 sex 表示性别,假设其取值 1 表示男性,2 表示女性。
sex <- c(1, 2, 1, 1, 2, 1, 2)
# 接着用函数 factor( ) 将变量 sex 转换成了因子并存为对象 sex.f,其中参数 levels 表示原变量的分类标签值,参数 labels 表示因子取值的标签。
sex.f <- factor(sex,
levels = c(1, 2),
labels = c("Male", "Female"))
sex.f
# ============ 输出 =============
# Male Female Male Male Female Male Female
# **Levels**:
# 'Male''Female'
注意,这两个参数在赋值时需要一一对应,R 会将它们相关联。因子型变量与一般的字符型变量的区别就是它有一个水平(level)属性。因子的属性可以使用函数 levels( )
查看:
levels(sex.f)
# 'Male''Female'
改变因子水平的排列顺序 → 改变参考组
在统计模型中,对于因子型变量,R 会将其第一个水平当作参考组。很多时候我们需要改变因子水平的排列顺序以改变参考组,这可以通过两种方法实现。第一种方法是在函数 factor( ) 中改变参数 levels 和 labels 的排列顺序,例如:
sex.f1 <- factor(sex, levels = c(2, 1), labels = c("Female", "Male"))
sex.f1
# Male Female Male Male Female Male Female
# **Levels**:
# 'Female' 'Male'
第二种方法是使用函数 relevel( )
:
sex.f1 <- relevel(sex.f, ref = "Female")
sex.f1
# Male Female Male Male Female Male Female
# **Levels**:
# 'Female' 'Male'
序因子:ordered = TRUE
要表示有序因子,需要在函数 factor ( ) 里指定参数 ordered = TRUE。例如:
status <- c(1, 2, 2, 3, 1, 2, 2)
status.f <- factor(
status,
levels = c(1, 2, 3),
labels = c("Poor", "Improved", "Excellent"),
ordered = TRUE
)
status.f
# PoorImprovedImprovedExcellentPoorImprovedImproved
1.3 矩阵
矩阵(matrix)是一个由行和列组成的二维数组。矩阵里的每个元素具有相同的模式(数值型、字符型或逻辑型)。在大多数情况下,矩阵里的元素是数值型的,它具有很多数学特性和运算方式,可以用来进行统计计算,例如因子分析、广义线性模型等。
1.3.1 创建:matrix( )
函数 matrix( )
常用于创建矩阵,例如:
M <- matrix(1:6, nrow = 2)
M
R 会根据向量的长度和参数 nrow 设定的行数自动计算列数。参数 byrow 默认为 FALSE,即按列将数值进行排列,如果需要按行排列,只需将参数 byrow 设为 TRUE。
常见的矩阵运算都可以在R 中实现,如矩阵加法、矩阵乘法、求逆矩阵、矩阵转置、求方阵的行列式、求方阵的特征值和特征向量等。
1.3.2 相乘:%*%
矩阵乘法中要求第一个矩阵的列数等于第二个矩阵的行数,其运算符为 %*%
。
先创建两个矩阵:
mat1 <- matrix(1:6, nrow = 3)
mat1
mat2 <- matrix(5:10, nrow = 2)
mat2
# 函数dim( )可以得到矩阵的维数,即行数和列数
dim(mat1)
# 32
dim(mat2)
# 23
mat1 %*% mat2
1.3.3 转置:t( )
矩阵的转置运算就是把矩阵的行和列互换。例如,求矩阵 mat1 的转置矩阵:
t(mat1)
1.3.4 行列式和逆矩阵:det( )、solve( )
求方阵的行列式和逆矩阵分别可以使用函数 det( )
和函数 solve( )
实现,例如:
mat3 <- matrix(1:4, nrow = 2)
det(mat3)
# -2
1.3.5 按行、列求和或者求平均:rowSums、colSums、rowMeans、ColMeans
例如:
rowSums(mat1)
colSums(mat1)
rowMeans(mat1)
colMeans(mat1)
1.4 数组
通常所说的数组(array)指的是多维数组,它与矩阵类似,但是维数大于 2。数组有一个特殊的维数(dim)属性。
下面的命令给一个向量加上维数后定义了一个数组,请注意数值的排列顺序。
由于 notebook 上显示的数组不太美好,建议使用
print()
。以下代码在显示数组时会额外加上 print()。
A <- 1:24
dim(A) <- c(3, 4, 2)
# A # notebook 上数组显示不太正常,使用 print() 可以解决
print(A)
上面的数组还可以通过函数 array( )
创建,并给各个维度添加名称和标签。
dim1 <- c("A1", "A2", "A3")
dim2 <- c("B1", "B2", "B3", "B4")
dim3 <- c("C1", "C2")
print(array(1:24, dim = c(3, 4, 2), dimnames = list(dim1, dim2, dim3)))
1.5 列表
列表(list)是 R 中最灵活也最复杂的一种数据结构,它可以由不同类型的对象混合组成。例如,它可以是向量、数组、表格和任意类型对象的组合。
list1 <- list(a = 1, b = 1:5, c = c("red", "blue", "green"))
list1
# $a
# 1
# $b
# 1 2 3 4 5
# $c
# 'red''blue''green'
在普通的数据分析中,创建列表并不是一项常见的任务。很多函数的返回值是一个列表。例如:
# 为了使结果具有可重复性,我们在该命令前用函数 set.seed( ) 设置了生成随机数的种子。如果不设定种子,每次显示的结果很可能不同。
set.seed(123)
# 用函数 rnorm( ) 从标准正态分布中生成了一个由 10 个数组成的随机样本。
dat <- rnorm(10)
# 用函数 boxplot( ) 对这个随机样本作**箱线图**,并把结果保存为 bp。
bp <- boxplot(dat)
# 函数 class( ) 用于查看对象的类型,这里 bp 是一个列表。
class(bp)
# 'list'
查看这个列表里面的内容:
这里列表 bp 包含了多个对象,如果想查看或使用某一个对象,只需用“$
”符号引用。例如,要查看列表 bp 中的对象 stats 的内容,可以输入 bp$stats
。对列表中其他对象感兴趣,请移步 boxplot.stats
的说明文档。
1.6 数据框
数据框(dataframe)是一个由行和列组成的二维结构,其中行表示观测(observation)或记录(record),列表示变量(variable)或指标(indicator)。数据框与 Excel、SAS 和SPSS 中的数据集类似。数据框看起来与矩阵很相似,而且矩阵的很多操作也适用于数据框,如子集的选择。
与矩阵不同的是,数据框里不同的列可以是不同模式(数值型、字符型等)的数据。数据框可以通过函数 data.frame( ) 创建。例如,下面的代码创建了一个包含 5 个观测对象、4 个变量的数据框:
ID <- 1:5
sex <- c("male", "female", "male", "female", "male")
age <- c(25, 34, 38, 28, 52)
pain <- c(1, 3, 2, 2, 3)
pain.f <- factor(pain, levels = 1:3, labels = c("mild", "medium", "severe"))
patients <- data.frame(ID, sex, age, pain.f)
patients
数据框本质上也是一种列表,要显示或使用数据框的某一变量(列),可以使用 $
符号加上变量名。例如:
patients$age
mean(patients$age)
大部分结构化的医学数据集均以数据框的形式呈现,因此,数据框是最常处理的数据结构。
数据类型的转换:is.、as.
在进行数据分析时,分析者需要对数据的类型熟稔于心,因为数据分析方法的选择与数据的类型是有密切联系的。R 提供了一系列用于判断某个对象的数据类型的函数,还提供了将某种数据类型转换为另一种数据类型的函数。这些函数都存在于基本包 base 里,下面列出了其中的一部分常用函数:
数据类型的判断与转换函数
is.numeric( ) | as.numeric( ) |
is.character( ) | as.character( ) |
is.logical( ) | as.logical( ) |
is.factor( ) | as.factor( ) |
is.vector( ) | as.vector( ) |
is.matrix( ) | as.matrix( ) |
is.array( ) | as.array( ) |
is.data.frame( ) | as.data.frame( ) |
is.list( ) | as.list( ) |
is.table( ) | as.table( ) |
以 is.
开头的函数的返回值为 TRUE 或 FALSE,而以 as.
开头的函数将对象转换为相应的类型。例如:
x <- c(2, 5, 8)
is.numeric(x)
# TRUE
is.vector(x)
# TRUE
y <- as.character(x)
y
# '2''5''8'
is.numeric(y)
# FALSE
is.character(y)
# TRUE
z <- c(TRUE, FALSE, TRUE, FALSE)
is.logical(z)
# TRUE
as.numeric(z)
# 1 0 1 0
参考:赵军《R语言医学数据分析实战》