n 每行最高值

问题描述 投票:0回答:1

我有一个数据框架,结构如下

输入

set.seed(5)    
df <- data.frame(A= round(runif(6,0,100)),B= round(runif(6,0,100)),C= round(runif(6,0,100)),D= round(runif(6,0,100)))

   A  B  C  D
1 20 53 32 55
2 69 81 56 84
3 92 96 26 89
4 28 11 20 72
5 10 27 39 21
6 70 49 89 23

现在,我想添加两列额外的列,每列分别是一行的第二和第三大元素。

輸出

   A  B  C  D thirdLarge  secLarge
1 20 53 32 55       32         53
2 69 81 56 84       69         81
3 92 96 26 89       89         92
4 28 11 20 72       20         28
5 10 27 39 21       21         27
6 70 49 89 23       49         70

我试着用一个简单的 "for循环 "来做,但这样做效率不够高,而且对于700000行来说,要花很长时间。

r data-manipulation
1个回答
3
投票

我们可以用 apply :

df[c('thirdLarge', 'secLarge')] <- t(apply(df, 1, function(x) 
                sort(x)[c(length(x)-2, length(x) - 1)]))
#This is shorter
df[c('thirdLarge', 'secLarge')] <- t(apply(df, 1, function(x) 
                        sort(x, decreasing = TRUE)[3:2]))

df
#   A  B  C  D thirdLarge secLarge
#1 20 53 32 55         32       53
#2 69 81 56 84         69       81
#3 92 96 26 89         89       92
#4 28 11 20 72         20       28
#5 10 27 39 21         21       27
#6 70 49 89 23         49       70

使用 rank 正如 @Chris Ruehlemann 所建议的那样,但如果你连续两个相同的值,这将会失败。

df[c('secLarge', 'thirdLarge')] <- t(apply(df, 1, function(x) 
                                      x[rank(-x) %in% 2:3]))

3
投票

如果速度是个问题,请查看 Rfast 包。

library(Rfast)
library(dplyr)

mutate(df, 
       lrg.2 = rownth(as.matrix(df), elems=rep(2, nrow(df)), descending=TRUE),
       lrg.3 = rownth(as.matrix(df), elems=rep(3, nrow(df)), descending=TRUE))

   A  B  C  D lrg.2 lrg.3
1 20 53 32 55    53    32
2 69 81 56 84    81    69
3 92 96 26 89    92    89
4 28 11 20 72    28    20
5 10 27 39 21    27    21
6 70 49 89 23    70    49

对于一个包含700,000行的数据框架,这需要<1秒。使用apply需要>30秒。


0
投票

看看我是否能做出一个更快的基础版本,不需要用 apply:

我基本上是按一次订购 row 和递减值,然后将其反馈到一个。matrix 并取所需的列。

udf <- unlist(df)
mat <- matrix(udf[order(row(df), -udf)], ncol=ncol(df), byrow=TRUE)
df[c('thirdLarge','secLarge')] <- mat[,3:2]

##   A  B  C  D thirdLarge secLarge
##1 20 53 32 55         32       53
##2 69 81 56 84         69       81
##3 92 96 26 89         89       92
##4 28 11 20 72         20       28
##5 10 27 39 21         21       27
##6 70 49 89 23         49       70

df <- df[rep(1:6, 116667),]
## 700,002 rows

system.time({
    udf <- unlist(df)
    mat <- matrix(udf[order(row(df), -udf)], ncol=ncol(df), byrow=TRUE)
    df[c('thirdLarge','secLarge')] <- mat[,3:2]
})
##   user  system elapsed 
##  0.971   0.000   0.972

比较在行上循环与 apply:

system.time({
    df[c('thirdLarge', 'secLarge')] <- t(apply(df, 1, function(x) 
                        sort(x, decreasing = TRUE)[3:2]))
})
##   user  system elapsed 
## 24.362   0.003  24.365 
© www.soinside.com 2019 - 2024. All rights reserved.