通过多列排列重新排序数据框中的行

时间:2013-01-11 01:17:16

标签: r

我正在尝试重新排序包含大约250,000行和7列的data.frame。我想要在data.frame顶部的行是第2列包含最低值而第7列最高的行,但是将包含从包含最低到最高值的列序列:2,5,1, 4,6,3,7(因此第5列将具有第二低的值等)。

一旦识别出与此序列匹配的任何行,它将继续查找行值,其中列值从序列2,5,1,4,6中的最低到最高,然后是2,5,1,4和依此类推,直到只有第2列为最低的行,其他列值随机进行分类。任何没有第2列作为最低值的行都将被忽略,并在排序的行下面保留未排序。我正在努力为我的问题提出任何可行的解决方案 - 我能提供的与我合作的数据相比最好的是:

df<-data.frame(matrix(rnorm(70000), nrow=10000))
df<-abs(df)

如果有人有任何想法,我会全力以赴。 谢谢!

4 个答案:

答案 0 :(得分:2)

鉴于您有一个统一类型(数字)的大数据集,我建议使用矩阵而不是data.frame

 tt <- abs(matrix(rnorm(70000), nrow=10000))

您希望与

匹配的订单
 desiredOrder <- c(2,5,1,4,6,3,7)

您需要查找每个行的顺序。我认为这里最容易确保给你一个列表,每行都有一个元素。我建议这样的事情。

 orders <- lapply(apply(tt, 1, function(x) list(order(x))), unlist)

然后,您需要经历(从desiredOrder[seq_len(7)]desiredOrder[seq_len(1)]以测试特定行的所需订单子集何时等于所需订单的所需子集。(我在考虑一些sapplywhichall

的组合

找到符合所需结果的所有行后,您可以使用setdiff查找不匹配的行,然后使用此tt向量重新排序new order

答案 1 :(得分:0)

一种可能的方法是对列中的值进行加权排名。这将是排名回归。 7列250K行不是那么大。对于那些你希望低值具有更高权重的人,你可以从NROW(dfrm)中减去等级。如果你想在该列排序方案中扩展wieighting,那么jsut乘以一个加权向量:比如c(1,.6,.3,0,.3,.6,1)

dmat <- matrix(sample(20, 20*7, repl=TRUE), 20, 7)
dfrm <- as.data.frame(dmat)

dfrm$wt <- sapply( dfrm[ c(2,5,1,4,6,3,7)] , rank); dfrm
 dfrm$wt[,1:3]  <- rep(NROW(dfrm),3) - dfrm$wt[ , 1:3] 
 dfrm$wt <- dfrm$wt*rep(c(1, .6, .3,  0, .3, .6, 1), each=NROW(dfrm))
 dfrm[ order( apply( dfrm$wt, 1, FUN=sum), decreasing=TRUE ) , ]

这并不会强制V2的最低值成为第一个,因为您隐含了多个标准。如果这不是你想象的那样,你仍然有能力重新加权。

答案 2 :(得分:0)

像这样:

dat <- as.matrix(df)
rnk <- t(apply(dat, 1, rank))
desiredRank <- order(c(2,5,1,4,6,3,7))
rnk.match <- rnk == matrix(desiredRank, nrow(rnk), ncol(rnk), byrow = TRUE)
match.score <- apply(rnk.match, 1, match, x = FALSE) - 1
match.score[is.na(match.score)] <- ncol(dat)
out <- dat[order(match.score, decreasing = TRUE), ]

head(out)
#            X1         X2        X3        X4        X5       X6        X7
#[1,] 0.7740246 0.19692680 1.5665696 0.9623104 0.2882492 1.367786 1.8644204
#[2,] 0.5895921 0.00498982 1.7143083 1.2698382 0.1776051 2.494149 1.4216615
#[3,] 0.1981111 0.11379934 1.0379619 0.2130251 0.1660568 1.227547 0.9248101
#[4,] 0.7507257 0.23353923 1.6502192 1.2232615 0.7497352 2.032547 1.4409475
#[5,] 0.5418513 0.06987903 1.8882399 0.6923557 0.3681018 2.172043 1.2215323
#[6,] 0.1731943 0.01088604 0.6878847 0.2450998 0.0125614 1.197478 0.3087192

在这个例子中,第一行匹配整个秩序列;下一行匹配序列的前五个等级:

head(match.score[order(match.score, decreasing = TRUE)])
# [1] 7 5 5 5 5 5

答案 3 :(得分:0)

您可以使用order() 索引 返回到订单的事实,
这正是你想要匹配的

For example if we apply `order` twice to each row of 
  [1,]   23   17  118   57   20   66  137
  [2,]   56   42   52   66   47    8   29
  [3,]   35    5   76   35   29  217   89

We would get
  [1,]    2    5    1    4    6    3    7
  [2,]    6    7    2    5    3    1    4
  [3,]    2    5    1    4    3    7    6

然后,您只需要检查哪些行符合您要查找的内容。


<小时/> 有几种方法可以实现这一点,下面是一个例子,我们创建了 逻辑矩阵comparisons,表示行的每个元素是否为 处于“正确”位置,如expectedOrder所示。

然后,我们根据“正确列”中的元素数量来排序原始行。 (当然,松散地使用这句话)

# assuming mydf is your data frame or matrix

# the expected order of the columns
expectedOrder <- c(2,5,1,4,6,3,7)

# apply the order function twice. 
ordering <- apply(mydf, 1, function(r) order(r) )  

# Recall that the output of apply is transposed relative to the input. 
# We make use of this along with the recycling of vectors for the comparison
comparisons <-  ordering == expectedOrder

# find all rows with at least matches to 2,5,1,4
topRows  <- which(colSums(comparisons[1:4, ])==4)

# reorder the indecies based on the total number of matches in comparisons
#  ie:  first all 7-matches, then 5-matches, then 4-matches
topRows <- topRows[order(colSums(comparisons[,topRows]), decreasing=TRUE)]

# reorder the dataframe (or matrix) 
mydf.ordered <- 
  rbind(mydf[topRows, ],  
        mydf[-topRows,])

head(mydf.ordered)
 #    X1 X2  X3  X4  X5  X6  X7
 #    23 17 118  57  20  66 137
 #    39 21 102  50  24  53 163
 #    80  6 159 116  44 139 248
 #   131  5 185 132 128 147 202
 #    35 18  75  40  33  67 151
 #    61 14 157  82  57 105 355