它们是循环遍历数据框行的 R 函数,并且 returns 每行的最高 3 列值

Is their an R function that loops through the rows of a data frame and returns the highest 3 column values for each row

我想遍历数据框的每一行,找出哪三个列名具有该行的前三个最大值。

我确实有使用 for 循环执行此操作的代码,但它太慢了。有没有人有比这个 for 循环更快的方法来做同样的事情?

dataframe2=dataframe
colnames=colnames(dataframe)
dfLength=length(rownames(dataframe))
for(x in 1:dfLength){
   vector=as.numeric(dataframe[x,1:length(colnames)])
   decreasing=order(vector, decreasing = TRUE)
   dataframe2[x,"sector_1"]=colnames[(decreasing[1])+1]
   dataframe2[x,"sector_2"]=colnames[(decreasing[2])+1]
   dataframe2[x,"sector_3"]=colnames[(decreasing[3])+1]
}

如果您先将数字列转换为 matrix 会容易得多。如果您有一个名为 myframe 的框架,那么您可以从:

开始
m <- as.matrix(myframe[numeric_columns])
cn <- colnames(myframe[numeric_columns])

其中 numeric_columns 是整数向量(我在这里的假设)或列名。

因为我没有你的数据,我会自己做一个:

set.seed(2)
m <- matrix(sample(100), nr=10, nc=10)
cn <- paste0("Z", 1:10)
colnames(m) <- cn
m
#       Z1  Z2 Z3 Z4 Z5 Z6 Z7 Z8 Z9 Z10
#  [1,] 19  50 53  1 88 72 79  9  8  29
#  [2,] 70  22 31 74 63 95 47 45 21  11
#  [3,] 57  67 66 56 81 33 24  2 49  69
#  [4,] 17  16 12 59 61 64 98  5 38  23
#  [5,] 91  35 27 34 80 94 40 52  4  36
#  [6,] 90  73 82 41 92 75 87 54 25  60
#  [7,] 13  83 77 55 68 86 14 32 93  28
#  [8,] 78 100 76 18 84 43 39 20 96  15
#  [9,] 44  37 99 42 85 26 58 65 89   6
# [10,] 51   7 10 71 62 30  3 46 48  97

此代码片段本身 returns 每行的前 3 列,数字为:

t(apply(m, 1, function(a) order(-a)[1:3]))
#       [,1] [,2] [,3]
#  [1,]    5    7    6
#  [2,]    6    4    1
#  [3,]    5   10    2
#  [4,]    7    6    5
#  [5,]    6    1    5
#  [6,]    5    1    7
#  [7,]    9    6    2
#  [8,]    2    9    5
#  [9,]    3    9    5
# [10,]   10    4    5

我们可以将它们转换为名称矩阵:

top3 <- t(apply(m, 1, function(a) order(-a)[1:3]))
top3[] <- cn[top3]
top3
#       [,1]  [,2]  [,3]
#  [1,] "Z5"  "Z7"  "Z6"
#  [2,] "Z6"  "Z4"  "Z1"
#  [3,] "Z5"  "Z10" "Z2"
#  [4,] "Z7"  "Z6"  "Z5"
#  [5,] "Z6"  "Z1"  "Z5"
#  [6,] "Z5"  "Z1"  "Z7"
#  [7,] "Z9"  "Z6"  "Z2"
#  [8,] "Z2"  "Z9"  "Z5"
#  [9,] "Z3"  "Z9"  "Z5"
# [10,] "Z10" "Z4"  "Z5"

编者注:如果您确实在许多列中拥有可比较的数据,那么对于许多 R 包而言,将其采用 "long" 格式是有意义的,其中一列包含名称,一列包含值.扩展上述数据,我将添加一个 "id" 列(因为您的数据可能有一个关键字段):

myframe <- as.data.frame(cbind(id=100L + 1:10, m))
head(myframe)
#    id Z1 Z2 Z3 Z4 Z5 Z6 Z7 Z8 Z9 Z10
# 1 101 19 50 53  1 88 72 79  9  8  29
# 2 102 70 22 31 74 63 95 47 45 21  11
# 3 103 57 67 66 56 81 33 24  2 49  69
# 4 104 17 16 12 59 61 64 98  5 38  23
# 5 105 91 35 27 34 80 94 40 52  4  36
# 6 106 90 73 82 41 92 75 87 54 25  60

转换为 "long" 格式(在此处使用 tidyverse 包):

head(tidyr::gather(myframe, Znum, Zval, -id))
#    id Znum Zval
# 1 101   Z1   19
# 2 102   Z1   70
# 3 103   Z1   57
# 4 104   Z1   17
# 5 105   Z1   91
# 6 106   Z1   90
tail(tidyr::gather(myframe, Znum, Zval, -id))
#      id Znum Zval
# 95  105  Z10   36
# 96  106  Z10   60
# 97  107  Z10   28
# 98  108  Z10   15
# 99  109  Z10    6
# 100 110  Z10   97

这表明每个 id 获得前三名的干净 dplyr 管道:

library(dplyr)
library(tidyr)

myframe %>%
  tidyr::gather(Znum, Zval, -id) %>%
  arrange(-Zval) %>%
  group_by(id) %>%
  slice(1:3) %>%
  ungroup()
# # A tibble: 30 x 3
#       id Znum   Zval
#    <int> <chr> <int>
#  1   101 Z5       88
#  2   101 Z7       79
#  3   101 Z6       72
#  4   102 Z6       95
#  5   102 Z4       74
#  6   102 Z1       70
#  7   103 Z5       81
#  8   103 Z10      69
#  9   103 Z2       67
# 10   104 Z7       98
# # ... with 20 more rows

当然,这是看待问题的不同方式,但根据您的其他工作,它可能会在其他地方提供一些简化和回报。