作为标题,如何通过dplyr
获得跨行的第二/第三大/最小值的列名?(注意:比较从gp1到gp3的值,我修改了原始数据)
一种方法是在基数R中使用apply
:
a <- data.frame(name=letters[1:9], gp1=c(3:11), gp2=c(1:9), gp3=c(8,8,2,6,6,6,12,12,6))
##
## name gp1 gp2 gp3
## 1 a 3 1 8
## 2 b 4 2 8
## 3 c 5 3 2
## 4 d 6 4 6
## 5 e 7 5 6
## 6 f 8 6 6
## 7 g 9 7 12
## 8 h 10 8 12
## 9 i 11 9 6
a$max1_colname <- apply(a, 1, function(t) colnames(a)[which.max(t)])
## There will be some warnings. the problem of name column?
##
## name gp1 gp2 gp3 max1_colname
## 1 a 3 1 8 gp3
## 2 b 4 2 8 gp3
## 3 c 5 3 2 gp1
## 4 d 6 4 6 gp1
## 5 e 7 5 6 gp1
## 6 f 8 6 6 gp1
## 7 g 9 7 12 gp3
## 8 h 10 8 12 gp3
## 9 i 11 9 6 gp1
如何通过使用dplyr
(忽略第4行有两个最大值)来完成它,第二大列名如何?
Extern外:更复杂的是,如果有两个最大值(例如第4行),如何得到如下结果:
##
## name gp1 gp2 gp3 max1_colname
## 1 a 3 1 8 gp3
## 2 b 4 2 8 gp3
## 3 c 5 3 2 gp1
## 4 d 6 4 6 gp1+gp3
## 5 e 7 5 6 gp1
## 6 f 8 6 6 gp1
## 7 g 9 7 12 gp3
## 8 h 10 8 12 gp3
## 9 i 11 9 6 gp1
谢谢。
发布于 2022-10-20 07:27:04
您可以在一个max.col
调用中使用mutate
。请注意,这将只保留一个值,并且可以使用ties.method
处理领带。默认情况下,它随机选择一个平分最大值。
library(dplyr)
a %>%
mutate(max1_colname = names(select(., gp1:gp3))[max.col(select(., gp1:gp3))])
对于第二个更复杂的案例,您可以这样做:
a %>%
rowwise() %>%
mutate(max1_colname = paste(names(select(., -name))[c_across(-name) == max(c_across(-name))], collapse = "+"))
# name gp1 gp2 gp3 max1_colname
# 1 a 3 1 8 gp3
# 2 b 4 2 8 gp3
# 3 c 5 3 2 gp1
# 4 d 6 4 6 gp1+gp3
# 5 e 7 5 6 gp1
# 6 f 8 6 6 gp1
# 7 g 9 7 12 gp3
# 8 h 10 8 12 gp3
# 9 i 11 9 6 gp1
若要获得第二个(或更多)最大值,请使用order
和decreasing = TRUE
a %>%
rowwise() %>%
mutate(max2_colname = names(.)[order(c_across(everything()), decreasing = TRUE)[2]])
# gp1 gp2 gp3 max2_colname
# 1 3 1 8 gp1
# 2 4 2 8 gp1
# 3 5 3 2 gp2
# 4 6 4 6 gp3
# 5 7 5 6 gp3
# 6 8 6 6 gp2
# 7 9 7 12 gp1
# 8 10 8 12 gp1
# 9 11 9 6 gp2
对于更复杂的情况,您希望获得最大的n
,并获得它们的全部,您可以使用dense_rank
+ which
a %>%
rowwise() %>%
mutate(max1_colname = paste(names(.)[which(dense_rank(-c_across(everything())) == 2)], collapse = "+"))
# gp1 gp2 gp3 max1_colname
# 1 3 1 8 gp1
# 2 4 2 8 gp1
# 3 5 3 2 gp2
# 4 6 4 6 gp2
# 5 7 5 6 gp3
# 6 8 6 6 gp2+gp3
# 7 9 7 12 gp1
# 8 10 8 12 gp1
# 9 11 9 6 gp2
发布于 2022-10-20 07:07:09
第一部分可通过以下方式完成:
library(tidyverse)
a %>%
rowwise() %>%
mutate(max1_colname = names(.)[which.max(c_across(everything()))])
gp1 gp2 gp3 max1_colname
3 1 8 gp3
4 2 8 gp3
5 3 2 gp1
6 4 6 gp1
7 5 6 gp1
8 6 6 gp1
9 7 12 gp3
10 8 12 gp3
11 9 6 gp1
第二部分的解决办法:
a1 <- a %>% mutate(id = row_number()) %>%
pivot_longer(-id)
a2 <- a1 %>%
group_by(id) %>%
top_n(value, n = 1) %>%
mutate(max1_colname = paste0(name, collapse = "+")) %>%
select(id, max1_colname) %>%
distinct()
a1 %>%
left_join(a2, by = c("id")) %>%
pivot_wider() %>%
relocate(max1_colname, .after = gp3) %>%
select(-id)
gp1 gp2 gp3 max1_colname
3 1 8 gp3
4 2 8 gp3
5 3 2 gp1
6 4 6 gp1+gp3
7 5 6 gp1
8 6 6 gp1
9 7 12 gp3
10 8 12 gp3
11 9 6 gp1
发布于 2022-10-20 07:59:52
还请注意,有一个基本的max.col
函数,唯一的问题是它返回一个索引(可以设置为第一个,最后,随机)。
a %>%
mutate(max1_colname = paste("grp", max.col(.), sep = ""))
# gp1 gp2 gp3 max1_colname
# 1 3 1 8 grp3
# 2 4 2 8 grp3
# 3 5 3 2 grp1
# 4 6 4 6 grp1
# 5 7 5 6 grp1
# 6 8 6 6 grp1
# 7 9 7 12 grp3
# 8 10 8 12 grp3
# 9 11 9 6 grp1
https://stackoverflow.com/questions/74135397
复制相似问题