它们是循环遍历数据框行的 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
当然,这是看待问题的不同方式,但根据您的其他工作,它可能会在其他地方提供一些简化和回报。
我想遍历数据框的每一行,找出哪三个列名具有该行的前三个最大值。
我确实有使用 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
当然,这是看待问题的不同方式,但根据您的其他工作,它可能会在其他地方提供一些简化和回报。