R 数据表映射

R 数据表映射,r,mapping,data.table,R,Mapping,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

我需要在一个大型(数百万行)数据集上进行批量重新映射

样本数据:

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
我想用DTmap中的映射来映射DT中的a1列和a2列。忽略它们只是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
设置键(DT,a1) 设置键(DTmap,a1)
DT.merge1您可以使用
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)

完美的正是我想要的,明白了。下次我将使用set.seed()。在第一次加入@Frank的解决方案时,为什么要使用i.b?它只与b一起工作。第二次,我明白了,因为否则它将是一个重复的列。@JesseBlocher
I.
前缀指的是
I
中的列;基本上,
i
用于指定要使用索引向量或参考数据表选择哪些行(有关
i
的更多信息,请参阅其含义)