2013-02-06 15 views
14

Mam dwie tabele danych, DT1 i DT2:Aktualizacja podzbiorem data.table podstawie dołączyć

set.seed(1) 
DT1<-data.table(id1=rep(1:3,2),id2=sample(letters,6), v1=rnorm(6), key="id2") 
DT1 
## id1 id2   v1 
## 1: 2 e 0.7383247 
## 2: 1 g 1.5952808 
## 3: 2 j 0.3295078 
## 4: 3 n -0.8204684 
## 5: 3 s 0.5757814 
## 6: 1 u 0.4874291 

DT2<-data.table(id2=c("n","u"), v1=0, key="id2") 
DT2 
## id2 v1 
## 1: n 0 
## 2: u 0 

Chciałbym zaktualizować dt1 na podstawie sprzężenia z DT2, ale tylko do pewnego podzbioru DT1. Na przykład, dla DT1[id1==3], spodziewam wartość v1 w rzędzie 4, aby być na bieżąco, jak w następujący wynik:

DT1 
## id1 id2   v1 
## 1: 2 e 0.7383247 
## 2: 1 g 1.5952808 
## 3: 2 j 0.3295078 
## 4: 3 n   0 
## 5: 3 s 0.5757814 
## 6: 1 u 0.4874291 

wiem jak zaktualizować tabelę (za pomocą operatora := przyporządkowania), jak dołączyć tabele (DT1[DT2]) oraz sposób podziału tabeli (DT1[id1==3]). Jednak nie jestem pewien, jak wykonać wszystkie trzy naraz.

EDYTOWANIE: Należy zauważyć, że oryginalny przykład próbuje tylko zaktualizować jedną kolumnę, ale moje rzeczywiste dane wymagają aktualizacji wielu kolumn. Rozważyć dodatkowe scenariusze w DT1b i DT2b:

set.seed(2) 
DT1b<-DT1[,v2:=rnorm(6)] # Copy DT1 and add a new column 
setkey(DT1b,id2) 
DT1b 
## id1 id2   v1   v2 
## 1: 2 e 0.7383247 -0.89691455 
## 2: 1 g 1.5952808 0.18484918 
## 3: 2 j 0.3295078 1.58784533 
## 4: 3 n -0.8204684 -1.13037567 
## 5: 3 s 0.5757814 -0.08025176 
## 6: 1 u 0.4874291 0.13242028 

DT2b<-rbindlist(list(DT2,data.table(id2="e",v1=0))) # Copy DT2 and add a new row 
DT2b[,v2:=-1] # Add a new column to DT2b 
setkey(DT2b,id2) 
DT2b 
## id2 v1 v2 
## 1: e 0 -1 
## 2: n 0 -1 
## 3: u 0 -1 

podstawie pomocnych odpowiedzi z @nmel i @BlueMagister, wpadłem na to rozwiązanie dla zaktualizowanego scenariusz:

DT1b[DT2b[DT1b[id1 %in% c(1,2)],nomatch=0],c("v1","v2"):=list(i.v1,i.v2)] 
DT1b 
## id1 id2   v1   v2 
## 1: 2 e 0.0000000 -1.00000000 
## 2: 1 g 1.5952808 0.18484918 
## 3: 2 j 0.3295078 1.58784533 
## 4: 3 n -0.8204684 -1.13037567 
## 5: 3 s 0.5757814 -0.08025176 
## 6: 1 u 0.0000000 -1.00000000 

Odpowiedz

13

Najprostszym sposobem ja może myśleć również o kluczowaniu przez id1. np

setkey(DT1, id2,id1) 
DT2[, id1 := 3] 
setkey(DT2, id2, id1) 

# use i.v1 to reference v1 from the i component 
DT1[DT2, v1 := i.v1 ] 


DT1 
    id1 id2  v1 
1: 2 e 0.7383247 
2: 1 g 1.5952808 
3: 2 j 0.3295078 
4: 3 n 0.0000000 
5: 3 s 0.5757814 
6: 1 u 0.4874291 
+0

Dziękuję za odpowiedź i inne uwagi, @mnel. To podejście działa dla oryginalnego przykładu i może być łatwo rozszerzone dla przypadku, gdy wiele kolumn wymaga aktualizacji, a nie tylko jednego. Ale jeśli podzbiór jest bardziej skomplikowany (np. 'Id1 == 3 | id1 == 2', zobacz zaktualizowane pytanie), wydaje się, że dodanie klucza id1 do DT2 staje się bardziej skomplikowane. – dnlbrky

7

Jest to podobne do mnel „s solution ale używa ifelse zamiast drugiego klucza.

DT1[DT2, v1 := ifelse(id1==3, i.v1, v1),nomatch=0] 
+0

Dzięki za odpowiedź @BlueMagister. To na pewno działa na przykład. Jak zmodyfikowałbyś swoją odpowiedź, gdyby tabele wymagały aktualizacji wielu kolumn, a nie tylko jednej? Rozszerzając go do dwóch kolumn, myślę, że środkowa część twojego rozwiązania byłaby podobna do 'c (" v1 "," v2 "): = lista (ifelse (id1 == 3, i.v1, v1), ifelse (id1 == 3, i.v2, v2)) '. – dnlbrky

+2

@dnlbrky, problemem z wieloma instrukcjami ifelse jest to, że musisz wielokrotnie oceniać 'id1 == 3' i' ifelse'. Jeśli podzestawujesz jako część klucza (wyszukiwanie binarne), będzie on znacznie wydajniejszy. – mnel

+0

Tak, @mnel, powinienem wyraźnie powiedzieć, że moja próba rozszerzenia rozwiązania z @ BlueMagister nie była skuteczna i że łowiłem coś lepszego niż moja próba. Podoba mi się, że to podejście @BlueMagister jest elastyczne pod względem dodawania warunków do podzbioru (na przykład "id1 == 3 | id == 2"). Zaktualizowałem moje pytanie, aby uwzględnić scenariusz wielu kolumn i warunków wielu podzbiorów. – dnlbrky