在这种情况下,它可能会像鸭子一样走路,甚至像鸭子一样呱呱叫,但是
f
来自:
f <- factor(sample(letters[1:5], 20, rep=TRUE), letters[1:5])
dim(f) <- c(4,5)
虽然真的不是矩阵
is.matrix()
声称它严格来说是一个。尽可能成为矩阵
是.matrix()
关注,
f
只需要是一个向量
dim
属性通过将属性添加到
f
你通过了考试。然而,正如您所看到的,一旦您开始使用
f
作为一个矩阵,它很快就失去了使它成为一个因素的特性(你最终会处理级别或维度)。
原子向量类型实际上只有矩阵和数组:
-
必然的
-
整数
-
真实的
-
复杂的
-
字符串(或字符),以及
-
未经加工的
此外,正如@hadley提醒我的,您还可以使用列表矩阵和数组(通过设置
暗淡的
属性。例如,请参见
Matrices & Arrays
哈德利书中的一节,
高级R
.)
这些类型之外的任何内容都将通过
as.vector()
。这发生在
matrix(f, nrow = 3)
不是因为
f
是原子的
根据
is.atomic()
(返回
TRUE
对于
f
因为它在内部存储为整数
typeof(f)
回报
"integer"
)但因为它有
class
属性这将设置
OBJECT
内部表示的位
f
任何具有类的对象都应该通过
作为.vector()
:
matrix <- function(data = NA, nrow = 1, ncol = 1, byrow = FALSE,
dimnames = NULL) {
if (is.object(data) || !is.atomic(data))
data <- as.vector(data)
....
通过添加维度
dim<-()
是在不复制对象的情况下创建数组的快速方法,但这绕过了R在强制执行
f
通过其他方法连接到矩阵
matrix(f, nrow = 3) # or
as.matrix(f)
当您尝试使用处理矩阵的基本函数或使用方法分派时,就会发现这一点。请注意,将尺寸指定给
f
,
f
仍然是一流的
"factor"
:
> class(f)
[1] "factor"
这解释了
head()
行为你得不到
head.matrix
行为,因为
f
至少就S3机制而言,不是矩阵:
> debug(head.matrix)
> head(f) # we don't enter the debugger
[1] d c a d b d
Levels: a b c d e
> undebug(head.matrix)
以及
head.default
方法调用
[
有一个
factor
方法,因此观察到的行为:
> debugonce(`[.factor`)
> head(f)
debugging in: `[.factor`(x, seq_len(n))
debug: {
y <- NextMethod("[")
attr(y, "contrasts") <- attr(x, "contrasts")
attr(y, "levels") <- attr(x, "levels")
class(y) <- oldClass(x)
lev <- levels(x)
if (drop)
factor(y, exclude = if (anyNA(levels(x)))
NULL
else NA)
else y
}
....
这个
cbind()
行为可以从记录的行为(来自
?cbind
,强调我的):
功能
cbind
和
rbind
是
S3通用
, ...
....
在默认方法中,所有向量/矩阵必须是原子的
(参见
vector
)或列表。不允许使用表达式。语言
对象(如公式和调用)和配对列表将被强制
到列表:其他对象(如名称和外部指针)将
作为元素包含在列表结果中。
输入的任何类别
可能已被丢弃(特别是,因子被替换为
其内部代码)。
同样,事实是
f
是一流的
“因子”
因为默认值
cbind公司
方法将被调用,它将剥离级别信息并返回您观察到的内部整数代码。
在许多方面,你必须忽略或至少不完全信任
is.foo
函数告诉你,因为它们只是使用简单的测试来判断某个东西是否是
foo
对象
是.matrix()
和
是.atomic()
显然是错误的
f
(带尺寸)
从特定的角度来看
他们在执行方面也是正确的,或者至少可以从执行中理解他们的行为;我想
is.atomic(f)
不正确,但如果
“如果是原子类型”
R核心的意思是“类型”
类型(f)
然后
是.atomic()
是正确的。更严格的测试是
is.vector()
哪一个
f
失败:
> is.vector(f)
[1] FALSE
因为它具有超出
names
属性:
> attributes(f)
$levels
[1] "a" "b" "c" "d" "e"
$class
[1] "factor"
$dim
[1] 4 5
至于你应该如何得到一个因子矩阵,那么你不能,至少如果你想让它保留因子信息(级别的标签)。一种解决方案是使用字符矩阵,保留标签:
> fl <- levels(f)
> fm <- matrix(f, ncol = 5)
> fm
[,1] [,2] [,3] [,4] [,5]
[1,] "c" "a" "a" "c" "b"
[2,] "d" "b" "d" "b" "a"
[3,] "e" "e" "e" "c" "e"
[4,] "a" "b" "b" "a" "e"
我们存储了
f
以备将来使用,万一我们一路上丢失了矩阵的一些元素。
或者使用内部整数表示:
> (fm2 <- matrix(unclass(f), ncol = 5))
[,1] [,2] [,3] [,4] [,5]
[1,] 3 1 1 3 2
[2,] 4 2 4 2 1
[3,] 5 5 5 3 5
[4,] 1 2 2 1 5
您可以通过以下方式再次返回级别/标签:
> fm2[] <- fl[fm2]
> fm2
[,1] [,2] [,3] [,4] [,5]
[1,] "c" "a" "a" "c" "b"
[2,] "d" "b" "d" "b" "a"
[3,] "e" "e" "e" "c" "e"
[4,] "a" "b" "b" "a" "e"
使用数据帧似乎并不理想,因为数据帧的每个组件都将被视为一个单独的因素,而您似乎希望将数组视为一组级别的单个因素。
如果你真的想做你想做的事情,那就是有一个因子矩阵,那么你很可能需要创建自己的S3类来完成这个任务,再加上所有的方法
"factorMatrix"
,其中您将级别存储在因子矩阵旁边作为额外属性。那么你需要写
[.factorMatrix
,这将获取级别,然后使用默认值
[
方法,然后再次添加levels属性。你可以写
cbind公司
和
head
方法。然而,所需方法的列表将快速增长,但如果您使对象具有类
c("factorMatrix", "matrix")
(即继承自
"matrix"
类),您将获取
“矩阵”
类(这将删除级别和其他属性),这样您至少可以处理对象,并查看需要在哪里添加新方法来填充类的行为。