连接数据帧而不返回所有匹配的组合

时间:2019-01-16 02:57:11

标签: r dataframe join dplyr purrr

我有listdata.frame(在此示例中只有2个):

set.seed(1)

df1 <- data.frame(id = sample(LETTERS,50,replace=T), val = rnorm(50), val1 = rnorm(50), stringsAsFactors = F)
df2 <- data.frame(id = sample(LETTERS,30,replace=T), val = rnorm(30), val2 = rnorm(30), stringsAsFactors = F)

df.list <- list(df1,df2)

我只想通过共享列名的子集将join data.frame合并为一个id

如果我使用:

library(dplyr)
df <- df.list %>% purrr::reduce(dplyr::inner_join,by="id")

我没有加入的共享列名被xy所修饰:

  id       val.x       val1     val.y       val2
1  G -0.05612874  0.2914462  2.087167  0.7876396
2  G -0.05612874  0.2914462 -0.255027  1.4411577
3  J -0.15579551 -0.4432919 -1.286301  1.0273924

实际上,对于我没有加入的共享列名,从列表中的单个data.frame中选择它们就足够了-不论它们存在于WRT中到加入的id

我不预先知道这些共享的列名,但这并不难发现:

例如:

df.list.colnames <- unlist(lapply(df.list,function(l) colnames(l %>% dplyr::select(-id))))
df.list.colnames <- table(df.list.colnames)
repeating.colnames <- names(df.list.colnames)[which(df.list.colnames > 1)]

然后允许我将它们与data.frame中的list分开:

repeating.colnames.df <- do.call(rbind,lapply(df.list,function(r) r %>% dplyr::select_(.dots = c("id",repeating.colnames)))) %>%
  unique()

然后我可以加入data.frame的列表,但这些列除外:

然后如上所述加入他们:

for(r in 1:length(df.list)) df.list[[r]] <- df.list[[r]] %>% dplyr::select_(.dots = paste0("-",repeating.colnames))
df <- df.list %>% purrr::reduce(dplyr::inner_join,by="id")

现在我要添加repeating.colnames.df了。我不知道join中的任何dplyr不会返回dfrepeating.colnames.df之间的所有组合,所以看来我只能做apply在每个df$id上,选择repeating.colnames.df中的第一个匹配项,然后将结果与df合并。

在这种情况下,还有什么麻烦的事吗?

2 个答案:

答案 0 :(得分:2)

如果我没有正确遵循,我认为您可以通过编写一个自定义函数传递给reduce来处理此问题,该函数标识公共列名(不包括您的联接列),并将这些列从“合并。在reduce遍历列表时,该函数将“累积”唯一列,默认为“最左侧”表中的列。

类似这样的东西:

library(dplyr)
library(purrr)
set.seed(1)
df1 <- data.frame(id = sample(LETTERS,50,replace=T), val = rnorm(50), val1 = rnorm(50), stringsAsFactors = F)
df2 <- data.frame(id = sample(LETTERS,30,replace=T), val = rnorm(30), val2 = rnorm(30), stringsAsFactors = F)
df.list <- list(df1,df2)

fun <- function(df1, df2, by_col = "id"){
  df1_names <- names(df1)
  df2_names <- names(df2)
  dup_cols <- intersect(df1_names[!df1_names %in% by_col], df2_names[!df2_names %in% by_col])
  out <- dplyr::inner_join(df1, df2[, !(df2_names %in% dup_cols)], by = by_col)
  return(out)
}

df_chase <- df.list %>% reduce(fun,by_col="id")

reprex package(v0.2.1)于2019-01-15创建

如果将df_chase与您的最终解决方案进行比较,则会得出相同的答案:

> all.equal(df_chase, df_orig)
[1] TRUE

答案 1 :(得分:0)

如果您说自己不太在乎它们,则可以使用 public static int removeLastTwoDigits(int n) { int m = 0; String sn = Integer.toString(m); if(n>99 ) { String result = sn.substring(0, sn.length() - 1); m = Integer.parseInt(result); } return m; }

base::merge