Search code examples
rcbind

cbind: is there a way to have missing values set to NA?


Please forgive me if I missed an answer to such a simple question.

I want to use cbind() to bind two columns. One of them is a single entry shorter in length.

Can I have R supply an NA for the missing value?

The documentation discusses a deparse.level argument but this doesn't seem to be my solution.

Further, if I may be so bold, would there also be a quick way to prepend the shorter column with NA's?


Solution

  • Try this:

    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
    

    or this:

    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
    

    I think this will do something similar to what DWin suggested and work regardless of which vector is shorter:

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

    The code above can also be condensed to:

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

    EDIT

    Here is what I came up with to address the question:

    "Further, if I may be so bold, would there also be a quick way to prepend the shorter column with NA's?"

    inserted into the original post by 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
    

    Here is a function:

    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)
    

    This version allows you to cbind two vectors of different mode:

    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)