【问题标题】:Combine column to remove NA's合并列以删除 NA
【发布时间】:2013-01-11 21:06:56
【问题描述】:

我在 R 中有一些列,对于每一行,其中一个只会有一个值,其余的将是 NA。我想将这些与非 NA 值组合成一列。有谁知道这样做的简单方法。例如我可以有如下:

data <- data.frame('a' = c('A','B','C','D','E'),
                   'x' = c(1,2,NA,NA,NA),
                   'y' = c(NA,NA,3,NA,NA),
                   'z' = c(NA,NA,NA,4,5))

所以我会的

'a' 'x' 'y' 'z'  
 A   1   NA  NA  
 B   2   NA  NA  
 C  NA   3   NA  
 D  NA   NA  4  
 E  NA   NA  5

我想得到

 'a' 'mycol'  
  A   1  
  B   2  
  C   3  
  D   4  
  E   5  

包含 NA 的列的名称会根据查询中前面的代码而变化,因此我将无法显式调用列名,但我将包含 NA 的列的列名存储为向量,例如在此示例中为 cols &lt;- c('x','y','z'),因此可以使用 data[, cols] 调用列。

任何帮助将不胜感激。

谢谢

【问题讨论】:

    标签: r merge na


    【解决方案1】:

    基于dplyr::coalesce 的解决方案可能是:

    data %>% mutate(mycol = coalesce(x,y,z)) %>%
             select(a, mycol)
    #   a mycol
    # 1 A     1
    # 2 B     2
    # 3 C     3
    # 4 D     4
    # 5 E     5 
    

    数据

    data <- data.frame('a' = c('A','B','C','D','E'),
                     'x' = c(1,2,NA,NA,NA),
                     'y' = c(NA,NA,3,NA,NA),
                     'z' = c(NA,NA,NA,4,5))
    

    【讨论】:

      【解决方案2】:

      您可以使用unlist 将列转换为一个向量。之后,可以使用na.omit 删除NAs。

      cbind(data[1], mycol = na.omit(unlist(data[-1])))
      
         a mycol
      x1 A     1
      x2 B     2
      y3 C     3
      z4 D     4
      z5 E     5
      

      【讨论】:

      • 此解决方案仅适用于根据可用数据对列进行排序的情况。第一列未与其他数据集的正确值配对,例如:data &lt;- data.frame('a' = c('A','B','C','D','E'),'x' = c(NA,NA,3,NA,NA),'y' = c(1,2,NA,NA,NA),'z' = c(NA,NA,NA,4,5))
      • 这应该处理@julia提出的问题:cbind.data.frame(data[1], mycol=c(na.omit(c(t(data[, -1])))))
      • 我在 stackoverflow.com/questions/40878660/… 处添加了此问题的特定扩展作为新帖子。
      【解决方案3】:

      这是一个更通用(但更简单)的解决方案,它扩展到具有无序 NA 的所有列类型(因子、字符等)。该策略只是使用is.na 将其他列的非 NA 值合并到您的合并列中进行索引:

      data$m = data$x  # your new merged column start with x
      data$m[!is.na(data$y)] = data$y[!is.na(data$y)]  # merge with y
      data$m[!is.na(data$z)] = data$z[!is.na(data$z)]  # merge with z
      
      > data
        a  x  y  z m
      1 A  1 NA NA 1
      2 B  2 NA NA 2
      3 C NA  3 NA 3
      4 D NA NA  4 4
      5 E NA NA  5 5
      

      请注意,如果同一行中有多个非 NA 值,这将覆盖 m 中的现有值。如果您有很多列,您可以通过循环 colnames(data) 来自动执行此操作。

      【讨论】:

        【解决方案4】:

        我会将rowSums()na.rm = TRUE 参数一起使用:

        cbind.data.frame(a=data$a, mycol = rowSums(data[, -1], na.rm = TRUE))
        

        给出:

        > cbind.data.frame(a=data$a, mycol = rowSums(data[, -1], na.rm = TRUE))
          a mycol
        1 A     1
        2 B     2
        3 C     3
        4 D     4
        5 E     5
        

        您必须直接调用该方法 (cbind.data.frame),因为上面的第一个参数不是数据框。

        【讨论】:

        • 很好的解决方案。但是字符数据呢?
        • 由于 OP 的示例不包含字符数据(标识符列除外),我没有考虑到这一点;这里的其他选项可以解决这个问题,但要付出代价;例如,取消列出具有许多行和列的数据框会很慢。如果您有非数字数据,请使用另一个选项,但如果您没有,这是一个非常简单且相对快速的解决方案。
        【解决方案5】:

        这样的?

        data.frame(a=data$a, mycol=apply(data[,-1],1,sum,na.rm=TRUE))
        

        给:

          a mycol
        1 A     1
        2 B     2
        3 C     3
        4 D     4
        5 E     5
        

        【讨论】:

        • 是的,您是对的,感谢您指出这一点!我不会编辑我的帖子,因为它会与 Gavin Simpson 的帖子重复。
        • 感谢 juba,如果列始终是数字,就像在我的示例中一样,但实际上列有时是字符,所以我使用了 Sven 的上述答案。
        【解决方案6】:

        max 也可以。也适用于字符串向量。

        cbind(data[1], mycol=apply(data[-1], 1, max, na.rm=T))
        

        【讨论】:

          【解决方案7】:

          在相关链接 (suppress NAs in paste()) 中,我展示了带有 na.rm 选项的 paste 版本(不幸的名称为 paste5)。

          这样代码就变成了

          cols <- c("x", "y", "z")
          cbind.data.frame(a = data$a, mycol = paste2(data[, cols], na.rm = TRUE))
          

          paste5 的输出是一个字符,如果你有字符数据,它就可以工作,否则你需要强制转换为你想要的类型。

          【讨论】:

            【解决方案8】:

            虽然这不是 OP 的情况,但似乎有些人喜欢基于总和的方法,以均值和模式思考如何,以使答案更具普遍性。这个答案与标题相符,这是很多人会发现的。

            data <- data.frame('a' = c('A','B','C','D','E'),
                               'x' = c(1,2,NA,NA,9),
                               'y' = c(NA,6,3,NA,5),
                               'z' = c(NA,NA,NA,4,5))
            
            splitdf<-split(data[,c(2:4)], seq(nrow(data[,c(2:4)])))
            
            data$mean<-unlist(lapply(splitdf, function(x)  mean(unlist(x), na.rm=T) ) )
            data$mode<-unlist(lapply(splitdf, function(x)  {
              tab <- tabulate(match(x, na.omit(unique(unlist(x) )))); 
                              paste(na.omit(unique(unlist(x) ))[tab == max(tab) ], collapse = ", " )}) )
            
            data
              a  x  y  z     mean mode
            1 A  1 NA NA 1.000000    1
            2 B  2  6 NA 4.000000 2, 6
            3 C NA  3 NA 3.000000    3
            4 D NA NA  4 4.000000    4
            5 E  9  5  5 6.333333    5
            

            【讨论】:

              【解决方案9】:

              使用dplyrtidyr 的一种可能性是:

              data %>%
               gather(variables, mycol, -1, na.rm = TRUE) %>%
               select(-variables)
              
                 a mycol
              1  A     1
              2  B     2
              8  C     3
              14 D     4
              15 E     5
              

              在这里它将数据从宽格式转换为长格式,从该操作中排除第一列并删除 NA。

              【讨论】:

                【解决方案10】:

                如果你想坚持基地,

                data <- data.frame('a' = c('A','B','C','D','E'),'x' = c(1,2,NA,NA,NA),'y' = c(NA,NA,3,NA,NA),'z' = c(NA,NA,NA,4,5))
                data[is.na(data)]<-","
                data$mycol<-paste0(data$x,data$y,data$z)
                data$mycol <- gsub(',','',data$mycol)
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2017-04-14
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-09-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-09-28
                  • 2021-07-21
                  相关资源
                  最近更新 更多