2015-03-11 8 views
9

Posso definire un valore di "riempimento" per NA in join dplyr? Ad esempio nel join definire che tutti i valori di NA dovrebbero essere 1?dplyr join definisce i valori NA

require(dplyr) 
lookup <- data.frame(cbind(c("USD","MYR"),c(0.9,1.1))) 
names(lookup) <- c("rate","value") 
fx <- data.frame(c("USD","MYR","USD","MYR","XXX","YYY")) 
names(fx)[1] <- "rate" 
left_join(x=fx,y=lookup,by=c("rate")) 

Sopra codice creerà NA per i valori di "XXX" e "YYY". Nel mio caso mi unisco a un numero elevato di colonne e ci saranno molte non partite. Tutte le non corrispondenze dovrebbero avere lo stesso valore. So che posso farlo in diversi passaggi ma la domanda è tutta da fare in uno? Grazie!

risposta

13

Prima di tutto, mi consiglia di non utilizzare la combinazione data.frame(cbind(...)). Ecco perché: cbind crea un matrix per impostazione predefinita se si passano solo vettori atomici. E le matrici in R possono avere solo un tipo di dati (si pensi alle matrici come vettore con attributo di dimensione, cioè numero di righe e colonne). Pertanto, il codice

cbind(c("USD","MYR"),c(0.9,1.1)) 

crea una matrice di carattere:

str(cbind(c("USD","MYR"),c(0.9,1.1))) 
# chr [1:2, 1:2] "USD" "MYR" "0.9" "1.1" 

anche se probabilmente vi aspettavate un frame di dati finale con una colonna di carattere o il fattore (rate) e una colonna numerica (valore). Ma quello che si ottiene è:

str(data.frame(cbind(c("USD","MYR"),c(0.9,1.1)))) 
#'data.frame': 2 obs. of 2 variables: 
# $ X1: Factor w/ 2 levels "MYR","USD": 2 1 
# $ X2: Factor w/ 2 levels "0.9","1.1": 1 2 

perché le stringhe (caratteri) vengono convertiti in fattori quando si utilizza data.frame di default (è possibile aggirare questo specificando stringsAsFactors = FALSE nella chiamata data.frame()).

suggerisco il seguente approccio alternativo per creare i dati di esempio (si noti anche che si può facilmente specificare i nomi delle colonne nella stessa chiamata):

lookup <- data.frame(rate = c("USD","MYR"), 
        value = c(0.9,1.1)) 

fx <- data.frame(rate = c("USD","MYR","USD","MYR","XXX","YYY")) 

Ora, per voi domanda effettiva, se ho capito bene , si desidera sostituire tutti i NA s con un 1 nei dati uniti. Se questo è corretto, ecco una funzione personalizzata utilizzando left_join e mutate_each per farlo:

library(dplyr) 
left_join_NA <- function(x, y, ...) { 
    left_join(x = x, y = y, by = ...) %>% 
    mutate_each(funs(replace(., which(is.na(.)), 1))) 
} 

Ora è possibile applicarlo ai dati in questo modo:

> left_join_NA(x = fx, y = lookup, by = "rate") 
# rate value 
#1 USD 0.9 
#2 MYR 1.1 
#3 USD 0.9 
#4 MYR 1.1 
#5 XXX 1.0 
#6 YYY 1.0 
#Warning message: 
#joining factors with different levels, coercing to character vector 

noti che si finisce con una colonna di carattere (rate) e una colonna numerica (valore) e tutti AN vengono sostituiti da 1.

str(left_join_NA(x = fx, y = lookup, by = "rate")) 
#'data.frame': 6 obs. of 2 variables: 
# $ rate : chr "USD" "MYR" "USD" "MYR" ... 
# $ value: num 0.9 1.1 0.9 1.1 1 1 
+2

primo grazie per i suggerimenti completi sulla creazione dei dati. In realtà è abbastanza utile per le domande future. Secondo, la tua formula è pulita e la userò. grazie molto! – Triamus

+2

perché non usare semplicemente 'fx [is.na (fx)] <- 1'? – rrs

+0

@rrs perché questo potrebbe essere 1/2 via attraverso una catena di dplyr lunga – Nelson

2

inciampai sullo stesso problema con dplyr e scritto una piccola funzione che ha risolto il problema. (La soluzione richiede tidyr e dplyr)

left_join0 <- function(x, y, fill = 0L){ 
    z <- left_join(x, y) 
    tmp <- setdiff(names(z), names(x)) 
    z <- replace_na(z, setNames(as.list(rep(fill, length(tmp))), tmp)) 
    z 
} 

Originariamente risposto a: R Left Outer Join with 0 Fill Instead of NA While Preserving Valid NA's in Left Table

1

Se stai usando dplyr in ogni caso, si potrebbe anche approfittare delle dplyr::coalesce, e utilizzare la sintassi dplyr a passare in quella un 1 o 0. credo che questo sembra bello ...

... %>% 
mutate_if(is.numeric,coalesce,0) 

Qualora il 0 è l'arg passato a dplyr::coalesce per sostituire AN.

Nell'esempio della domanda, ci sono dati con fattori. Sono convinto che non si disporranno dei tassi di FX come fattori o di un altro vettore in cui sostituire NA con zero, quindi vado avanti e aggiungo questo passaggio solo per rendere eseguibile la risposta dopo l'esempio fornito.

# replace NAs with zeros for all numeric columns 
# 
# ... code from question above 
left_join(x=fx,y=lookup,by=c("rate")) %>% 
    # ignore if factors in value column are because it's a toy example 
    mutate(value = as.numeric(as.character(value))) %>% 
    # the good stuff here 
    mutate_if(is.numeric,coalesce,0)