2017-04-20 23 views
2

我需要對大型(數百萬行)數據集執行批量重新映射。data.table映射

的樣本數據:

DT = data.table(yr = sample(3)+2000, a1 = sample(12), a2 = sample(12))[order(yr)] 
DT 
     yr a1 a2 
1: 2001 2 8 
2: 2001 3 12 
3: 2001 10 4 
4: 2001 9 6 
5: 2002 7 7 
6: 2002 11 3 
7: 2002 5 2 
8: 2002 1 11 
9: 2003 8 5 
10: 2003 12 1 
11: 2003 6 9 
12: 2003 4 10 

DTmap = data.table(a1 = 1:12, b=10001:10012) 
DTmap 
    a1  b 
1: 1 10001 
2: 2 10002 
3: 3 10003 
4: 4 10004 
5: 5 10005 
6: 6 10006 
7: 7 10007 
8: 8 10008 
9: 9 10009 
10: 10 10010 
11: 11 10011 
12: 12 10012 

我想列A1和A2 DT與DTmap映射映射。忽略它們只有10000個不同的事實 - 這是樣本數據的人爲因素,可以輕鬆檢查結果的準確性。 我可以用序列做到這一點的加入是這樣的:

setkey(DT,a1) 
setkey(DTmap,a1) 
DT.merge1 <- DT[DTmap] 

setkey(DT.merge1,a2) 
setnames(DTmap,c("a2","b")) 
setkey(DTmap,a2) 

DT.merge2 <- DT.merge1[DTmap] 
DT.merge2 
     yr a1 a2  b i.b 
1: 2003 12 1 10012 10001 
2: 2002 5 2 10005 10002 
3: 2002 11 3 10011 10003 
4: 2001 10 4 10010 10004 
5: 2003 8 5 10008 10005 
6: 2001 9 6 10009 10006 
7: 2002 7 7 10007 10007 
8: 2001 2 8 10002 10008 
9: 2003 6 9 10006 10009 
10: 2003 4 10 10004 10010 
11: 2002 1 11 10001 10011 
12: 2001 3 12 10003 10012 

DT.merge2[, `:=` (a1 = NULL, a2 = NULL)] 
setnames(DT.merge2,c("year","b1","b2")) 
DT.merge2 
    year b1 b2 
1: 2003 10012 10001 
2: 2002 10005 10002 
3: 2002 10011 10003 
4: 2001 10010 10004 
5: 2003 10008 10005 
6: 2001 10009 10006 
7: 2002 10007 10007 
8: 2001 10002 10008 
9: 2003 10006 10009 
10: 2003 10004 10010 
11: 2002 10001 10011 
12: 2001 10003 10012 

好像會有一種方法來使用()的data.table語法什麼的範圍內做到這一點,但我不能圖出來。我是一個非常新的R編碼器,但有很多其他語言的經驗。 這可能嗎?以上是相對較快的,但有很多種類的編碼(通過setkey)。看起來,使用by()與索引然後通過引用更新這些值會更快。

回答

2

你可以使用match爲:

DT[, `:=` (b1 = DTmap$b[match(a1,DTmap$a1)], b2 = DTmap$b[match(a2,DTmap$a1)])] 

或者爲@Frank建議:

DT[DTmap, on = .(a1), b1 := i.b][DTmap, on = .(a2=a1), b2 := i.b] 

用這兩種方法你:

> DT 
     yr a1 a2 b1 b2 
1: 2001 7 8 10007 10008 
2: 2001 4 11 10004 10011 
3: 2001 6 12 10006 10012 
4: 2001 8 2 10008 10002 
5: 2002 11 9 10011 10009 
6: 2002 9 5 10009 10005 
7: 2002 10 4 10010 10004 
8: 2002 2 10 10002 10010 
9: 2003 12 7 10012 10007 
10: 2003 3 1 10003 10001 
11: 2003 5 3 10005 10003 
12: 2003 1 6 10001 10006 

特別是在多列連接時,第二種方法要容易得多。


要刪除a1a2列,只需添加[, c('a1','a2') := NULL],如:

DT[, `:=` (b1 = DTmap$b[match(a1,DTmap$a1)], b2 = DTmap$b[match(a2,DTmap$a1)]) 
    ][, c('a1','a2') := NULL] 

然後你會得到:

> DT 
     yr b1 b2 
1: 2001 10007 10008 
2: 2001 10004 10011 
3: 2001 10006 10012 
4: 2001 10008 10002 
5: 2002 10011 10009 
6: 2002 10009 10005 
7: 2002 10010 10004 
8: 2002 10002 10010 
9: 2003 10012 10007 
10: 2003 10003 10001 
11: 2003 10005 10003 
12: 2003 10001 10006 

在一個側面說明:當提供帶有隨機值生成器的樣本數據(如samplernorm)最好使用set.seed()

二手數據:

set.seed(2004) 
DT = data.table(yr = sample(3)+2000, a1 = sample(12), a2 = sample(12))[order(yr)] 
DTmap = data.table(a1 = 1:12, b=10001:10012) 
+0

完美。正是我在找什麼。 –

+0

明白了。下次我將使用set.seed()。在第一次加入@ Frank的解決方案時,爲什麼要使用i.b?它適用於那裏。第二次,我明白,否則它會是一個重複的列。 –

+0

@JesseBlocher'i'前綴是指'i'中的列;基本上'i'是指定要用索引向量或引用data.table選擇哪些行([請參閱此處](https://rawgit.com/wiki/Rdatatable/data.table/vignettes/datatable-intro .html)瞭解更多信息「我」的含義) – Jaap