【问题标题】:cbind: is there a way to have missing values set to NA?cbind:有没有办法将缺失值设置为 NA?
【发布时间】:2013-10-05 03:10:39
【问题描述】:

如果我错过了这样一个简单问题的答案,请原谅我。

我想使用cbind() 来绑定两列。其中之一是长度较短的单个条目。

我可以让 R 为缺失值提供一个 NA 吗?

文档讨论了 deparse.level 参数,但这似乎不是我的解决方案。

此外,如果我可以这么大胆,是否还有一种快速的方法可以在较短的列前面加上 NA's?

【问题讨论】:

    标签: r cbind


    【解决方案1】:

    不久前,我编写了一个名为 Cbind 的函数,旨在执行此类操作。在当前形式下,它应该能够处理向量、data.frames 和矩阵作为输入。

    现在,函数在这里:https://gist.github.com/mrdwab/6789277

    这是如何使用该功能的:

    x <- 1:5
    y <- letters[1:4]
    z <- matrix(1:4, ncol = 2, dimnames = list(NULL, c("a", "b")))
    Cbind(x, y, z)
    #   x    y z_a z_b
    # 1 1    a   1   3
    # 2 2    b   2   4
    # 3 3    c  NA  NA
    # 4 4    d  NA  NA
    # 5 5 <NA>  NA  NA
    Cbind(x, y, z, first = FALSE)
    #   x    y z_a z_b
    # 1 1 <NA>  NA  NA
    # 2 2    a  NA  NA
    # 3 3    b  NA  NA
    # 4 4    c   1   3
    # 5 5    d   2   4
    

    需要的三个函数分别是padNAdotnamesCbind,定义如下:

    padNA <- function (mydata, rowsneeded, first = TRUE) {
    ## Pads vectors, data.frames, or matrices with NA
      temp1 = colnames(mydata)
      rowsneeded = rowsneeded - nrow(mydata)
      temp2 = setNames(
        data.frame(matrix(rep(NA, length(temp1) * rowsneeded), 
                          ncol = length(temp1))), temp1)
      if (isTRUE(first)) rbind(mydata, temp2)
      else rbind(temp2, mydata)
    }
    
    dotnames <- function(...) {
    ## Gets the names of the objects passed through ...
      vnames <- as.list(substitute(list(...)))[-1L]
      vnames <- unlist(lapply(vnames,deparse), FALSE, FALSE)
      vnames
    }
    
    Cbind <- function(..., first = TRUE) {
    ## cbinds vectors, data.frames, and matrices together
      Names <- dotnames(...)
      datalist <- setNames(list(...), Names)
      nrows <- max(sapply(datalist, function(x) 
        ifelse(is.null(dim(x)), length(x), nrow(x))))
      datalist <- lapply(seq_along(datalist), function(x) {
        z <- datalist[[x]]
        if (is.null(dim(z))) {
          z <- setNames(data.frame(z), Names[x])
        } else {
          if (is.null(colnames(z))) {
            colnames(z) <- paste(Names[x], sequence(ncol(z)), sep = "_")
          } else {
            colnames(z) <- paste(Names[x], colnames(z), sep = "_")
          }
        }
        padNA(z, rowsneeded = nrows, first = first)
      })
      do.call(cbind, datalist)
    }
    

    我停止处理该函数的部分原因是gdata 包已经有一个名为cbindX 的函数,它可以处理cbinding data.frames 和具有不同行数的矩阵。它不能直接作用于向量,所以你需要先将它们转换为data.frames。

    library(gdata)
    cbindX(data.frame(x), data.frame(y), z)
    #   x    y  a  b
    # 1 1    a  1  3
    # 2 2    b  2  4
    # 3 3    c NA NA
    # 4 4    d NA NA
    # 5 5 <NA> NA NA
    

    【讨论】:

    • +1 用于提及cbindX - 效果很好。这里是the code
    【解决方案2】:

    试试这个:

    x <- c(1:5)
    y <- c(4:1)
    length(y) = length(x)
    cbind(x,y)
         x  y
    [1,] 1  4
    [2,] 2  3
    [3,] 3  2
    [4,] 4  1
    [5,] 5 NA
    

    或者这个:

    x <- c(4:1)
    y <- c(1:5)
    length(x) = length(y)
    cbind(x,y)
          x y
    [1,]  4 1
    [2,]  3 2
    [3,]  2 3
    [4,]  1 4
    [5,] NA 5
    

    我认为这将做一些类似于 DWin 建议的事情并且不管哪个向量更短都可以工作:

    x <- c(4:1)
    y <- c(1:5)
    
    lengths <- max(c(length(x), length(y)))
    length(x) <- lengths
    length(y) <- lengths
    cbind(x,y)
    

    上面的代码也可以压缩成:

    x <- c(4:1)
    y <- c(1:5)
    length(x) <- length(y) <- max(c(length(x), length(y)))
    cbind(x,y)
    

    编辑

    这是我想出的解决问题的方法:

    “此外,如果我可以这么大胆,是否还有一种快速的方法可以在较短的列前加上 NA?”

    插入 Matt O'Brien 的原始帖子中。

    x <- c(4:1)
    y <- c(1:5)
    
    first <- 1   # 1 means add NA to top of shorter vector
                 # 0 means add NA to bottom of shorter vector
    
    if(length(x)<length(y)) {
         if(first==1) x = c(rep(NA, length(y)-length(x)),x);y=y
         if(first==0) x = c(x,rep(NA, length(y)-length(x)));y=y
    } 
    
    if(length(y)<length(x)) {
         if(first==1) y = c(rep(NA, length(x)-length(y)),y);x=x
         if(first==0) y = c(y,rep(NA, length(x)-length(y)));x=x
    } 
    
    cbind(x,y)
    
    #       x y
    # [1,] NA 1
    # [2,]  4 2
    # [3,]  3 3
    # [4,]  2 4
    # [5,]  1 5
    

    这是一个函数:

    x <- c(4:1)
    y <- c(1:5)
    
    first <- 1   # 1 means add NA to top of shorter vector
                 # 0 means add NA to bottom of shorter vector
    
    my.cbind <- function(x,y,first) {
    
      if(length(x)<length(y)) {
         if(first==1) x = c(rep(NA, length(y)-length(x)),x);y=y
         if(first==0) x = c(x,rep(NA, length(y)-length(x)));y=y
      } 
    
      if(length(y)<length(x)) {
         if(first==1) y = c(rep(NA, length(x)-length(y)),y);x=x
         if(first==0) y = c(y,rep(NA, length(x)-length(y)));x=x
      } 
    
      return(cbind(x,y))
    
    }
    
    my.cbind(x,y,first)
    
    my.cbind(c(1:5),c(4:1),1)
    my.cbind(c(1:5),c(4:1),0)
    my.cbind(c(1:4),c(5:1),1)
    my.cbind(c(1:4),c(5:1),0)
    my.cbind(c(1:5),c(5:1),1)
    my.cbind(c(1:5),c(5:1),0)
    

    这个版本允许你cbind两个不同模式的向量:

    x <- c(4:1)
    y <- letters[1:5]
    
    first <- 1   # 1 means add NA to top of shorter vector
                 # 0 means add NA to bottom of shorter vector
    
    my.cbind <- function(x,y,first) {
    
      if(length(x)<length(y)) {
         if(first==1) x = c(rep(NA, length(y)-length(x)),x);y=y
         if(first==0) x = c(x,rep(NA, length(y)-length(x)));y=y
      } 
    
      if(length(y)<length(x)) {
         if(first==1) y = c(rep(NA, length(x)-length(y)),y);x=x
         if(first==0) y = c(y,rep(NA, length(x)-length(y)));x=x
      } 
    
      x <- as.data.frame(x)
      y <- as.data.frame(y)
    
      return(data.frame(x,y))
    
    }
    
    my.cbind(x,y,first)
    
    #    x y
    # 1 NA a
    # 2  4 b
    # 3  3 c
    # 4  2 d
    # 5  1 e
    
    my.cbind(c(1:5),letters[1:4],1)
    my.cbind(c(1:5),letters[1:4],0)
    my.cbind(c(1:4),letters[1:5],1)
    my.cbind(c(1:4),letters[1:5],0)
    my.cbind(c(1:5),letters[1:5],1)
    my.cbind(c(1:5),letters[1:5],0)
    

    【讨论】:

    • @DWin 如果x 更短,你能不能直接切换顺序并使用length(x) = length(y)
    • 当然可以,但是您应该使用测试然后执行正确的操作。
    • @DWin 好的。是的,那将是最好的。我可以尝试创建一个函数来做到这一点,除非你先这样做。
    猜你喜欢
    • 2019-10-15
    • 2019-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-09
    相关资源
    最近更新 更多