我有一个数据,我想找出哪一列具有最大值并输出该列名称。一个问题是,如果没有最大值(例如,所有数字均相等),则返回all_equal
注释,或者如果两列的最大值与第三列的最大值相等,则返回该两列的名称。
这是示例数据
test <- data.frame(A=c(5,NA,NA,1,NA,NA,3,NA,NA),B=c(NA,2,NA,NA,1,NA,NA,1,NA),C=c(NA,NA,1,NA,NA,1,NA,NA,3),gr=gl(3,3))
A B C gr
1 5 NA NA 1
2 NA 2 NA 1
3 NA NA 1 1
4 1 NA NA 2
5 NA 1 NA 2
6 NA NA 1 2
7 3 NA NA 3
8 NA 1 NA 3
9 NA NA 3 3
在每个gr
中,列A
,B and C
中都有值。我的目的是找到该组中哪个列的最大值,然后将该列名称输出到名为col_name
的新列。
如果所有值都相同,如gr=2
,则输出为all_equal
如果该列中的两个列与第三列相比具有最大值,例如gr=3
到A&C
的输出列名。
我意识到没有col_name
所以我尝试了
gather
我在这里遇到的问题是,如果A,B和C列中的所有最大值都相等,则如何输出library(dplyr)
test%>%
group_by(gr)%>%
gather(variable, value, -gr) %>%
arrange(gr)%>%
mutate(col_name=variable[which.max(value)])
# A tibble: 18 x 4
# Groups: gr [2]
r variable value col_name
<fct> <chr> <dbl> <chr>
1 1 A 5 A
2 1 A NA A
3 1 A NA A
4 1 B NA A
5 1 B 2 A
6 1 B NA A
7 1 C NA A
8 1 C NA A
9 1 C 1 A
10 2 A 1 A
11 2 A NA A
12 2 A NA A
13 2 B NA A
14 2 B 1 A
15 2 B NA A
16 2 C NA A
17 2 C NA A
18 2 C 1 A
注释,
如果2列最大值等于(gr = 3中的A和C),则以all_equal
格式A&C
输出那些相等的列名称
预期输出为
col_name
提前谢谢!
答案 0 :(得分:2)
这里是一种ScrollView.frame = CGRect(x: 0, y: 0, width: ScrollView.frame.width, height: 3000)
的方法,我尝试使其更通用一些,以容纳不同数量的关注列。从上面的dplyr
数据帧开始,首先定义一个函数,该函数查找当前组的最大值,获取具有匹配值的列的索引,然后根据匹配的列数构建输出:
test
由于该输出是一个数据帧,因此您需要利用foo <- function(df_, cols = 1:3) {
# Get max
m = max(df_[, cols], na.rm = TRUE)
# Get columns
ix <- as.data.frame(which(df_[, cols] == m, arr.ind = TRUE))[, 2]
matchlen = length(ix)
columns <- names(df_[,cols])[ix]
# Get varname based on length
out = ifelse(matchlen == length(cols), "all_equal", paste(columns, collapse = "&"))
df_$col_name = out
return(df_)
}
将其应用于具有do
的组:
dplyr
该函数应允许输入灵活的列数,只要它们是数字即可。例如,
test %>%
group_by(gr) %>%
do(foo(.))
# A tibble: 9 x 5
# Groups: gr [3]
A B C gr col_name
<dbl> <dbl> <dbl> <fct> <chr>
1 5 NA NA 1 A
2 NA 2 NA 1 A
3 NA NA 1 1 A
4 1 NA NA 2 all_equal
5 NA 1 NA 2 all_equal
6 NA NA 1 2 all_equal
7 3 NA NA 3 A&C
8 NA 1 NA 3 A&C
9 NA NA 3 3 A&C
和
test %>%
group_by(gr) %>%
do(foo(., cols = 1:2))
似乎都可以。
修改:
是的,我想你可以!
test %>%
group_by(gr) %>%
do(foo(., cols = c(1,3)))
答案 1 :(得分:2)
这里是使用gather
的选项。我们将数据gather
转换为“长”格式,arrange
按组(gr)分组,“ val”按降序排列,按“ gr”分组,summarise
创建“基于OP帖子中描述的条件为每个'gr'指定col_name',并为right_join
和原始数据集
library(tidyverse)
test %>%
gather(key, val, -gr, na.rm = TRUE) %>%
arrange(gr, desc(val)) %>%
group_by(gr) %>%
summarise(col_name = case_when(n_distinct(val)==1 ~ "all_equal",
TRUE ~ paste(key[val==max(val)], collapse = "&"))) %>%
right_join(test) %>%
select(names(test), everything())
# A tibble: 9 x 5
# A B C gr col_name
# <dbl> <dbl> <dbl> <fct> <chr>
#1 5 NA NA 1 A
#2 NA 2 NA 1 A
#3 NA NA 1 1 A
#4 1 NA NA 2 all_equal
#5 NA 1 NA 2 all_equal
#6 NA NA 1 2 all_equal
#7 3 NA NA 3 A&C
#8 NA 1 NA 3 A&C
#9 NA NA 3 3 A&C
或使用data.table
library(data.table)
library(stringr)
setDT(test)[, col_name := {
v1 <- sort(na.omit(unlist(.SD)), decreasing = TRUE)
if(uniqueN(v1)==1) "all_equal" else
paste(str_remove(names(v1)[v1==max(v1)], "\\d+"), collapse="&")
}, by = gr]
test
# A B C gr col_name
#1: 5 NA NA 1 A
#2: NA 2 NA 1 A
#3: NA NA 1 1 A
#4: 1 NA NA 2 all_equal
#5: NA 1 NA 2 all_equal
#6: NA NA 1 2 all_equal
#7: 3 NA NA 3 A&C
#8: NA 1 NA 3 A&C
#9: NA NA 3 3 A&C
答案 2 :(得分:2)
类似于akrun的答案
library(tidyverse)
test <- data_frame(A=c(5,NA,NA,1,NA,NA,3,NA,NA),B=c(NA,2,NA,NA,1,NA,NA,1,NA),C=c(NA,NA,1,NA,NA,1,NA,NA,3),gr=gl(3,3))
test %>% gather(key, value, -gr, na.rm = TRUE) %>%
group_by(gr) %>%
arrange(gr) %>%
mutate(col_name = if_else(length(which(value == max(value))) == length(unique(key)),
"all_equal",
paste(flatten(.[which(value == max(value)), "key"]), collapse = "&"))) %>%
spread(key, value)
#> # A tibble: 3 x 5
#> # Groups: gr [3]
#> gr col_name A B C
#> <fct> <chr> <dbl> <dbl> <dbl>
#> 1 1 A 5 2 1
#> 2 2 all_equal 1 1 1
#> 3 3 A&C 3 1 3
由reprex package(v0.2.0)于2018-08-09创建。
这还将压缩数据帧以删除所有额外的NA
答案 3 :(得分:1)
使用自定义函数和data.table的解决方案:
myfun <- function(x) {
x <- as.matrix(x)
idx <- apply(x, 2, max, na.rm=T)==max(x, na.rm=T)
who <- colnames(x)[idx]
if(length(who)==1) return(who)
if(length(who)==2) return(paste0(who, collapse = "&"))
if(length(who)>2) return("all_equal")
}
library(data.table)
dt <- data.table(test)
dt[ , new := myfun(cbind(A,B,C)), by=gr]
请注意,我必须使用==max()
而不是which.max
来处理领带。我还很难用aggregate
之类的基本函数来实现这一点,所以我采用了data.table
的方式。
答案 4 :(得分:0)
这里有2个基本的R
解决方案
使用split<-
和aggregate
test0 <- aggregate(test[1:3], by = test[4], max,na.rm=T)[-1]
nms <- apply(do.call(pmax,test0) == test0, 1 , function(x) names(which(x)))
test$col_name <- NA
split(test$col_name, test$gr) <-
ifelse(lengths(nms) == 3, "all_equal", lapply(nms,paste,collapse="&"))
test
# A B C gr col_name
# 1 5 NA NA 1 A
# 2 NA 2 NA 1 A
# 3 NA NA 1 1 A
# 4 1 NA NA 2 all_equal
# 5 NA 1 NA 2 all_equal
# 6 NA NA 1 2 all_equal
# 7 3 NA NA 3 A&C
# 8 NA 1 NA 3 A&C
# 9 NA NA 3 3 A&C
详细信息
我们首先将测试合并到test0
test0
# A B C
# 1 5 2 1
# 2 1 1 1
# 3 3 1 3
然后使用pmax
获取最大行,使用which
获取列索引,使用names
获取列名称。
我们用"all_equal"
指定粘贴的名称(split<-
除外),它们被回收以形成输出。
使用stack
和ave
stacked <- cbind(na.omit(stack(test,-gr)), gr=levels(test$gr))
test$col_name <- with(stacked, ave(values, gr, FUN = function(x){
nms <- paste(names(test)[which(x == max(x))],collapse="&")
if (length(nms) == 3) "all_equal" else nms})[order(gr)])
# A B C gr col_name
# 1 5 NA NA 1 A
# 2 NA 2 NA 1 A
# 3 NA NA 1 1 A
# 4 1 NA NA 2 A&B&C
# 5 NA 1 NA 2 A&B&C
# 6 NA NA 1 2 A&B&C
# 7 3 NA NA 3 A&C
# 8 NA 1 NA 3 A&C
# 9 NA NA 3 3 A&C