【问题标题】:Get max and second max of row including column names in R获取最大和第二个最大行,包括 R 中的列名
【发布时间】:2022-09-29 05:49:05
【问题描述】:

如何返回 data.frame 的行最大值和第二最大值的列名和值?

示例数据:

example_df <- data.frame(
  mycol1 =c(101,-108,140,140,-150),
  mycol2 = c(111,-105,128,-220,-150),
  mycol3 = c(-103,-102,123,-210,-180), 
  mycol4 =c(106,-102,140,-200,-180),
  mycol5 =c(-105,-106,120,-150,-180)
)

所需数据:


desired_df <- data.frame(
  firstmax=c(\"mycol2 111\",\"mycol3 -102\",\"mycol1 140\",\"mycol1 140\", \"mycol1 -150\"),
  secondmax=c(\"mycol4 106\", \"mycol4 -102\", \"mycol4 140\",\"mycol5 -150\",\"mycol2 -150\"),
  stringsAsFactors = F
)
  • 我会从融化开始,然后你按列而不是按行说话
  • 发生关系时会发生什么?
  • 如果有关系,我想使用最低的列号

标签: r dataframe data.table max


【解决方案1】:

这可能不是最有效的方法,但它可以完成工作,

vals <- t(apply(example_df, 1, \(i)sort(i, decreasing = TRUE))[1:2,])
nms <- t(apply(example_df, 1, \(i)names(i)[order(i, decreasing = TRUE)])[1:2,])

mapply(\(x, y) paste(x, y, sep = ' '), data.frame(nms), data.frame(vals))

     X1            X2           
[1,] "mycol2 111"  "mycol4 106" 
[2,] "mycol3 -102" "mycol4 -102"
[3,] "mycol1 140"  "mycol4 140" 
[4,] "mycol1 140"  "mycol5 -150"
[5,] "mycol1 -150" "mycol2 -150"

您可以按照自己的方式整理输出。您也可以使用max.col() 对其进行矢量化处理

【讨论】:

  • 你能解释一下为什么` is used before the sort`函数吗?没有它,它会给出错误Unexpected Symbol
  • @KarthikS如果您在谈论反斜杠,它用于定义函数。您也可以选择apply(.., 1, function(i) sort()...
  • 啊,是的,对不起,在我的评论中错过了``
【解决方案2】:

这是一个 data.table 方法:

  1. 熔长
    library(data.table)
    
    df_long =   melt(setDT(example_df)[, i:=.I],"i")[
      order(-value),.SD[1:2,.(paste(variable,value),c("firstmax", "secondmax"))],i]
    
    1. 广播宽
    dcast(df_long, i~V2, value.var="V1")[,c(2,3)]
    

    输出:

          firstmax   secondmax
    1:  mycol2 111  mycol4 106
    2: mycol3 -102 mycol4 -102
    3:  mycol1 140  mycol4 140
    4:  mycol1 140 mycol5 -150
    5: mycol1 -150 mycol2 -150
    

【讨论】:

    【解决方案3】:

    这是max.col 的一种方法 - 获取每行的最大列索引,将该索引用于replace 将值用于-Inf,提取第二个索引并在pasteing 之后使用列名创建一个data.frame提取的

    first <- max.col(example_df, 'first')
    rn <- seq_len(nrow(example_df))
    second <- max.col(replace(example_df, cbind(rn, first), -Inf), "first")
    data.frame(firstmax = paste(names(example_df)[first], 
          example_df[cbind(rn, first)]), 
       secondmax = paste(names(example_df)[second], example_df[cbind(rn, second)]))
    

    -输出

        firstmax   secondmax
    1  mycol2 111  mycol4 106
    2 mycol3 -102 mycol4 -102
    3  mycol1 140  mycol4 140
    4  mycol1 140 mycol5 -150
    5 mycol1 -150 mycol2 -150
    

    【讨论】:

      【解决方案4】:

      这是我对使用循环的查询的看法

      example_list<-list()  #stores col name and value of highest and second highest
      for (i in 1:nrow(example_df)){
      example_list[[i]]<-sort(example_df[i,],decreasing = TRUE)[1:2]}
      example_list2<-list() #list with 1st sublevel containing highest colname and value and 2nd sublevel containing 2nd highest colname and value for each level of the list
      for (i in 1:length(example_list)){
      jnk<-list()
      for (j in 1:length(example_list[[i]])){
      jnk[[j]]<-c(colnames(example_list[[i]][j]),as.numeric(example_list[[i]][j]))
      example_list2[[i]]<-jnk}}
      first_max<-list() #list with colname and value of highest 
      for (i in 1:length(example_list2)){
      first_max[[i]]<-example_list2[[i]][[1]]}
      second_max<-list() #list with colname and value of 2nd highest
      for (i in 1:length(example_list2)){
      second_max[[i]]<-example_list2[[i]][[2]]}
      first_max2<-as.character() #colname and value of highest pasted together
      for (i in 1:length(first_max)){
      first_max2[i]<-paste0(first_max[[i]],sep=" ",collapse = "")}
      second_max2<-as.character() #colname and value of 2nd highest pasted together
      for (i in 1:length(second_max)){
      second_max2[i]<-paste0(second_max[[i]],sep=" ",collapse = "")}
      final_df<-data.frame(firstmax=first_max2,secondmax=second_max2) #desired df
      

      【讨论】:

        【解决方案5】:

        这是使用 kit 包中的 topn 的完美用例,调用它两次仍然比排序更大的 data.frame 更快

        library(data.table)
        library(kit)
        dt <- data.table(mycol1=c(101,-108,140,140,-150), mycol2 = c(111,-105,128,-220,-150), mycol3 = c(-103,-102,123,-210,-180), mycol4 =c(106,-102,140,-200,-180), mycol5 =c(-105,-106,120,-150,-180))
        res <- as.data.table(t(apply(dt, 1, function(x) paste(colnames(dt)[topn(x, 2L)], topn(x, 2L, index=FALSE)))))
        res
        #>             V1          V2
        #> 1:  mycol2 111  mycol4 106
        #> 2: mycol3 -102 mycol4 -102
        #> 3:  mycol1 140  mycol4 140
        #> 4:  mycol1 140 mycol5 -150
        #> 5: mycol1 -150 mycol2 -150
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-31
          • 1970-01-01
          • 1970-01-01
          • 2015-11-21
          相关资源
          最近更新 更多