R中纵向表的复杂连接

时间:2017-09-30 01:12:22

标签: r join dplyr tidyr

我有~16个.txt文件,我需要把它变成一个宽平面文件。对于每个新文件,时间已过,并添加了一些新变量。我想要做的是将这些新列附加到第一个表的右侧,通过标识变量连接。这很快变得复杂,所以这里有一个MRE:

df_1 <- data.frame(
  id = id[c(1:3,5)],
  first = first[c(1:3,5)],
  last = last[c(1:3,5)],
  a = a[c(1:3,5)],
  b = b[c(1:3,5)]
)

df_2 <- data.frame(
  id = id[c(1:3,5)],
  first = first[c(1:3,5)],
  last = last[c(1:3,5)],
  c = c[c(1:3,5)],
  d = d[c(1:3,5)]
)

df_3 <- data.frame(
  id = id[c(1,2,4,6)],
  first = first[c(1,2,4,6)],
  last = last[c(1,2,4,6)],
  e = e[c(1,2,4,6)],
  f = f[c(1,2,4,6)]
)

df_goal <- data.frame(id, first, last, a, b, c, d, e, f)

模拟三个不同的文件:

df_goal

> df_goal id first last a b c d e f 1 1 jeff teague 1 1 11 11 21 21 2 2 jimmy butler 2 2 12 12 22 22 3 3 andrew wiggins 3 3 13 13 NA NA 4 4 taj gibson 4 4 NA NA 24 24 5 5 karl-anthony towns NA NA 14 14 NA NA 6 6 jamal crawford NA NA NA NA 26 26 是我想要的,这就是它的样子:

full_join

请注意,这些是非常大的文件,并且列并不总是正确的顺序,因此我不能仅仅通过保留前三列来表示加入。

如果我对所有人进行df_all <- df_1 %>% full_join(df_2, by = "id") %>% full_join(df_3, by = "id") > df_all id first.x last.x a b first.y last.y c d first last e f 1 1 jeff teague 1 1 jeff teague 11 11 jeff teague 21 21 2 2 jimmy butler 2 2 jimmy butler 12 12 jimmy butler 22 22 3 3 andrew wiggins 3 3 andrew wiggins 13 13 <NA> <NA> NA NA 4 5 karl-anthony towns NA NA karl-anthony towns 14 14 <NA> <NA> NA NA 5 4 <NA> <NA> NA NA <NA> <NA> NA NA taj gibson 24 24 6 6 <NA> <NA> NA NA <NA> <NA> NA NA jamal crawford 26 26 ,我每次都会重复这些名字:

for

我接下来要做的事情。我写了一个id循环,我得到了每个数据框,只选择了(a)df_all列,以及(b)名称尚未出现在full_join数据框中的列,(c)做了dfs <- c("df_2", "df_3") df_all1 <- df_1 for (i in dfs) { df_all1 <- get(i)[!names(get(i)) %in% names(df_all1)[-1]] %>% full_join(df_all1, .) } > df_all1 id first last a b c d e f 1 1 jeff teague 1 1 11 11 21 21 2 2 jimmy butler 2 2 12 12 22 22 3 3 andrew wiggins 3 3 13 13 NA NA 4 5 karl-anthony towns NA NA 14 14 NA NA 5 4 <NA> <NA> NA NA NA NA 24 24 6 6 <NA> <NA> NA NA NA NA 26 26

id

请注意,这意味着在第一个文件中出现 not 的情况缺少名称(这些代表我的数据中的关键人口统计变量)。如果bind_row已经存在,我还尝试逐行进行并进行列连接,如果不存在则执行df_all2 <- df_1 for (i in dfs) { for (k in 1:nrow(get(i))) { if (get(i)[k, "id"] %in% df_all2$id) { df_all2 <- get(i)[k, !names(get(i)) %in% names(df_all2)[-1]] %>% left_join(df_all2, ., by = "id") } else { df_all2 <- bind_rows( df_all2, get(i)[k, !names(get(i)) %in% names(df_all2)[-1]] ) } } } 。此代码引发了错误:

join

是一种仅使用选择列执行tidyr::spread的方法,但必要时填写缺少的信息。我再次使用大量具有大量列的文件,所以我不能假设我知道任何列的位置;它必须由列名完成。

我还考虑过只包含一个新变量,即文件的日期,将它们全部堆叠在一起(“长”格式),然后使用tidyr::gathertidyverse ,但我还没有找到解决方案。

我并不认同basedata.tabledf_all1 <- df_1 for (i in dfs) { df_all1 <- get(i) %>% full_join( df_all1, ., by = names(get(i))[names(get(i)) %in% names(df_all1)] ) } df_all1 会很棒,甚至某种方式在R中进行SQL连接)甚至是R;我也对使用pandas的Python解决方案持开放态度。

简短版本:如何通过标识号将新列连接到现有数据集 - 并填写非新列中的信息,但由于案例是新的,需要填写在?

可能的解决方案,根据Psidom:

{{1}}

这可能是一种更有效的方法吗?

2 个答案:

答案 0 :(得分:1)

一旦melt df_all,请使用full_join

library(data.table)
df <- melt(setDT(df_all), 
 measure.vars = patterns("^first", "^last"))
df <- unique(df[,-c("id", "variable")])
df[!is.na(df$value1),]

    a  b  c  d  e  f       value1   value2
1:  1  1 11 11 21 21         jeff   teague
2:  2  2 12 12 22 22        jimmy   butler
3:  3  3 13 13 NA NA       andrew  wiggins
4: NA NA 14 14 NA NA karl-anthony    towns
5: NA NA NA NA 24 24          taj   gibson
6: NA NA NA NA 26 26        jamal crawford

答案 1 :(得分:1)

使用dplyr的最简单的解决方案是在by的调用中省略full_join()参数。

library(dplyr)
df_1 %>% 
  full_join(df_2) %>% 
  full_join(df_3)
  

加入,按= c(&#34; id&#34;,&#34;首先&#34;,&#34;最后&#34;)
  加入,by = c(&#34; id&#34;,&#34; first&#34;,   &#34;最后&#34)

  id        first     last  a  b  c  d  e  f
1  1         jeff   teague  1  1 11 11 21 21
2  2        jimmy   butler  2  2 12 12 22 22
3  3       andrew  wiggins  3  3 13 13 NA NA
4  5 karl-anthony    towns NA NA 14 14 NA NA
5  4          taj   gibson NA NA NA NA 24 24
6  6        jamal crawford NA NA NA NA 26 26
     

警告讯息:
  1:列id加入具有不同级别的因子,强制转换为字符向量
  2:列first加入不同级别的因子,强制转换为字符向量
  3:列last加入具有不同级别的因子,强制转换为字符向量

by?full_join参数的文档说:如果NULL,则默认*_join()将使用所有常见变量进行自然连接两个表中的名称。

所以这相当于浏览by = c("id", "first", "last") as proposed by Psidom

如果要加入许多数据框,下面的代码可能会节省大量的输入:

Reduce(full_join, list(df_1, df_2, df_3))

结果(包括消息)与上述相同。