我的数据看起来像这样:
set.seed(122217)
df <- data.frame(ID = paste0("id",1:100), A = rnorm(100), E = rnorm(100), I = rnorm(100), O = rnorm(100), U = rnorm(100))
我想产生一个包含100行和1 + 3列的新数据框。每行应对应于df中的每个ID,第一列为,ID
其他列为第一,第二,第三。
我可以用一些非常丑陋的代码来做到这一点:
library(data.table)
library(dplyr)
# transpose
t_df <- transpose(df[,2:6])
# get row and colnames in order
colnames(t_df) <- df[,1]
rownames(t_df) <- colnames(df[,2:6])
id_largest <-function(data, col){
values <- data[,col]
names(values) <- row.names(data)
values <- sort(values, decreasing = T)
ranking <- names(values)
out <- data.frame( id= colnames(data)[col], First=ranking[1], Second=ranking[2], Third=ranking[3])
return(out)
}
ranking <- purrr::map(1:ncol(t_df), id_largest, data=t_df) %>% rbindlist()
这段代码产生了我想要的:
> head(ranking)
id First Second Third
1: id1 A E I
2: id2 U O I
3: id3 A E I
4: id4 E U I
5: id5 I A U
6: id6 I A U
但是不是很优雅。有没有更干净的方法可以做到这一点?
使用data.table
以下解决方案:
library(data.table)
melt(setDT(df), id = 1)[order(-value)
][, variable[1:3], ID
][, dcast(.SD, ID ~ rowid(ID, prefix = 'p'))]
这使:
ID p1 p2 p3 1: id001 A E I 2: id002 U O I 3: id003 A E I 4: id004 E U I 5: id005 I A U .... 95: id095 O A U 96: id096 U A I 97: id097 A U O 98: id098 U A O 99: id099 I E U 100: id100 E I U
与相同的逻辑tidyverse
:
library(dplyr)
library(tidyr)
df %>%
gather(key, value, -1) %>%
group_by(ID) %>%
arrange(ID, -value) %>%
slice(1:3) %>%
select(-value) %>%
mutate(rn = paste0('p', row_number())) %>%
spread(rn, key)
使用的数据:
set.seed(122217)
df <- data.frame(ID = sprintf("id%03d",1:100), A = rnorm(100), E = rnorm(100), I = rnorm(100), O = rnorm(100), U = rnorm(100))
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句