使用带有排序因子的data.frame上的排序和顺序时的奇怪行为

时间:2016-06-15 01:36:30

标签: r

我在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

2 个答案:

答案 0 :(得分:4)

根据OP的要求,这里有一个详细的解释,可以帮助其他R用户逃避陷阱。

陷阱1

正如乔兰所指出的,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" 

陷阱2

字符按词汇顺序排序。因此,将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没有说明为什么他需要使用有序因子 因素(无论是否有序)不对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

陷阱3

当我开始学习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