属性
属性描述了对象所代表的内容以及R解释该对象的方式。很多时候两个对象之间的唯一差别就在于它们的属性不同。下表展示了一些重要的属性。很多常见的属性都是针对常见的数值型数据对象而言的:像数组、矩阵和数据框。
属性 | 描述 |
---|---|
class | 对象的类 |
comment | 对象的注解;一般用于描述对象的含义 |
dim | 对象的维度 |
dimnames | 与对象的每个维度相关的名字 |
names | 返回对象的名字属性。返回结果取决于对象的类型,对于数据框对象会返回数据框的列名,对于数组会返回数组中被命名元素的名字 |
row.names | 对象的行名 |
tsp | 对象的起始点。对时间序列对象很有用 |
levels | 因子型变量的水平 |
标准使用方法:对于对象x和属性a,一般用a(x)来查询x的a属性。
这个操作也可以改变对象的属性。
我们可以通过attributes
函数获得一个包含对象所有属性的列表。
> m <- matrix(data=1:12, nrow=4, ncol=3,
+ dimnames=list(c("r1","r2","r3","r4"),c("c1","c2","c3")))
> m
c1 c2 c3
r1 1 5 9
r2 2 6 10
r3 3 7 11
r4 4 8 12
> attributes(m)
$dim
[1] 4 3
$dimnames
$dimnames[[1]]
[1] "r1" "r2" "r3" "r4"
$dimnames[[2]]
[1] "c1" "c2" "c3"
用dim
和dimnames
函数可以直接获取对应属性的信息。
> dim(m)
[1] 4 3
> dimnames(m)
[[1]]
[1] "r1" "r2" "r3" "r4"
[[2]]
[1] "c1" "c2" "c3"
存在简便的函数获取行名和列名:
> colnames(m)
[1] "c1" "c2" "c3"
> rownames(m)
[1] "r1" "r2" "r3" "r4"
有意思的是,我们可以通过简单地改变属性将矩阵转化为其他类的对象。例如我们通过移除对象的维度属性,达到改变类型和类的目的。
> dim(m) <- NULL
> m
[1] 1 2 3 4 5 6 7 8 9 10 11 12
> class(m)
[1] "integer"
> typeof(m)
[1] "integer"
下面我们来比较一下普通一维数组和二维数组的异同。
先创建一个数组a:
> a <- array(1:12, dim=c(3,4))
> a
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
然后,定义一个包含相同对象的向量:
> b <- 1:12
> b
[1] 1 2 3 4 5 6 7 8 9 10 11 12
我们可以用方括号来操作a中的元素,但对b不能用同样的方式(因为对象b没有任何维度)。
> a[2,2]
[1] 5
> b[2,2]
Error in b[2, 2] : 量度数目不对
咦,这连个对象在R里面是不是相同的啊?下面用==
看下:
> a == b
[,1] [,2] [,3] [,4]
[1,] TRUE TRUE TRUE TRUE
[2,] TRUE TRUE TRUE TRUE
[3,] TRUE TRUE TRUE TRUE
结果表明对象的所有元素都是相同的。但这不意味着这两者完全一样的,我们自己也能很明显感觉它们的差异。
R中有一个all.equal
函数可以用来比较两个对象的数据和维度以甄别两个对象是否近乎相同,若不同则会返回其原因。
> all.equal(a,b)
[1] "Attributes: < Modes: list, NULL >"
[2] "Attributes: < Lengths: 1, 0 >"
[3] "Attributes: < names for target but not for current >"
[4] "Attributes: < current is not list-like >"
[5] "target is matrix, current is numeric"
如果我们只care两个对象是不是完全一致,而不关心不一致的原因,可以使用identical
函数。
> identical(a, b)
[1] FALSE
通过赋予对象b一个维度属性,可以将b转化为一个与a相同的数组。
> dim(b) <- c(3, 4)
> b[2,2]
[1] 5
> all.equal(a,b)
[1] TRUE
> identical(a,b)
[1] TRUE
类
对象的类是对象的属性之一。对于简单的对象而言,其类和类型是有紧密联系的。然而,对于复合型对象,两者则可能不同(最常见的是数据框,你创建一个然后用class
与typeof
函数看看就知道了)。
下面是一个简单数值型向量的类型和类:
> x <- c(1,2,3)
> typeof(x)
[1] "double"
> class(x)
[1] "numeric"
与改变其他属性的操作一样,我们可以改变R对象所属的类。例如,在计算机内部,因子是通过整型数据以及整型数据到因子水平的映射来实现的(整型数据占的存储空间较少且固定,因此比字符向量更高效)。
在调用class
函数或者typeof
函数时,对于有些对象,我们需要对其进行引用以防止其在调用时被执行。比如,我们想查询符号x而不是x所指向的对象的类型时,用如下操作:
> x = 1
> class(quote(x))
[1] "name"
> typeof(quote(x))
[1] "symbol"
# 观察区别
> class(x)
[1] "numeric"
> typeof(x)
[1] "double"
学习整理自《R核心技术手册》