2016-08-28 33 views
7

Wczoraj dałem tę odpowiedź: Matching Data Tables by five columns to change a value in another column.Czy można użyć idiomu indeksu sprzężenia danych.table, aby wykonać lewe połączenie i przypisać NA w niepasujących wierszach od I do X?

W komentarzach OP zapytał, czy moglibyśmy skutecznie osiągnąć lewe połączenie dwóch stołów, a tym samym uzyskać NA, które spowodowałyby przypisanie prawej tabeli do lewej tabeli. Wydaje mi się, że data.table nie zapewnia żadnych środków.

Oto przykład przypadek użyłem w tym pytaniu:

set.seed(1L); 
dt1 <- data.table(id=1:12,expand.grid(V1=1:3,V2=1:4),blah1=rnorm(12L)); 
dt2 <- data.table(id=13:18,expand.grid(V1=1:2,V2=1:3),blah2=rnorm(6L)); 
dt1; 
##  id V1 V2  blah1 
## 1: 1 1 1 -0.6264538 
## 2: 2 2 1 0.1836433 
## 3: 3 3 1 -0.8356286 
## 4: 4 1 2 1.5952808 
## 5: 5 2 2 0.3295078 
## 6: 6 3 2 -0.8204684 
## 7: 7 1 3 0.4874291 
## 8: 8 2 3 0.7383247 
## 9: 9 3 3 0.5757814 
## 10: 10 1 4 -0.3053884 
## 11: 11 2 4 1.5117812 
## 12: 12 3 4 0.3898432 
dt2; 
## id V1 V2  blah2 
## 1: 13 1 1 -0.62124058 
## 2: 14 2 1 -2.21469989 
## 3: 15 1 2 1.12493092 
## 4: 16 2 2 -0.04493361 
## 5: 17 1 3 -0.01619026 
## 6: 18 2 3 0.94383621 
key <- paste0('V',1:2); 

A oto rozwiązanie dałem który robi nie dostać NAS dla niedopasowanych wierszy:

dt1[dt2,on=key,id:=i.id]; 
dt1; 
##  id V1 V2  blah1 
## 1: 13 1 1 -0.6264538 
## 2: 14 2 1 0.1836433 
## 3: 3 3 1 -0.8356286 
## 4: 15 1 2 1.5952808 
## 5: 16 2 2 0.3295078 
## 6: 6 3 2 -0.8204684 
## 7: 17 1 3 0.4874291 
## 8: 18 2 3 0.7383247 
## 9: 9 3 3 0.5757814 
## 10: 10 1 4 -0.3053884 
## 11: 11 2 4 1.5117812 
## 12: 12 3 4 0.3898432 

czego potrzebujemy jest dla wartości id 12 i mniejszych, które pozostają w dt1, które mają być zastąpione przez NA (, nie, ponieważ mają 12 lub mniej, i nie ponieważ te wartości id brakuje dt2, ale ponieważ dołączyć na key kolumn, a mianowicie V1 i V2, nie powoduje w meczu dla tych wierszy w dt1 przeciwko dt2).

Jak już wspomniałem w komentarzach do tego pytania, obejście problemu polega na przeniesieniu dt1$id do wszystkich NA, a następnie uruchomieniu przypisania indeksu. Stąd, to oczekiwany wynik:

dt1$id <- NA; 
dt1[dt2,on=key,id:=i.id]; 
dt1; 
##  id V1 V2  blah1 
## 1: 13 1 1 -0.6264538 
## 2: 14 2 1 0.1836433 
## 3: NA 3 1 -0.8356286 
## 4: 15 1 2 1.5952808 
## 5: 16 2 2 0.3295078 
## 6: NA 3 2 -0.8204684 
## 7: 17 1 3 0.4874291 
## 8: 18 2 3 0.7383247 
## 9: NA 3 3 0.5757814 
## 10: NA 1 4 -0.3053884 
## 11: NA 2 4 1.5117812 
## 12: NA 3 4 0.3898432 

myślę, że obejście jest ok, ale nie jestem pewien, dlaczego data.table nie wydają się być zdolne do tej funkcji w jednym ujęciu z indeksem dołącz -przypisanie operacji. Poniżej przedstawiono trzy martwe końce ja zbadałem:

1:nomatch

data.table zapewnia nomatch argument, który wygląda trochę jak all, all.x i all.y argumentów merge(). Jest to w rzeczywistości bardzo ograniczony argument; pozwala jedynie na zmianę z łączenia prawego (nomatch=NA, domyślne) na sprzężenie wewnętrzne (nomatch=0). Nie możemy osiągnąć lewostronnego połączenia z nim.

2: klapki dt1 i dt2

Od dt1[dt2] jest prawo dołączyć, możemy po prostu odwrócić go, co oznacza, dt2[dt1], dla uzyskania odpowiadającego lewo przyłączyć.

To nie zadziała albo dlatego musimy użyć składni przypisania := w miejscu w j argumentu przypisać do dt1 i pod przewracanej rozmowy będziemy zamiast być przypisanie dt2. Próbowałem przypisać do i.id pod odwróconą komendą, ale nie wpłynęło to na oryginalny kod dt1.

3: użycie merge.data.table()

Możemy zadzwonić merge.data.table() z all.x=T argument do osiągnięcia LEFT JOIN. Problem polega obecnie na tym, że merge.data.table() nie ma argumentu j i po prostu nie zapewnia możliwości przypisania w miejscu kolumny lewej (lub prawej) tabeli.


Czy jest możliwe wykonanie tej operacji w ogóle przy użyciu data.table? A jeśli tak, jaki jest najlepszy sposób na zrobienie tego?

Odpowiedz

8

AFAIU po prostu chcesz wyszukać kolumnę id od dt2 do dt1. Oryginalna zmienna id w kodzie dt1 wydaje się nie mieć związku z całym procesem podczas dołączania do V1,V2, a użytkownik nie chce mieć wartości wyniku w postaci dt1$id. Więc technicznie poprawnym sposobem rozwiązania tego problemu jest w ogóle nie używanie tej kolumny.

set.seed(1) 
library(data.table) 
dt1 <- data.table(id=1:12,expand.grid(V1=1:3,V2=1:4),blah1=rnorm(12L)); 
dt2 <- data.table(id=13:18,expand.grid(V1=1:2,V2=1:3),blah2=rnorm(6L)); 
on = paste0("V",1:2) # I rename to `on` to not mask `key` function 
dt1[,id:=NULL 
    ][dt2,on=on,id:=i.id 
     ][] 
# V1 V2  blah1 id 
# 1: 1 1 -0.6264538 13 
# 2: 2 1 0.1836433 14 
# 3: 3 1 -0.8356286 NA 
# 4: 1 2 1.5952808 15 
# 5: 2 2 0.3295078 16 
# 6: 3 2 -0.8204684 NA 
# 7: 1 3 0.4874291 17 
# 8: 2 3 0.7383247 18 
# 9: 3 3 0.5757814 NA 
#10: 1 4 -0.3053884 NA 
#11: 2 4 1.5117812 NA 
#12: 3 4 0.3898432 NA 

Oprócz pytanie ...
- nie trzeba używać ; na końcu linii, jeśli istnieje tylko pojedynczy wyraz ocenić
- użyj dt1[, id := NA_integer_] zamiast dt1$id <- NA
- używaj set.seed, podając kod z rnorm i innymi połączeniami losowymi

+1

Niewielkie: jeśli chcesz, aby kolejność kolumn była zabezpieczona ved, użyj 'id: = NA' zamiast' id: = NULL'. – Arun

+1

Doskonała odpowiedź. Nigdy nie przyszło mi do głowy, że oryginalna kolumna 'id' w' dt1' jest nieistotna dla konstrukcji nowej kolumny 'id'. Przypuszczam, że może nigdy nie być korzyścią z używania lewostronnego z idiomem przypisywania indeksów, ponieważ nie pasujące wiersze powinny być pozostawione same sobie (osiągalne przy połączeniu wewnętrznym/prawym) lub ich wartości zastępcze mogą być określane niezależnie od wcześniejszych wartości, co jest możliwe do osiągnięcia poprzez całkowitą przebudowę kolumny (w wyniku której powstają węzły NA) lub przypisanie pożądanej wartości zastępczej przed operacją przypisania indeksu. – bgoldst