[英]Merging in R based on column and row
對於示例數據框:
survey <- structure(list(id = 1:10, cntry = structure(c(2L, 3L, 1L, 2L,
2L, 3L, 1L, 1L, 3L, 2L), .Label = c("DE", "FR", "UK"), class = "factor"),
age.cat = structure(c(1L, 1L, 2L, 4L, 1L, 3L, 4L, 4L, 1L,
2L), .Label = c("Y_15.24", "Y_40.54", "Y_55.plus", "Y_less.15"
), class = "factor")), .Names = c("id", "cntry", "age.cat"
), class = "data.frame", row.names = c(NA, -10L))
我想添加一個稱為“ age.cat”的額外列,該列由另一個數據框填充:
age.cat <- structure(list(cntry = structure(c(2L, 3L, 1L), .Label = c("DE",
"FR", "UK"), class = "factor"), Y_less.15 = c(0.2, 0.2, 0.3),
Y_15.24 = c(0.2, 0.1, 0.2), Y_25.39 = c(0.2, 0.3, 0.1), Y_40.54 = c(0.3,
0.2, 0.1), Y_55.plus = c(0.1, 0.2, 0.3)), .Names = c("cntry",
"Y_less.15", "Y_15.24", "Y_25.39", "Y_40.54", "Y_55.plus"), class = "data.frame", row.names = c(NA,
-3L))
age.cat數據框按不同的年齡類別列出了這三個國家的人口比例。 需要在調查數據框中添加相應的國家/年齡類別作為附加列。 以前,例如,當我使用單個國家/地區時,我使用合並,但是據我所知,這在這里不起作用,因為我需要在列和行上進行匹配。
有人有什么想法嗎?
使用data.table
,我將直接執行以下操作:
require(data.table) # v1.9.6+
dt1[dt2, ratio := unlist(mget(age.cat)), by=.EACHI, on="cntry"]
哪里,
dt1 = as.data.table(survey)[, age.cat := as.character(age.cat)]
dt2 = as.data.table(age.cat)
對於dt2
每一行,找到dt1$cntry
中與dt2$cntry
對應的匹配行(通過在cntry
列上進行匹配,有助於將其cntry
子集操作)。 提取那些匹配行的age.cat
值,並將其傳遞給mget()
函數,該函數查找以age.cat
的值命名的變量,並在dt2
找到它( age.cat
,我們也允許dt2
列也可見)目的),並提取相應的值。 由於它返回list
,因此我們unlist
其unlist
list
。 這些值通過引用分配給列ratio
。
由於這避免了通過熔化/聚集而不必要地實現中間數據的實現,因此它非常有效。 此外,由於在連接時通過引用添加了新列,因此避免了另一個中間實現,並且效率很高。
就我個人而言,我發現代碼更容易理解所發生的事情(當然具有足夠的基礎R知識),但這當然是主觀的。
data.table語法的一般形式是DT[i, j, by]
,其內容為:
取
DT
,i
子集行,然后計算by
分組的j
。
data.table中的i
參數除了是子集操作(例如dt1[cntry == "FR"]
,還可以是另一個data.table 。
考慮一下表達式: dt1[dt2, on="cntry"]
。
它要做的第一件事是通過對on
= "cntry"
提供的列進行匹配,為dt2
每一行計算dt1
所有匹配的行索引。 例如,對於dt2$cntry == "FR"
,在dt1
中匹配的行索引是c(1,4,5,10)
。 這些行索引是使用快速二進制搜索在內部計算的。
一旦計算出匹配的行索引,它就會考慮是否在j
參數中提供了表達式。 在上面的表達式中, j
為空。 因此,它從dt1
和dt2
返回所有列(導致右連接)。
換句話說,data.table允許加入以類似的方式被執行以子集 (因為在這兩種操作的目的,操作i
參數是要獲得匹配的行)。 例如, dt1[cntry == "FR"]
將首先計算匹配的行索引,然后提取這些行的所有列(因為j
參數中未提供任何列)。 這具有幾個優點。 例如,如果我們只想返回列的子集,那么我們可以這樣做,例如:
dt1[dt2, .(cntry, Y_less.15), on="cntry"]
這是有效的,因為我們查看了j
表達式,並注意到只需要這兩列。 因此,在計算出的行索引上,我們僅提取所需的列,從而避免了所有其他列的不必要的實現。 因此有效
同樣,就像我們可以選擇列一樣,我們也可以對列進行計算 。 例如,如果您想獲得sum(Y_less.15)
怎么辦?
dt1[dt2, sum(Y_less.15), on="cntry"]
# [1] 2.3
很好,但是它會計算所有匹配行的總和。 如果要在dt2$cntry
獲取每一行的sum
dt2$cntry
辦? 這是by = .EACHI
出現的地方。
dt1[dt2, sum(Y_less.15), on="cntry", by=.EACHI]
# cntry V1
# 1: FR 0.2
# 2: UK 0.2
# 3: DE 0.3
by=.EACHI
確保為i = dt2
每一行評估j
表達式。
同樣,我們也可以在使用:=
運算符加入時添加/更新列。 這就是上面顯示的答案。 唯一棘手的部分是從dt2
提取那些匹配行的值,因為它們存儲在單獨的列中。 因此,我們使用mget()
。 並且表達式“ unlist(mget(.))
在dt2
每一行都被求值,同時與"cntry"
列匹配。 然后使用:=
運算符將相應的值分配給ratio
。
有關
:=
運算符歷史的更多詳細信息,請參見this , this和this 。有關
by=.EACHI
更多by=.EACHI
,請參見此文章 。有關data.table語法介紹和參考語義的更多信息,請參見vignettes 。
希望這可以幫助。
我們可以將第二個數據集melt
為“長”格式后進行聯接
library(data.table) #v1.9.7
melt(setDT(age.cat), id.var="cntry")[survey, on = c("cntry", "variable" = "age.cat")]
# cntry variable value id
# 1: FR Y_15.24 0.2 1
# 2: UK Y_15.24 0.1 2
# 3: DE Y_40.54 0.1 3
# 4: FR Y_less.15 0.2 4
# 5: FR Y_15.24 0.2 5
# 6: UK Y_55.plus 0.2 6
# 7: DE Y_less.15 0.3 7
# 8: DE Y_less.15 0.3 8
# 9: UK Y_15.24 0.1 9
#10: FR Y_40.54 0.3 10
如果我們使用的是CRAN版本,即data.table_1.9.6
,
melt(setDT(age.cat), id.var="cntry", variable.name = "age.cat")[survey,
on = c("cntry", "age.cat")]
您可以將age.cat轉換為長格式,然后按以下方式使用join:
library(dplyr)
library(tidyr)
age.cat <- gather(age.cat, age.cat, proportion, -cntry)
inner_join(survey, age.cat)
您可以使用包reshape2
和dplyr
來做到這dplyr
:
age.cat %>% melt(variable.name="age.cat") %>% left_join(survey, .)
#### id cntry age.cat value
#### 1 1 FR Y_15.24 0.2
#### 2 2 UK Y_15.24 0.1
#### 3 3 DE Y_40.54 0.1
那是你要的嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.