R - 分别将一个数据帧合并/连接到多个数据帧

时间:2017-11-21 20:19:42

标签: r dplyr left-join

我已经看到几个线程将多个数据帧合并到一个" master"数据帧,但我想采用一个参考数据帧并将其应用于其他几个数据帧,同时保持其他数据帧分离。我尝试过使用lapply和'循环,但没有想出如何做到这一点。 (免责声明:我是R的新人。)

df_geo是参考数据框,看起来像这样:

district sector cell    village  village_code
west    sectorA cellA   villageA    XXXXXXXX
west    sectorA cellA   villageB    XXXXXXXX
west    sectorB cellB   villageC    XXXXXXXX
south   sectorC cellC   villageD    XXXXXXXX

还有其他三个数据集,其中包含更多列,其中包含特定于其所包含数据类型的信息,即分发,调查,跟进。每个数据集都有区域,扇区,单元格和村庄(名称相同)的列。例如:

> df_distr
v1  district sector cell    village     v2  v3  …
..  west    sectorA cellA   villageA    ..  ..  …
..  west    sectorA cellA   villageB    ..  ..  …
..  west    sectorB cellB   villageC    ..  ..  …
..  south   sectorC cellC   villageD    ..  ..  …

> df_survey
v1  v5  v6  district sector  cell   village     v7  …  
..  ..  ..  west    sectorA cellA   villageA    ..  ..
..  ..  ..  west    sectorA cellA   villageB    ..  ..
..  ..  ..  west    sectorB cellB   villageC    ..  ..
..  ..  ..  south   sectorC cellC   villageD    ..  ..

每个数据框具有不同数量的列,并且位置变量在每个数据列中不在相同的数字列中。每个区 - 扇区 - 单元 - 村组合都是唯一的,每个village_code也是如此。我正在尝试向三个数据帧中的每一个添加一个village_code列,该数据帧根据区 - 扇区 - 单元 - 村庄匹配记录8位数字位置ID。理想情况下,我希望将列附加到每个原始数据帧(而不是存储在列表中)。因此,我希望他们看起来像这样:

> df_distr
v1  district sector cell    village     v2  v3  …  village_code
..  west    sectorA cellA   villageA    ..  ..  …    XXXXXXXX
..  west    sectorA cellA   villageB    ..  ..  …    XXXXXXXX
..  west    sectorB cellB   villageC    ..  ..  …    XXXXXXXX
..  south   sectorC cellC   villageD    ..  ..  …    XXXXXXXX

> df_survey
v1  v5  v6  district sector  cell   village     v7  …  village_code
..  ..  ..  west    sectorA cellA   villageA    ..  ..   XXXXXXXX
..  ..  ..  west    sectorA cellA   villageB    ..  ..   XXXXXXXX
..  ..  ..  west    sectorB cellB   villageC    ..  ..   XXXXXXXX
..  ..  ..  south   sectorC cellC   villageD    ..  ..   XXXXXXXX

我可以使用df_distr <- left_join(df_distr, df_geo, by = c("district", "sector", "cell", "village"))之类的代码逐个成功完成此操作,但我想要一种更有效的方法。

2 个答案:

答案 0 :(得分:0)

您可以利用data.table修改引用属性来附加village_code列,而无需重新分配数据框:

library(data.table)

setDT(df_geo)
setDT(df_distr)
setDT(df_survey)

lapply(list(df_distr, df_survey), 
       function(x) x[df_geo, village_code := i.village_code, 
                     on=.(district, sector, cell, village)])

请注意,由于df_distrdf_surveylapply会被打印出来,但data.frames本身已成功修改。如果您只想要:=的副作用,则可以使用purrr::walk,其效果类似lapply/map,但会抑制输出:

library(purrr)
walk(list(df_distr, df_survey), ~ .[df_geo, village_code := i.village_code,
                                    on=.(district, sector, cell, village)])

请注意,此方法也比重新分配快得多,因为在修改data.frames时没有复制。

<强>结果:

> df_distr
   v1 district  sector  cell  village v2 v3 village_code
1: ..     west sectorA cellA villageA .. ..     XXXXXXXX
2: ..     west sectorA cellA villageB .. ..     XXXXXXXX
3: ..     west sectorB cellB villageC .. ..     XXXXXXXX
4: ..    south sectorC cellC villageD .. ..     XXXXXXXX

> df_survey
   v1 v5 v6 district  sector  cell  village v7 village_code
1: .. .. ..     west sectorA cellA villageA ..     XXXXXXXX
2: .. .. ..     west sectorA cellA villageB ..     XXXXXXXX
3: .. .. ..     west sectorB cellB villageC ..     XXXXXXXX
4: .. .. ..    south sectorC cellC villageD ..     XXXXXXXX

数据:

df_geo = read.table(text = "district sector cell    village  village_code
west    sectorA cellA   villageA    XXXXXXXX
                    west    sectorA cellA   villageB    XXXXXXXX
                    west    sectorB cellB   villageC    XXXXXXXX
                    south   sectorC cellC   villageD    XXXXXXXX", header = TRUE)

df_distr = read.table(text = "v1  district sector cell    village     v2  v3
..  west    sectorA cellA   villageA    ..  ..
..  west    sectorA cellA   villageB    ..  ..
..  west    sectorB cellB   villageC    ..  ..
..  south   sectorC cellC   villageD    ..  ..", header = TRUE)


df_survey = read.table(text = "v1  v5  v6  district sector  cell   village     v7  
..  ..  ..  west    sectorA cellA   villageA    ..
..  ..  ..  west    sectorA cellA   villageB    ..
..  ..  ..  west    sectorB cellB   villageC    ..
..  ..  ..  south   sectorC cellC   villageD    ..", header = TRUE)

答案 1 :(得分:-1)

我们说我有一组四个数据帧。 reference是df_geo的替代,tab*数据框代表您正在使用的未知表格。

reference = data.frame(key = letters[1:10],value = 1:10)
tab1 = data.frame(journey = LETTERS[1:3],key=letters[1:3])
tab2 = data.frame(trip = LETTERS[7:10],key=letters[7:10])
tab3 = data.frame(destination = LETTERS[4:8],key=letters[4:8])

目标是将reference加入到彼此的数据框中。

output = lapply(list(tab1=tab1,tab2=tab2,tab3=tab3),left_join,reference,by="key")

在这里,我创建tab*数据框的命名列表(重要),并使用lapply将相同的函数应用于每个数据框,left_join在这种情况下。在我指定函数之后,我可以为函数提供其他必要的参数 - 在这种情况下,要加入的表(reference)和by="key"来指示它们应该如何连接。

这将返回一个数据框列表,但您似乎希望将它们分配回全局环境。

lapply(names(output),function(x){
  assign(x,value=output[[x]],envir=globalenv())
})

这次当我们使用lapply时,我们会对输出的名称(这是我们在上一步中指定的名称)进行操作。我们assignoutput的值命名为tab*将这个名字带入全球环境。

现在所有的df.write.mode("overwrite") .parquet("/Volumes/Data Drive/dgebooth_Collection20161031.parquet") 数据框都已更新,我们要做的就是编写一个需要更新的数据框的命名列表。