每行n个最大值

时间:2020-05-13 09:41:14

标签: r data-manipulation

我有一个具有以下结构的数据框

输入

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行。

3 个答案:

答案 0 :(得分: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

按照@Chris Ruehlemann的建议使用rank,但是如果连续两个相同的值,这将失败。

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

答案 1 :(得分: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秒。使用套用需要30秒钟以上。

答案 2 :(得分:0)

看看我是否可以制作不需要for(Node *node: nodes){ std::cout << node->value << "-->" << node->parentTree->id << '\n'; 的更快的基本版本:

基本上,我按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