2015-03-11 13 views
9

Kann ich einen "fill" -Wert für NA in dplyr join definieren? Zum Beispiel in der Join-Definition, dass alle NA-Werte 1 sein sollten?dplyr join define NA-Werte

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

Der obige Code erstellt NA für die Werte "XXX" und "YYY". In meinem Fall schließe ich mich einer großen Anzahl von Spalten an und es wird viele Nicht-Übereinstimmungen geben. Alle Nicht-Übereinstimmungen sollten denselben Wert haben. Ich weiß, dass ich es in mehreren Schritten tun kann, aber die Frage ist, kann alles in einem getan werden? Danke!

Antwort

13

Zunächst möchte ich empfehlen, die Kombination data.frame(cbind(...)) nicht zu verwenden. Hier ist warum: cbind erstellt eine matrix standardmäßig, wenn Sie nur atomare Vektoren an es übergeben. Und Matrizen in R können nur einen Typ von Daten haben (man denke an Matrizen als ein Vektor mit einem Dimensionsattribut, d. H. Einer Anzahl von Reihen und Spalten). Daher Code

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

schafft eine Zeichenmatrix:

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

obwohl Sie wahrscheinlich einen endgültigen Datenrahmen mit einer Zeichen oder Faktor-Säule (Rate) und einem numerischen Spalte (Wert) erwartet. Aber was man bekommt, ist:

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 

weil Strings (Zeichen) Faktoren umgewandelt werden, wenn data.frame standardmäßig mit (Sie können dies umgehen, indem sie stringsAsFactors = FALSE im data.frame() Aufruf spezifiziert).

Ich schlage vor, den folgenden alternativen Ansatz, die Beispieldaten zu erstellen (auch beachten Sie, dass Sie leicht die Spaltennamen in dem gleichen Anruf angeben):

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

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

Nun, für Sie aktuelle Frage, wenn ich das richtig verstehen , Sie möchten alle s durch eine 1 in den verknüpften Daten ersetzen. Wenn das stimmt, ist hier eine benutzerdefinierte Funktion left_join und mutate_each mit tun, dass:

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

Jetzt können Sie es auf Ihre Daten wie folgt anwenden:

> 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 

Beachten Sie, dass Sie mit einer Zeichenspalte am Ende (Rate) und eine numerische Spalte (Wert) und alle nationalen Agenturen werden von 1.

ersetzt
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

erstmal danke für die umfassenden datenerstellungshinweise. Das ist eigentlich sehr hilfreich für zukünftige Fragen. Zweitens ist deine Formel ordentlich und ich werde sie benutzen. Danke vielmals! – Triamus

+2

Warum nicht einfach 'fx [is.na (fx)] <- 1' verwenden? – rrs

+0

@rrs, weil das ein halber Weg durch eine lange dplyr-Kette sein könnte – Nelson

2

ich auf dem gleichen Problem mit dplyr stolperte und schrieb eine kleine Funktion, die mein Problem gelöst. (Die Lösung erfordert tidyr und 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 
} 

Ursprünglich beantwortet unter: R Left Outer Join with 0 Fill Instead of NA While Preserving Valid NA's in Left Table

1

Wenn Sie mit dplyr sowieso, dann kann man auch nutzen dplyr::coalesce, und verwenden Sie die dplyr Syntax in das passieren a 1 oder 0 ich denke, das ... schön aussieht

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

Wo die 0 die aRG dplyr::coalesce vergangen ist Nas zu ersetzen.

In dem Beispiel in der Frage gibt es Datenrahmen mit Faktoren. Ich bin sicher, dass man keine FX-Kurse als Faktoren haben würde, oder einen anderen Vektor, in dem du NA durch Null ersetzen würdest. Also füge ich diesen Schritt unten hinzu, um die Antwort nach dem bereitgestellten Beispiel ausführbar zu machen.

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