cbind: есть ли способ установить отсутствующие значения в NA?

Пожалуйста, простите меня, если я пропустил ответ на такой простой вопрос.

Я хочу использовать cbind() для привязки двух столбцов. Один из них представляет собой одиночную запись меньшей длины.

Могу ли я сделать так, чтобы R предоставил NA для отсутствующего значения?

В документации обсуждается аргумент deparse.level, но это не похоже на мое решение.

Кроме того, если я могу быть настолько смелым, будет ли также быстрый способ добавить более короткий столбец с NA?


person tumultous_rooster    schedule 29.09.2013    source источник


Ответы (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?»

вставлен в исходный пост Мэттом О'Брайеном.

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)

Эта версия позволяет связать два вектора разного режима:

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)
person Mark Miller    schedule 29.09.2013
comment
@DWin Не могли бы вы просто изменить порядок и использовать length(x) = length(y), если x было короче? - person Mark Miller; 29.09.2013
comment
Конечно, но вы должны использовать тест, а затем выполнить правильное действие. - person IRTFM; 29.09.2013
comment
@DWin Хорошо. Да, это было бы лучше всего. Я могу попытаться создать функцию для этого, если вы не сделаете это первым. - person Mark Miller; 29.09.2013

Некоторое время назад я собрал функцию под названием 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

Требуемые функции two — это padNA, dotnames и Cbind, которые определяются следующим образом:

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, которая обрабатывает cbindобработку 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
person A5C1D2H2I1M1N2O1R2T1    schedule 29.09.2013
comment
+1 за упоминание cbindX - работает очень хорошо. Вот код - person n1k31t4; 02.12.2015