我在apply
找到了一些奇怪的行为。
假设我有一个有序变量的任意矩阵
set.seed(4)
x <- ordered(sample(1:10, size=4, replace=T))
y <- ordered(sample(1:10, size=4, replace=T))
z <- ordered(sample(1:10, size=4, replace=T))
data1 <- data.frame(x,y,z)
现在我想获得每个变量的排名。我可以通过两种方式做到这一点:
使用for循环:
rankmat1 <- data1
for(i in 1:dim(data1)[2]){
rankmat1[, i] <- rank(data1 [, i])
}
或apply
rankmat2 <- apply(data1, 2, rank)
所以,这是原始级别:
data1
x y z
1 6 9 10
2 1 3 1
3 3 8 8
4 3 10 3
以下是正确的排名:
rankmat1
x y z
1 4.0 3 4
2 1.0 1 1
3 2.5 2 3
4 2.5 4 2
但为什么来自apply
的这些排名不同?
rankmat2
x y z
[1,] 4.0 4 2
[2,] 1.0 2 1
[3,] 2.5 3 4
[4,] 2.5 1 3
order
也会发生这种情况:
ordermat1 <- data1
for(i in 1:dim(data1 )[2]){
ordermat1[, i] <- order(data1 [, i])
}
ordermat2 <- apply(data1, 2, order)
ordermat1
x y z
1 2 2 2
2 3 3 4
3 4 1 3
4 1 4 1
ordermat2
x y z
[1,] 2 4 2
[2,] 3 2 1
[3,] 4 3 4
[4,] 1 1 3
答案 0 :(得分:4)
根据OP的要求,这里有一个详细的解释,可以帮助其他R用户逃避陷阱。
正如乔兰所指出的,apply
将数据框强制转换为矩阵,从而用字符替换有序因子。所以,原始data.frame
data1
x y z
1 6 9 10
2 1 3 1
3 3 8 8
4 3 10 3
变为
as.matrix(data1)
x y z
[1,] "6" "9" "10"
[2,] "1" "3" "1"
[3,] "3" "8" "8"
[4,] "3" "10" "3"
字符按词汇顺序排序。因此,将y
列排序为字符返回
sort(c("9", "3", "8", "10"))
[1] "10" "3" "8" "9"
而不是
sort(c(9, 3, 8, 10))
[1] 3 8 9 10
这解释了为什么apply
会在此处为rank
操作返回不同的结果。
您可以使用lapply
来计算数据框每列的排名。
as.data.frame(lapply(data1, rank))
x y z
1 4.0 3 4
2 1.0 1 1
3 2.5 2 3
4 2.5 4 2
lapply
返回一个列表,数据框是一种特殊的列表。
避免sapply
因为sapply
获取lapply
的输出并将其“简化”为它认为合适的内容。在这里,
sapply(data1, rank)
x y z
[1,] 4.0 3 4
[2,] 1.0 1 1
[3,] 2.5 2 3
[4,] 2.5 4 2
返回一个矩阵(再次!),需要强制转换为数据帧。 (参见Patrick Burns撰写的The R Inferno第8.3.20章。无论如何,这篇文章是一本很好的读物。)
OP没有说明为什么他需要使用有序因子。 因素(无论是否有序)apply
将按预期工作。
set.seed(4)
x2 <- sample(1:10, size = 4, replace = T)
y2 <- sample(1:10, size = 4, replace = T)
z2 <- sample(1:10, size = 4, replace = T)
data2 <- data.frame(x2, y2, z2)
data2
x2 y2 z2
1 6 9 10
2 1 3 1
3 3 8 8
4 3 10 3
apply(data2, 2, rank)
x2 y2 z2
[1,] 4.0 3 4
[2,] 1.0 1 1
[3,] 2.5 2 3
[4,] 2.5 4 2
(不过,最好在数据框中使用lapply
代替apply
。
当我开始学习R
时,我被函数ordered()
的名称误导了。我花了一段时间才明白它创造了一种特殊的因素。同样,我花了一些时间来确定sort()
和order()
之间的差异以及何时适当地使用哪个函数。
答案 1 :(得分:0)
我不确定为什么提取原因恰好适用于函数。但您可以尝试sapply
来解决问题。
rankmat3 <- as.data.frame(sapply(data1, rank))结果如下:
rankmat3 x y z 1 4.0 3 4 2 1.0 1 1 3 2.5 2 3 4 2.5 4 2