【问题标题】:Return the column name of the second largest value of a row返回一行第二大值的列名
【发布时间】:2021-06-18 09:39:13
【问题描述】:
df = data.frame( ID = c (1,2,3,4,5), a = c (0,2,0,1,0),
                 b = c (0,3,2,NA,0), c = c(0,4,NA,NA,1),
                 d = c (2,5,4,NA,1))
maxn <- function(n) function(x) order(x, decreasing = TRUE)[n]
df<-df %>% mutate( second_largest=apply(.[2:5], 1, function(x) names(x)[maxn(2)(x)]) ) 

我使用上面的 R 代码来获取 a,b,c,d 的第二大值的列名。对于 ID=4,由于 b,c,d 存在缺失值,因此第二大值的名称应为 NA。但是,代码返回 b。我应该如何删除缺失值?

【问题讨论】:

  • 如果有两个1s和两个0s怎么办?
  • 我会从左到右选择
  • 那你的选择是什么?在两个1s 之间,您最多取一个取第二大取一个,还是不取两个取最大值?
  • 如果第 1 列和第 2 列都有两个 1,则最大的应该是第 2 列,第二大的应该是第 1 列。左侧变量将是较小的变量。谢谢。

标签: r rowwise


【解决方案1】:

另一种方法

df = data.frame( ID = c (1,2,3,4,5), a = c (0,2,0,1,0),
                 b = c (0,3,2,NA,0), c = c(0,4,NA,NA,1),
                 d = c (2,5,4,NA,1))

library(dplyr, warn.conflicts = F)

df %>% group_by(ID) %>% rowwise() %>%
  mutate(name = {x <- c_across(everything());
  if (sum(!is.na(x)) >= 2) tail(head(names(cur_data())[order(x, decreasing = T)],2),1) else NA})

#> # A tibble: 5 x 6
#> # Rowwise:  ID
#>      ID     a     b     c     d name 
#>   <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
#> 1     1     0     0     0     2 a    
#> 2     2     2     3     4     5 c    
#> 3     3     0     2    NA     4 b    
#> 4     4     1    NA    NA    NA <NA> 
#> 5     5     0     0     1     1 d

如果您必须改为对几列执行此操作

df %>% group_by(ID) %>% rowwise() %>%
  mutate(name = {x <- c_across(c('a', 'c'));
  if (sum(!is.na(x)) >= 2) tail(head(c('a', 'c')[order(x, decreasing = T)],2),1) else NA})

# A tibble: 5 x 6
# Rowwise:  ID
     ID     a     b     c     d name 
  <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
1     1     0     0     0     2 c    
2     2     2     3     4     5 a    
3     3     0     2    NA     4 NA   
4     4     1    NA    NA    NA NA   
5     5     0     0     1     1 a 

【讨论】:

  • 如果我的数据集中有很多列,如何将数据限制为仅从第 2 列到第 4 列?
  • @NewYorkCrosser,请告诉我是否正确理解你,因为我看到不同的答案后感到困惑
  • 是的,代码返回我想要的!我只想知道如何将分析限制在选定的列。非常感谢。
  • @NewYorkCrosser,是的,有很多方法可以限制搜索。这些方式取决于 cols 的实际名称。您可以使用选择辅助函数而不是 everything()
  • @NewYorkCrosser,请告诉我你的实际列名,以便我给你一些建议
【解决方案2】:

我认为您可以使用以下解决方案。我测试了一些可能的数字配置,并且成功了:

library(dplyr)
library(purrr)

df %>%
  mutate(Name = pmap_chr(., ~ {x <- c(...)[-1]; 
  if(sum(is.na(x)) >= 3) {
    NA
  } else { 
    ind <- which(x == max(x[!is.na(x)]))
    if(length(ind) > 1) {
      colnames(df[-1])[ind[2]]
    } else {
      colnames(df[-1])[which(x == sort(x)[length(sort(x))-1])][1]
    }
  }
 }
))

  ID a  b  c  d Name
1  1 0  0  0  2    a
2  2 2  3  4  5    c
3  3 0  2 NA  4    b
4  4 1 NA NA NA <NA>
5  5 0  0  1  1    d

【讨论】:

    【解决方案3】:

    我们可以把函数改成-

    maxn <- function(n) function(x) order(x, decreasing = TRUE)[!is.na(x)][n]
    

    然后代码将与您的方法一起使用 -

    library(dplyr)
    
    df %>% 
      mutate(second_largest=apply(.[2:5], 1, function(x) names(x)[maxn(2)(x)])) 
    
    #  ID a  b  c  d second_largest
    #1  1 0  0  0  2              a
    #2  2 2  3  4  5              c
    #3  3 0  2 NA  4              b
    #4  4 1 NA NA NA           <NA>
    #5  5 0  0  1  1              d
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-06
      • 1970-01-01
      相关资源
      最近更新 更多