簡體   English   中英

基於列和行在R中合並

[英]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 ,因此我們unlistunlist list 這些值通過引用分配給列ratio

由於這避免了通過熔化/聚集而不必要地實現中間數據的實現,因此它非常有效。 此外,由於在連接時通過引用添加了新列,因此避免了另一個中間實現,並且效率很高。

就我個人而言,我發現代碼更容易理解所發生的事情(當然具有足夠的基礎R知識),但這當然是主觀的。


稍微詳細一點的解釋:

data.table語法的一般形式是DT[i, j, by] ,其內容為:

DTi子集行,然后計算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為空。 因此,它從dt1dt2返回所有列(導致右連接)。

換句話說,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

有關:=運算符歷史的更多詳細信息,請參見thisthisthis

有關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)

您可以使用包reshape2dplyr來做到這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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM