本期目录:
因子
矩阵
数组
列表
创建列表
列表取子集
修改名字
添加/删除列表元素
列表展开
今天继续介绍R语言中的数据结构:因子、列表、矩阵、数组
因子
多数变量可归为名义型、有序型或连续型变量。
名义型变量(nominal-variable)是没有顺序之分的类别变量。糖尿病类型diabetes
(Type1
、Type2
)是名义型变量的一例。即使在数据中Type1
编码为1
而Type2
编码为2`,这也并不意味着二者是有序的。
有序型变量(ordinal-variable)表示一种顺序关系,而非数量关系。病情status
(poor
、improved
、excellent
)是有序型变量的一个示例。很明显病情为poor
(较差)病人的状态不如improved
(病情好转)的病人,但并不知道相差多少。
连续型变量(continuous-variable)可以呈现为某个范围内的任意值,并同时表示了顺序和数量。年龄Age
就是一个连续型变量,它能够表示像14.5或22.8这样的值以及其间的其他任意值。
类别(名义型)变量和有序类别(有序型)变量在R中称为因子(factor)。因子在R中非常重要,因为它决定了数据的分析方式以及如何进行视觉呈现。
创建因子
因子可以通过函数factor()
创建。比如用以下代码即可创建一个名为status
的因子型向量:
status "Poor", "Improved", "Excellent", "Poor"))
status
## [1] Poor Improved Excellent Poor
## Levels: Excellent Improved Poor
此时的status
是一个因子型向量,也是没有顺序之分的名义型变量,虽然给出了Levels
,但是并不能表示它们之间有高低顺序,默认的水平顺序是按照首字母排列的。
因子水平和标签
如果要更改不同水平的顺序,可以使用以下代码:
# 指定顺序
levels(status) "Poor", "Excellent", "Improved")
status
## [1] Improved Excellent Poor Improved
## Levels: Poor Excellent Improved
或者直接在factor()
中指定:
status "Poor", "Improved", "Excellent", "Poor"),
levels = c("Poor", "Excellent", "Improved")
)
status
## [1] Poor Improved Excellent Poor
## Levels: Poor Excellent Improved
对于不同的水平,你也可以修改它的显示标签:
status "Poor", "Improved", "Excellent", "Poor"),
levels = c("Poor", "Excellent", "Improved"),
labels = c("第一水平", "第二水平", "第三水平")
)
status
## [1] 第一水平 第三水平 第二水平 第一水平
## Levels: 第一水平 第二水平 第三水平
如果想要把某个变量变成有序型变量,可以使用ordered=TRUE
参数:
status "Poor", "Improved", "Excellent", "Poor"),
ordered = T
)
status
## [1] Poor Improved Excellent Poor
## Levels: Excellent
可以看到此时结果中的Levels
有了小于号,用来表示高低顺序。
Note
名义型变量和有序型变量在进行统计分析时会使用完全不同的方法,比如在进行线性回归或者cox回归分析时,名义型变量的默认方法是哑变量编码,而有序型变量的编码方式是正交多项式编码。相关内容可参考:分类变量进行回归分析时的编码方案
计数
table()
函数可用于查看每个水平的数量:
table(status)
## status
## Excellent Improved Poor
## 1 1 2
如果和length()
同用则可以快速计算有几个水平(或类别,在分类变量中很常用):
# 查看有几个类别
length(table(status))
## [1] 3
因子类型是R语言中处理分类变量非常有用的类型,在画图的时候也可以使用因子规定好顺序,方便对图形进行排列。
forcats
包提供了一套专门用于处理因子的函数,非常实用,大家可以阅读以下文章进一步了解:
矩阵
矩阵,matrix,表面看起来像一个数据框,有行和列,也是二维的,但是矩阵里面的所有元素都必须是同一类型的,比如必须都是数值型,或者必须都是字符型,或者必须都是逻辑型,等。
可通过函数matrix()
创建矩阵。一般使用格式为:
myymatrix byrow = 是不是按行进行填充?,
dimnames = list(行名, 列名))
其中vector
是矩阵所需要的元素,nrow
和ncol
用以指定行和列的数量,dimnames
包含了以字符型向量表示的行名和列名(这个参数可以省略不写)。选项byrow
则表明矩阵应当按行填充(byrow=TRUE
)还是按列填充(byrow=FALSE
),默认情况下按列填充。
以下代码创建了一个5行、4列的矩阵,用1~20这20个数字进行填充,并且定义了行的名字和列的名字,并且是按列进行填充:
y 1:20, nrow=5, ncol=4,
dimnames = list(c("行1","行2","行3","行4","行5"),
c("列1","列2","列3","列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
对矩阵取行和列的语法和数据框完全一样,使用方括号即可,这里就不重复了。
y[1,2]
## [1] 6
数组
数组,array,类似矩阵,但可以有更多的维度(行、列以外的方向),比如可以有3维甚至更多,这种结构可能是你无法想象的(超过3维的东西你能想象出来吗?),但是幸好这个结构我们用的不多。
数组可通过array
函数创建,形式如下:
myarray
其中vector
包含了数组中的数据,dimensions
是一个数值型向量,给出了各个维度下标的最大值,而dimnames
是可选的、各维度名称标签的列表。
以下代码创建一个三维数组(234):
dim1 "A1", "A2")
dim2 "B1", "B2", "B3")
dim3 "C1", "C2", "C3", "C4")
z 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
列表
列表,list,是除了数据框之外第二重要的数据结构,甚至可以说是最重要的数据结构,但同时也是最复杂的一种结构。
列表是一个大型的存储结构,里面啥都能放。比如,可以包含不同类型的数据,也可以包含其他数据结构,如向量、矩阵或数据框等,列表中也可以包含列表。
创建列表
可以使用函数list()创建列表,使用语法为:
mylist ...)
其中的对象可以是目前为止讲到的任何结构。你还可以为列表中的对象命名:
mylist ...)
以下是一个创建列表的示例,我们先创建了5个不同类型的对象,然后把这些对象全部放到1个列表中:
g "My First List" # 字符串
h 25, 26, 18, 39) # 数值型向量
j 1:10, nrow=5) # 矩阵
k "one", "two", "three") # 字符型向量
l "apple",1,TRUE) # 列表
# 放到1个列表中
mylist 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"
##
## [[5]]
## [[5]][[1]]
## [1] "apple"
##
## [[5]][[2]]
## [1] 1
##
## [[5]][[3]]
## [1] TRUE
可以看出列表的成分非常复杂,上面的列表mylist
的长度为5,因为有5个成分:
# 查看长度
length(mylist)
## [1] 5
前两个成分是有名字的:title
和ages
,后三个成分没有名字,但是有序号,分别是[[3]]
、[[4]]
、[[5]]
。
列表取子集
如果你要提取列表中的成分(或者叫对列表取子集),可以直接使用序号或者名字:
mylist[2] # 取第2个成分
## $ages
## [1] 25 26 18 39
mylist["title"] # 取第一个成分
## $title
## [1] "My First List"
注意此时得到的对象仍然是list
:
class(mylist[2])
## [1] "list"
class(mylist["title"])
## [1] "list"
列表中还有一个特殊的操作,也就是[[]]
,两个中括号,这样可以直接提取到具体的内容:
# 直接提取具体的内容
mylist[["title"]]
## [1] "My First List"
# 此时得到的是字符型向量
class(mylist[["title"]])
## [1] "character"
或者可以使用$
,也可以直接得到具体的内容,但是这种方法只能用于有名字的时候:
mylist$title
## [1] "My First List"
如果使用了[[]]
或者$
符号取子集后,得到的是具体的内容,我们可以继续通过[]
选择其中的元素:
# 取第2个对象中的第1个元素
mylist[[2]][1]
## [1] 25
修改名字
如果要给列表中的成分添加/修改/删除名字,也是使用names()
:
# 给第3-5个对象添加名字
names(mylist)[3:5] "名字3","名字4","名字5")
# 或者:
names(mylist)[c(3:5)] "名字3","名字4","名字5")
# 查看结果
names(mylist)
## [1] "title" "ages" "名字3" "名字4" "名字5"
#修改第一个成分的名字:
names(mylist)[1] "改个名字"
names(mylist)
## [1] "改个名字" "ages" "名字3" "名字4" "名字5"
删除名字:
# 删除所有名字
names(mylist) NULL
names(mylist) # 此时再查看名字已经没有了
## NULL
添加/删除列表元素
如果要向列表中添加新的成分:
mylist[["新的元素"]] 1,2,3)
mylist
## [[1]]
## [1] "My First List"
##
## [[2]]
## [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"
##
## [[5]]
## [[5]][[1]]
## [1] "apple"
##
## [[5]][[2]]
## [1] 1
##
## [[5]][[3]]
## [1] TRUE
##
##
## $新的元素
## [1] 1 2 3
删除列表中的成分:
# 删除第一个成分
mylist 1]
mylist
## [[1]]
## [1] 25 26 18 39
##
## [[2]]
## [,1] [,2]
## [1,] 1 6
## [2,] 2 7
## [3,] 3 8
## [4,] 4 9
## [5,] 5 10
##
## [[3]]
## [1] "one" "two" "three"
##
## [[4]]
## [[4]][[1]]
## [1] "apple"
##
## [[4]][[2]]
## [1] 1
##
## [[4]][[3]]
## [1] TRUE
##
##
## $新的元素
## [1] 1 2 3
# 或者
mylist$新的元素 NULL
mylist
## [[1]]
## [1] 25 26 18 39
##
## [[2]]
## [,1] [,2]
## [1,] 1 6
## [2,] 2 7
## [3,] 3 8
## [4,] 4 9
## [5,] 5 10
##
## [[3]]
## [1] "one" "two" "three"
##
## [[4]]
## [[4]][[1]]
## [1] "apple"
##
## [[4]][[2]]
## [1] 1
##
## [[4]][[3]]
## [1] TRUE
列表展开
把列表展开成向量:
unlist(mylist)
##
## "25" "26" "18" "39" "1" "2" "3" "4" "5" "6"
##
## "7" "8" "9" "10" "one" "two" "three" "apple" "1" "TRUE"
class(unlist(mylist))
## [1] "character"
str(unlist(mylist)) # 命名字符型向量
## Named chr [1:20] "25" "26" "18" "39" "1" "2" "3" "4" "5" "6" "7" "8" "9" ...
## - attr(*, "names")= chr [1:20] "" "" "" "" ...
掌握了这些基本的数据结构和常用操作后,就算是正式入门R语言了,后面的章节会继续一些常用的数据处理操作。