2013-09-29 12 views
11

Per favore perdonami se ho perso una risposta a una domanda così semplice.cbind: c'è un modo per avere valori mancanti impostati su NA?

Desidero utilizzare cbind() per associare due colonne. Uno di questi è una singola voce più breve di lunghezza.

Posso fornire R un NA per il valore mancante?

La documentazione tratta un argomento deparse.level ma questa non sembra essere la mia soluzione.

Inoltre, se posso essere così sfacciato, ci sarebbe anche un modo rapido per anteporre la colonna più corta con NA?

risposta

7

Prova questo:

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 

o questo:

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 

Penso che questo farà qualcosa di simile a quello che DWin suggerito e lavorare indipendentemente da quale vettore è più breve:

x <- c(4:1) 
y <- c(1:5) 

lengths <- max(c(length(x), length(y))) 
length(x) <- lengths 
length(y) <- lengths 
cbind(x,y) 

Il codice di cui sopra può anche essere condensato a:

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

EDIT

Ecco quello che mi è venuta per affrontare la questione:

"Inoltre, se posso permettermi, ci sarebbero anche un modo veloce per anteporre la colonna più corta con NA di ?"

inserito nel post originale da 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 

Ecco una funzione:

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) 

Questa versione consente di cbind due vettori di diverse modalità:

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) 
+1

Funzionerà correttamente solo se y è più corto di x. –

+0

@DWin Non potresti semplicemente cambiare l'ordine e usare 'length (x) = length (y)' se 'x' era più corto? –

+2

Certo, ma è necessario utilizzare un test e quindi eseguire l'azione corretta. –

4

Qualche tempo fa avevo messo insieme una funzione chiamata Cbind che era destinato a fare questo genere di cose. Nella sua forma attuale, dovrebbe essere in grado di gestire i vettori, data.frame s, e le matrici come input.

Per ora, la funzione è qui: https://gist.github.com/mrdwab/6789277

Ecco come si potrebbe usare la funzione:

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 

I due tre funzioni richieste sono padNA, dotnames, e Cbind, che sono definito come segue:

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) 
} 

Parte del motivo per cui ho smesso di funzionare sulla funzione era che il pacchetto gdata ha già una funzione chiamata cbindX che gestisce cbind ing data.frame s e matrici con diversi numeri di righe. Non funzionerà direttamente sui vettori, quindi è necessario prima convertirli in data.frame s.

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 
+0

+1 per aver menzionato 'cbindX' - funziona molto bene. Ecco [il codice] (https://github.com/cran/gdata/blob/master/R/cbindX.R) –