基于匹配每个数据帧中的两个可交换列来合并两个数据帧

发布于 2024-11-09 06:39:25 字数 996 浏览 3 评论 0原文

我在 R 中有两个数据帧。

dataframe 1

A B C D E F G
1 2 a a a a a
2 3 b b b c c
4 1 e e f f e

dataframe 2

X Y Z
1 2 g
2 1 h
3 4 i
1 4 j

我想将 dataframe1 的 A 列和 B 列与 dataframe2 的 X 列和 Y 列相匹配。这不是成对比较,即第 1 行 (A=1 B=2) 被认为是相同的作为数据帧2的第1行(X = 1,Y = 2)和第2行(X = 2,Y = 1)。

当可以找到匹配时,我想添加数据帧1的C,D,E,F列到dataframe2的匹配行,如下:没有匹配为na。

最终数据帧

X Y Z C  D  E  F  G
1 2 g a  a  a  a  a 
2 1 h a  a  a  a  a
3 4 i na na na na na
1 4 j e  e  f  f  e

我只能知道如何对单列进行匹配,但是,如何对两个可交换列进行匹配并根据匹配结果合并两个数据帧对我来说很困难。请帮助提供明智的方法来做到这一点。

为了便于讨论(感谢 Vincent 和 DWin(我之前的问题)的评论,我应该测试一下引用。)将数据帧 1 和 2 加载到 R 是有配额的。

df1 <- data.frame(A = c(1,2,4), B=c(2,3,1), C=c('a','b','e'), 
                                D=c('a','b','e'), E=c('a','b','f'), 
                                F=c('a','c','f'), G=c('a','c', 'e'))

df2  <- data.frame(X = c(1,2,3,1), Y=c(2,1,4,4), Z=letters[7:10])

I have two dataframe in R.

dataframe 1

A B C D E F G
1 2 a a a a a
2 3 b b b c c
4 1 e e f f e

dataframe 2

X Y Z
1 2 g
2 1 h
3 4 i
1 4 j

I want to match dataframe1's column A and B with dataframe2's column X and Y. It is NOT a pairwise comparsions, i.e. row 1 (A=1 B=2) are considered to be same as row 1 (X=1, Y=2) and row 2 (X=2, Y=1) of dataframe 2.

When matching can be found, I would like to add columns C, D, E, F of dataframe1 back to the matched row of dataframe2, as follows: with no matching as na.

Final dataframe

X Y Z C  D  E  F  G
1 2 g a  a  a  a  a 
2 1 h a  a  a  a  a
3 4 i na na na na na
1 4 j e  e  f  f  e

I can only know how to do matching for single column, however, how to do matching for two exchangable columns and merging two dataframes based on the matching results is difficult for me. Pls kindly help to offer smart way of doing this.

For the ease of discussion (thanks for the comments by Vincent and DWin (my previous quesiton) that I should test the quote.) There are the quota for loading dataframe 1 and 2 to R.

df1 <- data.frame(A = c(1,2,4), B=c(2,3,1), C=c('a','b','e'), 
                                D=c('a','b','e'), E=c('a','b','f'), 
                                F=c('a','c','f'), G=c('a','c', 'e'))

df2  <- data.frame(X = c(1,2,3,1), Y=c(2,1,4,4), Z=letters[7:10])

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

画离情绘悲伤 2024-11-16 06:39:25

以下作品有效,但毫无疑问可以改进。

我首先创建一个小辅助函数,对 A 和 B 执行按行排序(并将其重命名为 V1 和 V2)。

replace_index <- function(dat){
  x <- as.data.frame(t(sapply(seq_len(nrow(dat)), 
    function(i)sort(unlist(dat[i, 1:2])))))
  names(x) <- paste("V", seq_len(ncol(x)), sep="")
  data.frame(x, dat[, -(1:2), drop=FALSE])
} 

replace_index(df1)

  V1 V2 C D E F G
1  1  2 a a a a a
2  2  3 b b b c c
3  1  4 e e f f e

这意味着您可以使用直接的合并来组合数据。

merge(replace_index(df1), replace_index(df2), all.y=TRUE)

  V1 V2    C    D    E    F    G Z
1  1  2    a    a    a    a    a g
2  1  2    a    a    a    a    a h
3  1  4    e    e    f    f    e j
4  3  4 <NA> <NA> <NA> <NA> <NA> i

The following works, but no doubt can be improved.

I first create a little helper function that performs a row-wise sort on A and B (and renames it to V1 and V2).

replace_index <- function(dat){
  x <- as.data.frame(t(sapply(seq_len(nrow(dat)), 
    function(i)sort(unlist(dat[i, 1:2])))))
  names(x) <- paste("V", seq_len(ncol(x)), sep="")
  data.frame(x, dat[, -(1:2), drop=FALSE])
} 

replace_index(df1)

  V1 V2 C D E F G
1  1  2 a a a a a
2  2  3 b b b c c
3  1  4 e e f f e

This means you can use a straight-forward merge to combine the data.

merge(replace_index(df1), replace_index(df2), all.y=TRUE)

  V1 V2    C    D    E    F    G Z
1  1  2    a    a    a    a    a g
2  1  2    a    a    a    a    a h
3  1  4    e    e    f    f    e j
4  3  4 <NA> <NA> <NA> <NA> <NA> i
妥活 2024-11-16 06:39:25

这有点笨重,并且存在一些潜在的冲突和顺序问题,但可以与您的示例

df1a <- df1; df1a$A <- df1$B; df1a$B <- df1$A #reverse A and B
merge(df2, rbind(df1,df1a), by.x=c("X","Y"), by.y=c("A","B"), all.x=TRUE)

一起生成

  X Y Z    C    D    E    F    G
1 1 2 g    a    a    a    a    a
2 1 4 j    e    e    f    f    e
3 2 1 h    a    a    a    a    a
4 3 4 i <NA> <NA> <NA> <NA> <NA>

This is slightly clunky, and has some potential collision and order issues but works with your example

df1a <- df1; df1a$A <- df1$B; df1a$B <- df1$A #reverse A and B
merge(df2, rbind(df1,df1a), by.x=c("X","Y"), by.y=c("A","B"), all.x=TRUE)

to produce

  X Y Z    C    D    E    F    G
1 1 2 g    a    a    a    a    a
2 1 4 j    e    e    f    f    e
3 2 1 h    a    a    a    a    a
4 3 4 i <NA> <NA> <NA> <NA> <NA>
懷念過去 2024-11-16 06:39:25

一种方法是创建一个用于匹配的 id 键,该键是顺序不变的。

# create id key to match
require(plyr)
df1 = adply(df1, 1, transform, id = paste(min(A, B),  "-", max(A, B)))
df2 = adply(df2, 1, transform, id = paste(min(X, Y),  "-", max(X, Y)))

# combine data frames using `match`
cbind(df2, df1[match(df2$id, df1$id),3:7])

这会产生输出

X Y Z    id    C    D    E    F    G
1   1 2 g 1 - 2    a    a    a    a    a
1.1 2 1 h 1 - 2    a    a    a    a    a
NA  3 4 i 3 - 4 <NA> <NA> <NA> <NA> <NA>
3   1 4 j 1 - 4    e    e    f    f    e

One approach would be to create an id key for matching that is order invariant.

# create id key to match
require(plyr)
df1 = adply(df1, 1, transform, id = paste(min(A, B),  "-", max(A, B)))
df2 = adply(df2, 1, transform, id = paste(min(X, Y),  "-", max(X, Y)))

# combine data frames using `match`
cbind(df2, df1[match(df2$id, df1$id),3:7])

This produces the output

X Y Z    id    C    D    E    F    G
1   1 2 g 1 - 2    a    a    a    a    a
1.1 2 1 h 1 - 2    a    a    a    a    a
NA  3 4 i 3 - 4 <NA> <NA> <NA> <NA> <NA>
3   1 4 j 1 - 4    e    e    f    f    e
南城旧梦 2024-11-16 06:39:25

您还可以以两种方式连接表(X == AY == B,然后 X == BY == A)并rbind它们。这将产生重复对,其中一种方式产生匹配,另一种方式产生 NA,因此您可以通过为每个 XY 组合仅切片一行(没有 NA 的行)来减少重复项代码> 如果存在的话。

library(dplyr)
m <- left_join(df2,df1,by = c("X" = "A","Y" = "B"))
n <- left_join(df2,df1,by = c("Y" = "A","X" = "B"))

rbind(m,n) %>%
  group_by(X,Y) %>%
  arrange(C,D,E,F,G) %>% # sort to put NA rows on bottom of pairs
  slice(1) # take top row from combination

生产:

Source: local data frame [4 x 8]
Groups: X, Y

  X Y Z  C  D  E  F  G
1 1 2 g  a  a  a  a  a
2 1 4 j  e  e  f  f  e
3 2 1 h  a  a  a  a  a
4 3 4 i NA NA NA NA NA

You could also join the tables both ways (X == A and Y == B, then X == B and Y == A) and rbind them. This will produce duplicate pairs where one way yielded a match and the other yielded NA, so you would then reduce duplicates by slicing only a single row for each X-Y combination, the one without NA if one exists.

library(dplyr)
m <- left_join(df2,df1,by = c("X" = "A","Y" = "B"))
n <- left_join(df2,df1,by = c("Y" = "A","X" = "B"))

rbind(m,n) %>%
  group_by(X,Y) %>%
  arrange(C,D,E,F,G) %>% # sort to put NA rows on bottom of pairs
  slice(1) # take top row from combination

Produces:

Source: local data frame [4 x 8]
Groups: X, Y

  X Y Z  C  D  E  F  G
1 1 2 g  a  a  a  a  a
2 1 4 j  e  e  f  f  e
3 2 1 h  a  a  a  a  a
4 3 4 i NA NA NA NA NA
千鲤 2024-11-16 06:39:25

这是基础 R 中的另一个可能的解决方案。此解决方案使用 cbind() 为两个 data.frames 添加新的关键列(K1K2)矢量化 pmin()pmax() 函数来导出关键列的规范顺序,并对其进行合并:

merge(cbind(df2,K1=pmin(df2$X,df2$Y),K2=pmax(df2$X,df2$Y)),cbind(df1,K1=pmin(df1$A,df1$B),K2=pmax(df1$A,df1$B)),all.x=T)[,-c(1:2,6:7)];
##   X Y Z    C    D    E    F    G
## 1 1 2 g    a    a    a    a    a
## 2 2 1 h    a    a    a    a    a
## 3 1 4 j    e    e    f    f    e
## 4 3 4 i <NA> <NA> <NA> <NA> <NA>

请注意 pmin()< 的使用/代码> 和pmax() 仅适用于此问题,因为您只有两个关键列;如果你有更多,那么你必须使用某种 apply+sort 解决方案来实现合并的规范键顺序,类似于 @Andrie 在他的辅助函数中所做的,这适用于任意数量的键列,但是性能会较差。

Here's another possible solution in base R. This solution cbind()s new key columns (K1 and K2) to both data.frames using the vectorized pmin() and pmax() functions to derive the canonical order of the key columns, and merges on those:

merge(cbind(df2,K1=pmin(df2$X,df2$Y),K2=pmax(df2$X,df2$Y)),cbind(df1,K1=pmin(df1$A,df1$B),K2=pmax(df1$A,df1$B)),all.x=T)[,-c(1:2,6:7)];
##   X Y Z    C    D    E    F    G
## 1 1 2 g    a    a    a    a    a
## 2 2 1 h    a    a    a    a    a
## 3 1 4 j    e    e    f    f    e
## 4 3 4 i <NA> <NA> <NA> <NA> <NA>

Note that the use of pmin() and pmax() is only possible for this problem because you only have two key columns; if you had more, then you'd have to use some kind of apply+sort solution to achieve the canonical key order for merging, similar to what @Andrie does in his helper function, which would work for any number of key columns, but would be less performant.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文