2013-05-21 34 views
26

Zbieram dane z 4 df i chcę je scalić przez rownames. Szukam skutecznego sposobu, aby to zrobić. To jest uproszczona wersja danych, które mam.Scalanie więcej niż 2 ramek danych w R przez rownames

df1   <- data.frame(N= sample(seq(9, 27, 0.5), 40, replace= T), 
          P= sample(seq(0.3, 4, 0.1), 40, replace= T), 
          C= sample(seq(400, 500, 1), 40, replace= T)) 
df2   <- data.frame(origin= sample(c("A", "B", "C", "D", "E"), 40, 
              replace= T), 
          foo1= sample(c(T, F), 40, replace= T), 
          X= sample(seq(145600, 148300, 100), 40, replace= T), 
          Y= sample(seq(349800, 398600, 100), 40, replace= T)) 
df3   <- matrix(sample(seq(0, 1, 0.01), 40), 40, 100) 
df4   <- matrix(sample(seq(0, 1, 0.01), 40), 40, 100) 
rownames(df1) <- paste("P", sprintf("%02d", c(1:40)), sep= "") 
rownames(df2) <- rownames(df1) 
rownames(df3) <- rownames(df1) 
rownames(df4) <- rownames(df1) 

To co bym normalnie zrobić:

# merge df1 and df2 
dat   <- merge(df1, df2, by= "row.names", all.x= F, all.y= F) #merge 
rownames(dat) <- dat$Row.names #reset rownames 
dat$Row.names <- NULL #remove added rownames col 

# merge dat and df3 
dat   <- merge(dat, df3, by= "row.names", all.x= F, all.y= F) #merge 
rownames(dat) <- dat$Row.names #reset rownames 
dat$Row.names <- NULL #remove added rownames col 

# merge dat and df4 
dat   <- merge(dat, df4, by= "row.names", all.x= F, all.y= F) #merge 
rownames(dat) <- dat$Row.names #reset rownames 
dat$Row.names <- NULL #remove added rownames col 

Jak widać, to wymaga dużo kodu. Moje pytanie brzmi, czy ten sam rezultat można osiągnąć za pomocą prostszych środków. Próbowałem (bez powodzenia): AKTUALIZACJA: działa to teraz!

MyMerge  <- function(x, y){ 
    df   <- merge(x, y, by= "row.names", all.x= F, all.y= F) 
    rownames(df) <- df$Row.names 
    df$Row.names <- NULL 
    return(df) 
} 
dat   <- Reduce(MyMerge, list(df1, df2, df3, df4)) 

Dzięki z góry za wszelkie sugestie

+1

Co dokładnie masz na myśli przez 'bez success'? Dokładniej opisz błędy, jeszcze lepiej stwórz powtarzalny przykład: –

+0

1.) Jeśli nazwy rzędów są tak ważne dla twojej struktury danych że połączysz się z nimi, dlaczego po prostu nie poświęcisz kolumny "data.frame" na to? Który pozwala zaoszczędzić większość kodu. 2.) Nawet jeśli je zachowasz, możesz zaoszczędzić sporo kodu, zobacz parametry "scal" 'by.x' i' by.y' 3.) Usunięcie kolumny z danych.frame można uzyskać za pomocą 'df $ Row.Names <- NULL' 4.) Podejście "Reduce" powinno zadziałać, zastanawiam się także, dlaczego to się nie uda. – Beasterfield

+0

Podałem kilka przykładowych danych. Odkryłem także, że sugerowane podejście z działa mimo wszystko. Problem polegał na tym, że chciałem scalić pojedynczą kolumnę z pliku df, usuwając w ten sposób informacje rowname. – HDR

Odpowiedz

4

Trzy linie kodu daje dokładnie ten sam wynik:

dat2 <- cbind(df1, df2, df3, df4) 
colnames(dat2)[-(1:7)] <- paste(paste('V', rep(1:100, 2),sep = ''), 
          rep(c('x', 'y'), each = 100), sep = c('.')) 
all.equal(dat,dat2)  

Ah widzę, teraz rozumiem dlaczego otrzymujesz tyle ból. Używanie starej pętli for na pewno wystarczy. Może są nawet bardziej inteligentne rozwiązania

rn <- rownames(df1) 
l <- list(df1, df2, df3, df4) 
dat <- l[[1]] 
for(i in 2:length(l)) { 
    dat <- merge(dat, l[[i]], by= "row.names", all.x= F, all.y= F) [,-1] 
    rownames(dat) <- rn 
} 
+0

Cześć, dziękuję za odpowiedź. Widzę, jak to działa. Jednakże, i przyznaję, że nie wyjaśniłem tego w moich przykładowych danych, chcę, żeby to działało także wtedy, gdy 'rownames' są niepodobne. Tak więc w przykładzie rownames są równe, ale przetwarzanie powinno nadal działać, gdy wiersze są tasowane, lub np. 'df2' ma więcej lub mniej wierszy. Właśnie dlatego wybrałem opcję "scalania". – HDR

33

join_all z plyr prawdopodobnie będzie robić co chcesz. Ale wszystkie one muszą być ramki danych i rownames są dodawane jako kolumny

require(plyr) 

df3 <- data.frame(df3) 
df4 <- data.frame(df4) 

df1$rn <- rownames(df1) 
df2$rn <- rownames(df2) 
df3$rn <- rownames(df3) 
df4$rn <- rownames(df4) 

df <- join_all(list(df1,df2,df3,df4), by = 'rn', type = 'full') 

type argument powinien pomóc nawet jeśli rownames różnić i nie pasują Jeśli nie chcesz rownames:

df$rn <- NULL 
9

Edytując twoją funkcję, wymyśliłem funkcję, która pozwala scalić więcej ramek danych przez konkretny klucz kolumny (nazwa kolumny). Uzyskaną ramka danych zawiera wszystkie zmienną połączonych ramek danych (jeśli chcesz zachować tylko zmienne wspólne (z wyłączeniem NA, przeznaczenie: all.x= FALSE, all.y= FALSE)

MyMerge <- function(x, y){ 
    df <- merge(x, y, by= "name of the common column", all.x= TRUE, all.y= TRUE) 
    return(df) 
} 
new.df <- Reduce(MyMerge, list(df1, df2, df3, df4)) 
+1

Fajna funkcja, czy mimo to ta funkcja może zmieniać nazwy kolumn i podawać nazwy kolumn w odróżnieniu od wspólnych nazw kolumn? – Chirag

+0

Po scaleniu dwóch ramek danych zwykle używam funkcji "fix()", która pozwala na edycję bazy danych - dlatego możesz także zmienić nazwy kolumn. –

3

czekałem dla tej samej funkcji Po wypróbowaniu kilku. . tutejszych opcji i innych gdzie indziej najłatwiej było dla mnie:

cbind.data.frame (DF1, DF2, DF3, DF4 ....)

+0

To będzie działać tylko wtedy, gdy wiersze będą w tej samej kolejności w każdej ramce danych. – Matt

Powiązane problemy