我需要对大型(数百万行)数据集进行批量重新映射。
示例数据:
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
我想将 DT 中的 a1 和 a2 列与 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 语法中使用 by() 或其他方法来做到这一点,但我无法弄清楚。我是一个相当新的 R 程序员,但在其他语言方面拥有丰富的经验。 这可能吗?上面的代码相对较快,但是有多种编码(通过 setkey)。看起来,使用 by() 和索引然后通过引用更新这些值会快得多。
最佳答案
您可以使用 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
特别是在连接多个列时,第二种方法要容易得多。
要删除 a1
和 a2
列,只需添加 [, 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
旁注:当使用随机值生成器(例如 sample
或 rnorm
)提供样本数据时,最好使用 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)
关于r - 数据表映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43523719/