2015-02-23 16 views
5

Chciałbym połączyć 2 df, gdzie w df1 zawiera 2 kolumny i df2 1 kolumny, jak zastosować funkcję scalania w tym przypadku?Jak scalić 2 kolumny na 1 kolumnie

Oto przykładowy przypadek:

df1 <- data.frame(var1=letters[1:5],var2=letters[6:10]) 
df2 <- data.frame(var3=letters[1:10]) 

Fałsz próba:

merge(df1,df2,by.x=c("var1","var2"),by.y="var3",all.y=TRUE) 

Jak połączyć te dwa df, tak że poszukiwania dopasowanie używa obu kolumn DF1 (zm1 & var2) i działa na df2 (var3)?

Pożądany wyjściowa:

var1 var2 var3 
1  a f  a 
2  b g  b 
3  c h  c 
4  d i  d 
5  e j  e 
6  <NA> <NA> f 
7  <NA> <NA> g 
8  <NA> <NA> h 
9  <NA> <NA> i 
10 <NA> <NA> j 

EDIT: Lepsze dane (mam nadzieję):

df1 <- data.frame(var1=c(letters[1:5],rep("x",5)),var2=c(letters[6:10],rep("x",5))) 
df2 <- data.frame(var3=letters[1:10]) 

Pożądany wyjściowa:

 var1 var2 var3 
1  a f  a 
2  b g  b 
3  c h  c 
4  d i  d 
5  e j  e 
6  x x  f 
7  x x  g 
8  x x  h 
9  x x  i 
10  x x  j 
+0

'dwukrotnie merge' may być jednym możliwym rozwiązaniem. – Metrics

+0

tak, myślałem o tym, ale może być brudny z moich prawdziwych danych. – Maximilian

+0

przez niechlujny, mam na myśli zmywanie danych :) Myślałem, że to może być raczej podatne na błąd – Maximilian

Odpowiedz

5

Można użyć merge z argumentem by='row.names' i sort=F (jak wskazano przez Matthew Plourde), aby nie pozwolić merge bałagan kolejność:

> merge(df1, df2, by='row.names', sort=FALSE, all=TRUE)[c("var1", "var2", "var3")] 
    var1 var2 var3 
1  a f a 
2  b g b 
3  c h c 
4  d i d 
5  e j e 
6 <NA> <NA> i 
7 <NA> <NA> f 
8 <NA> <NA> g 
9 <NA> <NA> h 
10 <NA> <NA> j 
+1

nigdy nie pomyślałbym o 'by = 0'. Podanie 'scalania' argumentu' sort = FALSE' daje ci całkowitą pewność. –

+1

Powinieneś naprawdę wyjaśnić, że dołącza się do nazw wierszy. –

5

Oto możliwe data.table rozwiązanie jak za pierwszym pożądanym wyjściem

library(data.table) 
setkey(setDT(df2), var3) 
df2[df1, `:=`(var1 = i.var1, var2 = i.var2)][] 
#  var3 var1 var2 
# 1: a a f 
# 2: b b g 
# 3: c c h 
# 4: d d i 
# 5: e e j 
# 6: f NA NA 
# 7: g NA NA 
# 8: h NA NA 
# 9: i NA NA 
# 10: j NA NA 
+0

Pracowałem nad tym samym rozwiązaniem. Ale byłeś szybki :-) – akrun

+0

Wygląda na to, że @ user1981275 opracował bardziej ogólne rozwiązanie –

+0

tak, to jest bardzo nowatorskie. Nigdy nie myślałem o 'by = 0' (może widziałem to już wcześniej, nie pamiętam). – akrun

5

Naprawdę wystarczy zmienić kolejność df2 według df1 i cbind im:

cbind(df1, df2[order(match(df2$var3, df1$var1)),, drop=FALSE]) 

Jeśli df2 ma więcej niż jedną kolumnę, nie trzeba drop=FALSE.

# var1 var2 var3 
# 1  a f a 
# 2  b g b 
# 3  c h c 
# 4  d i d 
# 5  e j e 
# 6  x x f 
# 7  x x g 
# 8  x x h 
# 9  x x i 
# 10 x x j 

Zgodnie z tym podejściem, dla pierwszego zestawu danych bez xs, można użyć:

cbind(lapply(df1, `length<-`, nrow(df2)), df2[order(match(df2$var3, df1$var1)),, drop=FALSE]) 

# var1 var2 var3 
# 1  a f a 
# 2  b g b 
# 3  c h c 
# 4  d i d 
# 5  e j e 
# 6 <NA> <NA> f 
# 7 <NA> <NA> g 
# 8 <NA> <NA> h 
# 9 <NA> <NA> i 
# 10 <NA> <NA> j 

Albo w bardziej czytelny sposób:

df1 <- lapply(df1, `length<-`, nrow(df2)) 
df2 <- df2[order(match(df2$var3, df1$var1)),, drop=FALSE] 
cbind(df1, df2) 
+0

dla drugiego zestawu danych (z "x"), dlaczego nie po prostu "cbind (df1, df2)"? – user1981275

+0

To zakłada, że ​​"df2" jest już w porządku, co jest właściwością przykładowych danych OP, ale nie wyobrażam sobie, że jest to własność jego prawdziwych danych w ogóle. –

Powiązane problemy