在R

2017-09-30 73 views
1

中的纵向表的复杂连接我有〜16个.txt文件,我需要变成一个宽的平面文件。对于每个新文件,时间已过,并添加了一些新变量。我想要做的就是将这些新列添加到第一个表的右侧,并加入一个识别变量。这得到迅速复杂,所以这里是一个MRE:在R

library(dplyr) 

id <- as.character(1:6) 
first <- c("jeff", "jimmy", "andrew", "taj", "karl-anthony", "jamal") 
last <- c("teague", "butler", "wiggins", "gibson", "towns", "crawford") 
set.seed(1839) 
a <- c(1:4, NA, NA) 
b <- c(1:4, NA, NA) 
c <- c(11:13, NA, 14, NA) 
d <- c(11:13, NA, 14, NA) 
e <- c(21, 22, NA, 24, NA, 26) 
f <- c(21, 22, NA, 24, NA, 26) 

模拟三种不同的文件:

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柱,和(b)这些名字都没有出现在df_all数据帧的是,和(c)做了full_join列:

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已经存在,我还尝试逐行进行列连接,如果不存在,则会执行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::spreadtidyr::gather,但我还没有找到一个解决方案呢。

我并不喜欢tidyversebasedata.table会很棒,甚至可以通过某种方式在R中进行SQL连接)甚至是R;我也对使用熊猫的Python解决方案开放。

简短版本:如何将新列与现有数据集(通过标识号)相结合并填写来自非新列的信息,但由于案例是新的,需要填写?


可能的解决方法,每Psidom:

df_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 

也许更有效的方式来做到这一点,但?

+0

我完全跳过了包括我定义这些data.frames的地方。现在更新。 –

+1

'df_1%>%full_join(df_2,by = c(“id”,“first”,“last”))%>%full_join(df_3,by = c(“id”,“first”,“last”) )'适合我。 – Psidom

+0

我也是,谢谢!但是:如果我不知道这些变量的名字怎么办?也就是说,假设我想加入“综合”数据框到目前为止的所有变量? –

回答

1

使用melt一旦你有一个full_join df_all。

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

使用dplyr最简单的办法就是省略by参数在调用full_join()

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

Joining, by = c("id", "first", "last")
Joining, by = c("id", "first", "last")

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 

Warning messages:
1: Column id joining factors with different levels, coercing to character vector
2: Column first joining factors with different levels, coercing to character vector
3: Column last joining factors with different levels, coercing to character vector

by参数的文档中?full_join说:如果NULL,默认,*_join()会做自然连接,使用具有跨两个表通用名称的所有变量。

所以这等价于通过by = c("id", "first", "last")as proposed by Psidom


如果有很多数据帧的加入,下面的代码可以节省大量的输入:

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

结果(inluding消息)是与上述相同。