R合並數據框有重復匹配時只保留第一行


前言

合並數據框有重復匹配時通常會返回所有的匹配,如何只保留匹配的第一行呢?其實這個需求也很常見。如芯片探針ID和基因ID往往多對一,要合並ID對應矩陣和芯片表達矩陣時。

數據例子

data = data.frame(id = c(1,2,3,4,5),
                  state = c("KS","MN","AL","FL","CA"))
scores = data.frame(id = c(1,1,1,2,2,3,3,3),
                    score = c(66,75,78,86,85,76,75,90))

數據長這樣:

想要這樣的結果:

錯誤的嘗試

試了不少方法,以下都是達不到需求的:

dplyr::left_join(data,scores,by="id")
dplyr::inner_join(data,scores,by="id")
dplyr::left_join(data, scores, by="id", match="first") 

merge(data, scores, by = "id")                  
dplyr::semi_join(data, scores, by = "id") 

#distinct去重
dplyr::left_join(data, dplyr::distinct(scores, id, .keep_all = T))
data %>% dplyr::left_join(dplyr::distinct(scores, id, .keep_all = T)) %>% 
  tidyr::replace_na(replace = list("score"=0L)) #替換na

正確方法

通過網上查找,找到了如下實現方式:

方法1

require(data.table)
setDT(scores); setDT(data) # convert to data.tables by reference
scores[data, mult = "first", on = "id", nomatch=0L]

#注意兩者順序
data[scores, mult = "first", on = "id", nomatch=0L] #達不到要求

方法2

merge(data, aggregate(score ~ id, data=scores, head, 1), by="id") 

方法3

merge(data, scores[!duplicated(scores$id),], by="id")

方法4

#Return also those which found no match
tt <- cbind(data, score=scores[match(data$id, scores$id),"score"])
#Return only those which found a match
tt[!is.na(tt$score),]

總結

個人最鍾意第一種方法,因為data.table真的適合處理大數據,相比於join和merge等快了不少,幾千萬個基因探針我用join處理的話要很久很久,而且占的內存超級大。data.table幾分鍾就處理完了。

不過data.table的語法感覺怪怪的,所以一直沒去學,看來要好好學習一下了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM