2015-08-31 76 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 
相關問題