2015-11-13 7 views
8

Mam dwie poniższe tabele:R - Tworzenie nowej zmiennej, gdzie każda obserwacja zależy od innej tabeli i innych zmiennych w ramce danych

df <- data.frame(eth = c("A","B","B","A","C"),ZIP1 = c(1,1,2,3,5)) 
Inc <- data.frame(ZIP2 = c(1,2,3,4,5,6,7),A = c(56,98,43,4,90,19,59), B = c(49,10,69,30,10,4,95),C = c(69,2,59,8,17,84,30)) 

eth ZIP1   ZIP2 A B C 
A  1   1  56 49 69 
B  1   2  98 10 2 
B  2   3  43 69 59 
A  3   4  4 30 8 
C  5   5  90 10 17 
        6  19 4 84 
        7  59 95 39 

Chciałbym utworzyć zmienną Inc w ramce danych df gdzie dla każdej obserwacji wartość jest przecięciem punktu obserwacji eth i ZIP. W moim przykładzie będzie to prowadzić do:

eth ZIP1 Inc   
    A  1 56 
    B  1 49 
    B  2 10 
    A  3 43 
    C  5 17 

pętli lub brute force dość mógł go rozwiązać, ale na to potrzeba czasu na moim zbiorze, szukam bardziej subtelny sposób może użyciu data.table. Wydaje mi się, że jest to bardzo standardowe pytanie i przepraszam, jeśli tak jest, moja niezdolność do sformułowania dokładnego tytułu tego problemu (jak być może zauważyliście ...) jest może dlatego nie znalazłem żadnego podobnego pytania w wyszukiwaniu na forum ..

Dzięki!

Odpowiedz

5

Co na ten temat?

library(reshape2) 
merge(df, melt(Inc, id="ZIP2"), by.x = c("ZIP1", "eth"), by.y = c("ZIP2", "variable")) 
    ZIP1 eth value 
1 1 A 56 
2 1 B 49 
3 2 B 10 
4 3 A 43 
5 5 C 17 
+0

Dobrze, dziękuję! Nadal jestem nowicjuszem i nie myślę wystarczająco mocno, aby korzystać z tych funkcji :) Po prostu nastąpiła awaria, mówiąc, że zmienne dla x i y muszą odpowiadać. Zmieniłem nazwy dla nich tak, aby były takie same i nadal się rozbijali, wtedy użyłem prostego "by" zamiast "by.x by.y" i zadziałało. – Yurienu

6

Oczywiście, można to zrobić w data.table:

library(data.table) 
setDT(df) 

df[ melt(Inc, id.var="ZIP2", variable.name="eth", value.name="Inc"), 
    Inc := i.Inc 
, on=c(ZIP1 = "ZIP2","eth") ] 

Składnia tego "scalić-Assign" operacji jest X[i, Xcol := expression, on=merge_cols].

Możesz samodzielnie uruchomić część i = melt(Inc, id.var="ZIP", variable.name="eth", value.name="Inc"), aby zobaczyć, jak działa. Wewnątrz scalania kolumny z i można odnosić do prefiksów i.*.


przemian ...

setDT(df) 
setDT(Inc) 
df[, Inc := Inc[.(ZIP1), eth, on="ZIP2", with=FALSE], by=eth] 

ten zbudowany jest na podobnym pomyśle. The package vignettes to dobre miejsce do rozpoczęcia tego typu składni.

+0

Dzięki. Spróbuję rzeczywiście zrozumieć logikę. Wydaje się jednak, że nie działa, ale to moje złe: zaktualizowałem post, aby oddzielić ZIP pierwszej i drugiej tabeli. Który powinienem wybrać w twojej formule? Błąd: "nieużywany argument (on = c (" ZIP1 "," eth "))" – Yurienu

+0

@Julien OK, zaktualizowałem dla tego przypadku. Nie jestem pewien, czy działa on w data.table 1.9.6 (używam wersji devel). Nieużywane argumenty zostaną naprawione, jeśli najpierw uruchomisz linię 'setDT'. – Frank

+1

Dzięki za referencje będzie to dla mnie bardzo przydatne! Twoje rozwiązanie nadal ma tę samą awarię, nawet przy użyciu setDT. Ale będę pracował nad lepszym zrozumieniem scalania przy użyciu data.tables, które i tak przyda mi się na dłuższą metę :) – Yurienu

2

moje rozwiązanie (które być może wydaje się niezgrabny)

for (i in 1:length(df$eth)) { 
    df$Inc[i] <- Inc[as.character(df$eth[i])][df$ZIP[i],] 
} 
5

Inna opcja:

library(dplyr) 
library(tidyr) 
Inc %>% 
    gather(eth, value, -ZIP2) %>% 
    left_join(df, ., by = c("eth", "ZIP1" = "ZIP2")) 
6

Możemy użyć row/column indeksowanie

df$Inc <- Inc[cbind(match(df$ZIP1, Inc$ZIP2), match(df$eth, colnames(Inc)))] 

df 
# eth ZIP1 Inc 
#1 A 1 56 
#2 B 1 49 
#3 B 2 10 
#4 A 3 43 
#5 C 5 17 
Powiązane problemy