数据结构
R 语言的基础数据结构可以按照维度来划分(1 维、 2 维…n 维);也可以按照它们所包含的数据类型是否相同来划分。 这样就产生了五种数据类型,它们是数据分析中最常用的:
Homogeneous | Heterogeneous | |
---|---|---|
1d | Atomic vector | List |
2d | Matrix | Data frame |
nd | Array |
向量(vector)
向量包括:原子向量 (Atomic vector) 和列表 (List)。兩者都属于一维数据, 两者的区别在于: 原子向量中的所有元素都必须是相同的类型;而列表中的元素可以是不同的类型
is.vector()
并不能测试一个对象是不是向量。 相反,仅当对象是除了名字以外,不包含其它属性时,它才返回TRUE
。 所以,请使用is.atomic(x) || is.list(x)
来测试一个对象是不是向量。
向量具有三个共同属性:
- 类型,
typeof()
,它是什么 - 长度,
length()
,它包含有多少元素 - 属性,
attributes()
,额外的任意元数据
原子向量 (Atomic vector)
- 原子向量类型:逻辑类型 (logical)、 整数类型 (integer)、 双精度数值类型 (double)、 字符类型 (character)、 复数类型 (complex)、 raw类型。
- 缺失值用
NA
表示,是一个长度为1的逻辑向量,NA可根据所处整体环境强制转换成正确的类型,或者使用NA_real_
(双精度浮点数向量)、NA_integer_
和NA_character_
来创建一系列确定类型的NA
typeof
确定具体的数据类型,is
开头的函数(如:is.integer
)来确定是否属于某一特定类型is.atomic()
是检测原子向量最通用的- 强制转换:一个原子向量中的所有元素都必须是相同的类型。 所以,当你试图合并不同类型的数据时,将向最灵活的类型进行强制转换。 以灵活程度排序,从小到大依次为:逻辑、 整数、双精度浮点数和字符。
- 如果转换遇到歧义,则需要使用
as.character()
、as.double()
、as.integer()
或者as.logical()
等函数,进行明确的强制转换。
列表(List)
c()可以将几个向量合并成一个。 如果原子向量和列表同时存在,那么在合并之前, c()会将原子向量强制转换成列表
x <- list(list(1, 2), c(3, 4))
y <- c(list(1, 2), c(3, 4))
str(x)
#> List of 2
#> $ :List of 2
#> ..$ : num 1
#> ..$ : num 2
#> $ : num [1:2] 3 4
str(y)
#> List of 4
#> $ : num 1
#> $ : num 2
#> $ : num 3
#> $ : num 4
列表用来建立 R 语言中的许多更加复杂的数据结构。 比如, 数据框和其他复杂对象
is.list(mtcars)
#> [1] TRUE
这里说明一点:data.frame是比list更为复杂的数据结构
属性(Attributes)
所有的对象都可以拥有任意多个附加属性, 附加属性用来存取与该对象相关的元数据。 属性可以看做是已命名的列表(带有不重复的名字)。 属性可以使用 attr()
函数一个一个的访问,也可以使用 attributes()函数一次性访问。
y <- 1:10
attr(y, "my_attribute") <- "This is a vector"
attr(y, "alpha") <- "This is a vector"
attr(y, "my_attribute")
#> [1] "This is a vector"
attributes(y)
#> $my_attribute
#> [1] "This is a vector"
#>
#> $alpha
#> [1] "This is a vector"
attr(y, "my_attribute") <- "alpha"
attributes(y)
#> $my_attribute
#> [1] "alpha"
#>
#> $alpha
#> [1] "This is a vector"
structure()
函数返回一个带有属性的对象, 也可以用来修改属性
structure(y, alpha = "alpha")
#> [1] 1 2 3 4 5 6 7 8 9 10
#> attr(,"my_attribute")
#> [1] "alpha"
#> attr(,"alpha")
#> [1] "alpha"
默认情况下,当修改向量时,数据的大多数属性会丢失,但有三种重要的属性不会丢失:名字(name),维度(dimension),类(class)
三个特殊属性需要使用特定函数
names(x)
、class(x)
和dim(x)
访问,而不是attr(x, "names")
、attr(x, "class")
和attr(x, "dim")
数据框(data frame)
数据框是由等长向量构成的列表。 它也是二维结构,所以它具有矩阵和列表双重属性。也就是说,数据框拥有 names()
、 colnames()
和 rownames()
,尽管 names()
和 colnames()
对数据框来说是一样的。 数据框的 length()
是列表的长度,所以和 ncol()
相同; nrow()
则得到行数。
由于数据框是一个包含向量的列表,所以数据框的某个是列表类型是有可能的:
df <- data.frame(x = 1:3)
df$y <- list(1:2, 1:3, 1:4)
df
#> x y
#> 1 1 1, 2
#> 2 2 1, 2, 3
#> 3 3 1, 2, 3, 4
当把列表传入
data.frame()
函数时,该函数将试图把列表的每一个元素都放到单独的一列中。一种绕开的方法是使用I()
函数,它使得data.frame()
把列表看成一个整体单元
R中的对象
S3对象
S3 对象是由原子向量、数组和列表组成的,所以你可以使用上面描述的技术对 S3 对象进行取子集操作。 你可以通过 str()
函数获得的它们的结构信息。
S4对象
对 S4 对象来说,有另外两种取子集操作符: @
(相当于$
)和 slot()
(相当于[[
)。 @
比$
更加严格,如果槽(slot)不存在,那么它会返回错误。