2013-04-16 5 views
14

Jak scalić 2 podobne ramki danych, ale czy mają one większe znaczenie?Scalanie ramek danych i nadpisywanie wartości

Na przykład:

Dataframe 1

Date  Col1 Col2 
jan   2  1 
feb   4  2 
march  6  3 
april  8  NA 

Dataframe 2

Date  Col2 Col3 
jan   9  10 
feb   8  20 
march  7  30 
april  6  40 

złączenie według daty dataframe 1 nadrzędności ale dataframe 2 wykroje napełniania

DataframeMerge

Date  Col1 Col2 Col3 
jan   2  1  10 
feb   4  2  20 
march  6  3  30 
april  8  6  40 

EDIT - ROZWIĄZANIE

commonNames <- names(df1)[which(colnames(df1) %in% colnames(df2))] 
commonNames <- commonNames[commonNames != "key"] 
dfmerge<- merge(df1,df2,by="key",all=T) 
for(i in commonNames){ 
    left <- paste(i, ".x", sep="") 
    right <- paste(i, ".y", sep="") 
    dfmerge[is.na(dfmerge[left]),left] <- dfmerge[is.na(dfmerge[left]),right] 
    dfmerge[right]<- NULL 
    colnames(dfmerge)[colnames(dfmerge) == left] <- i 
} 

Odpowiedz

12
merdat <- merge(dfrm1,dfrm2, by="Date") # seems self-documenting 

# explanation for next line in text below. 
merdat$Col2.y[ is.na(merdat$Col2.y) ] <- merdat$Col2.x[ is.na(merdat$Col2.y) ] 

Następnie zmień nazwę "merdat $ Col2.y" na "merdat $ Col2" i usuń "merdat $ Col2.x".

W odpowiedzi na prośbę o więcej komentarzy: Jednym ze sposobów aktualizacji tylko części wektora jest skonstruowanie wektora logicznego do indeksowania i zastosowanie go "[" po obu stronach przydziału. Innym sposobem jest opracowanie wektora logicznego, który jest tylko na LHS przypisania, ale następnie uczynić wektor przy użyciu rep(), który ma taką samą długość jak sum(logical.vector). Celem jest, aby oba wystąpienia miały tę samą długość (i kolejność) przydziału, co zastępowane elementy.

+0

dobra odpowiedź, ale kilka dodatkowych komentarzy w kodzie sprawi, że będzie ona bardzo przydatna. – Sam

+0

Doceniam odpowiedź, ale "przykro mi to mówić, zapomniałem wspomnieć o jednym ważnym elemencie informacji, innym niż data (klucz) kolumny Nie znam innych kolumn w tabelach. Niektóre mogą pasować do niektórych, nie mogą.Przypuszczam, że mógłbym po prostu użyć dopasowania między nazwami (dfrm1) i nazwami (dfrm2), aby uzyskać kolumny, których potrzebuję do zastosowania twojego kodu? (dołączając oczywiście x i y do nazw pseudonimów) – EvilWeebl

+0

Dzięki za pomoc, wziąłem twoją odpowiedź i rozszerzyłem ją, aby pokryć, gdy podobne kolumny są nieznane. Dodałem rozwiązanie do mojego pytania, aby pomóc każdemu w przyszłości. – EvilWeebl

5

Rozważmy następujący przykład:

> d1 <- data.frame(x=1:4, a=2:5, b=c(3,4,5,NA)) 
> d1 
    x a b 
1 1 2 3 
2 2 3 4 
3 3 4 5 
4 4 5 NA 
> d2 <- data.frame(x=1:4, b=c(6,7,8,9), c=11:14) 
> d2 
    x b c 
1 1 6 11 
2 2 7 12 
3 3 8 13 
4 4 9 14 

Teraz użyj merge i within z ifelse:

> within(merge(d1, d2, by="x"), {b <- ifelse(is.na(b.x),b.y,b.x); b.x <- NULL; b.y <- NULL}) 
    x a c b 
1 1 2 11 3 
2 2 3 12 4 
3 3 4 13 5 
4 4 5 14 9 
+2

To jest fajne, ale to działa tylko wtedy, gdy wiesz już, które nazwy kolumn będą dostępne zarówno w dataframes, nie jest to przypadek, o którym mowa OP (zobacz wyjaśnienie commit w [42-s odpowiedzi] (https://stackoverflow.com/a/16042494/210945)). – naught101

10

Aktualizacja za pomocą v1.9.6 z data.table za on= argument (który pozwala na AdHoc dołącza:

setDT(df1)[df2, `:=`(Col2 = ifelse(is.na(Col2), i.Col2, Col2), 
        Col3 = i.Col3), on="Date"][] 

Oto rozwiązanie data.table Upewnij się, że i df2 „s Date kolumna df1 jest. czynnik o pożądanych poziomach (dla zamawiania)

require(data.table) 
dt1 <- data.table(df1, key="Date") 
dt2 <- data.table(df2, key="Date") 
# Col2 refers to the Col2 of dt1 and i.col2 refers to that of dt2 
dt1[dt2, `:=`(Col3 = Col3, Col1 = Col1, 
     Col2 = ifelse(is.na(Col2), i.Col2, Col2))] 

# the result is stored in dt1 
> dt1 
#  Date Col1 Col2 Col3 
# 1: jan 2 1 10 
# 2: feb 4 2 20 
# 3: march 6 3 30 
# 4: april 8 6 40 
1

Oto rozwiązanie dplyr. Kredyt dla @docendo discimus

df1 <- data.frame(y = c("A", "B", "C", "D"), x1 = c(1,2,NA, 4)) 

    y x1 
1 A 1 
2 B 2 
3 C NA 
4 D 4 

df2 <- data.frame(y = c("A", "B", "C"), x1 = c(5, 6, 7)) 

    y x1 
1 A 5 
2 B 6 
3 C 7 

dplyr

left_join(df1, df2, by="y") %>% 
transmute(y, x1 = ifelse(is.na(x1.y), x1.x, x1.y)) 

    y x1 
1 A 5 
2 B 6 
3 C 7