2015-08-31 40 views
2

我有一个“字典”表是这样的:做这个连接/合并的“数据表”方式是什么?

dict <- data.table(
    Nickname = c("Abby", "Ben", "Chris", "Dan", "Ed"), 
    Name = c("Abigail", "Benjamin", "Christopher", "Daniel", "Edward") 
) 
dict 
# Nickname  Name 
# 1:  Abby  Abigail 
# 2:  Ben Benjamin 
# 3: Chris Christopher 
# 4:  Dan  Daniel 
# 5:  Ed  Edward 

和一个“数据”表是这样的:

dat <- data.table(
    Friend1 = c("Abby", "Ben", "Ben", "Chris"), 
    Friend2 = c("Ben", "Ed", NA, "Ed"), 
    Friend3 = c("Ed", NA, NA, "Dan"), 
    Friend4 = c("Dan", NA, NA, NA) 
) 
dat 
# Friend1 Friend2 Friend3 Friend4 
# 1: Abby  Ben  Ed  Dan 
# 2:  Ben  Ed  NA  NA 
# 3:  Ben  NA  NA  NA 
# 4: Chris  Ed  Dan  NA 

我想产生一个data.table看起来像这样

result <- data.table(
    Friend1.Nickname = c("Abby", "Ben", "Ben", "Chris"), 
    Friend1.Name = c("Abigail", "Benjamin", "Benjamin", "Christopher"), 
    Friend2.Nickname = c("Ben", "Ed", NA, "Ed"), 
    Friend2.Name = c("Benjamin", "Edward", NA, "Edward"), 
    Friend3.Nickname = c("Ed", NA, NA, "Dan"), 
    Friend3.Name = c("Edward", NA, NA, "Daniel"), 
    Friend4.Nickname = c("Dan", NA, NA, NA), 
    Friend4.Name = c("Daniel", NA, NA, NA) 
) 
result 
# sorry, word wrapping makes this too annoying to copy 

这就是我想到的解决方案:

friend_vars <- paste0("Friend", 1:4) 
friend_nicks <- paste0(friend_vars, ".Nickname") 
friend_names <- paste0(friend_vars, ".Name") 
setnames(dat, friend_vars, friend_nicks) 
for (i in 1:4) { 
    dat[, friend_names[i] := dict$Name[match(dat[[friend_nicks[i]]], dict$Nickname)], with = FALSE] 
} 

有没有更“数据表式”的方式来做到这一点?我确信它很好,很高效,但是阅读起来很难看,部分来自data.table的内部任务,我不觉得我正在充分利用这个软件包的优势。

我也不是一个非常强大的SQL用户,我不太习惯加入术语。我有一种感觉,Data.table - left outer join on multiple tables可能在这里有用,但我不知道如何将它应用于我的情况。

回答

6

使用data.table 1.9.5

for (nm in names(dat)) { 
    on = setattr("Nickname", 'names', nm) 
    dat[dict, paste0(nm, ".Name") := i.Name, on=on] 
} 

我们可以加入使用on=,而不是设置键。现在您可以使用setcolorder()重新排列名称。

我避免重塑数据,除非绝对必要。这是更新的地方,而加入的地方非常方便。而现在与on=的论点,我无法拒绝张贴答案:-)。

+0

我为此升级到了1.9.5,我很高兴我做到了。 'on ='语法很棒!顺便说一句,如果你事先知道你将要从宽格式转换到长格式,一般来说,融合第一,融化第二,还是先融化再融合,效率会更高? – shadowtalker

+0

太棒了!我的猜测是融化+加入会更快(因为你只需要加入一次)。并且熔化通常是在速度方面廉价的操作(如果正确实施)。 – Arun

+1

另请参见:其中是否记录了'i。*'语法?我无法在'[.data.table'或':=' – shadowtalker

2

我没有拿出瓦特/那完全匹配您的result的解决方案,但您可能能够工作瓦特/是这样的:

dat[, id := .I] 
dat.m <- melt(dat, id.vars='id', variable.name='Friend', value.name='Nickname') 
setkey(dict, Nickname) 
dat.m[, Name := dict[Nickname, Name]] 
> dat.m 
    id Friend Nickname  Name 
1: 1 Friend1  Abby  Abigail 
2: 2 Friend1  Ben Benjamin 
3: 3 Friend1  Ben Benjamin 
4: 4 Friend1 Chris Christopher 
5: 1 Friend2  Ben Benjamin 
6: 2 Friend2  Ed  Edward 
7: 3 Friend2  NA   NA 
8: 4 Friend2  Ed  Edward 
9: 1 Friend3  Ed  Edward 
10: 2 Friend3  NA   NA 
11: 3 Friend3  NA   NA 
12: 4 Friend3  Dan  Daniel 
13: 1 Friend4  Dan  Daniel 
14: 2 Friend4  NA   NA 
15: 3 Friend4  NA   NA 
16: 4 Friend4  NA   NA 

变量id只是一个占位符,所以我可以融化DT。

+1

是的,我认为长格式更好。做这种合并的标准方式是'setkey(dat.m,昵称); dat.m [字典,名称:= i.Name]'。 OP还可以使用'dcast(dat.m,id〜Friend,value.var = c(“Name”,“Nickname”))'来恢复为宽格式,尽管它看起来仍然不像他们想要的输出。 – Frank

+0

@Frank如果'dict'中有未使用的元素,那么回答不会很好。考虑'dict < - rbind(dict,data.table(昵称=“Fran”,Name =“Francesca”))'。您在结果中获得了与'dict'中未使用的行相对应的额外行。 – shadowtalker

+0

@ssdecontrol'dat.m [dict]'会有更多的行,是的,但'dat.m'无法获得额外的行。如果你尝试运行我的代码,然后运行'dat.m',你会发现它只是向表中添加一列 - 这样的合并不能添加行。 – Frank

2
setkey(dict,Nickname) 
dat[,paste(names(dat),"Name",sep="."):=lapply(.SD,function(x)dict[J(x)]$Name)] 
setcolorder(dat,c(1,5,2,6,3,7,4,8)) 
dat 
# Friend1 Friend1.Name Friend2 Friend2.Name Friend3 Friend3.Name Friend4 Friend4.Name 
# 1: Abby  Abigail  Ben  Benjamin  Ed  Edward  Dan  Daniel 
# 2:  Ben  Benjamin  Ed  Edward  NA   NA  NA   NA 
# 3:  Ben  Benjamin  NA   NA  NA   NA  NA   NA 
# 4: Chris Christopher  Ed  Edward  Dan  Daniel  NA   NA 
1

在基地,超级难看:

cbind(dat, lapply(dat, function(x){dict$Name[match(x, dict$Nickname)]})) 

    Friend1 Friend2 Friend3 Friend4   V2  NA  NA  NA 
1: Abby  Ben  Ed  Dan  Abigail Benjamin Edward Daniel 
2:  Ben  Ed  NA  NA Benjamin Edward  NA  NA 
3:  Ben  NA  NA  NA Benjamin  NA  NA  NA 
4: Chris  Ed  Dan  NA Christopher Edward Daniel  NA 
相关问题