在R中,发现部分匹配另一个数据帧中的行的行

时间:2018-03-31 13:17:34

标签: r dataframe dplyr match

我有以下两个数据框:

> df1
# A tibble: 4 x 4
    x     y     z     w
  <dbl> <dbl> <dbl> <dbl>
    4     5     8     9
    4     6     7     4
    3     6     7    10
    8     2     8     9
> df2
# A tibble: 4 x 4
    x     y     z     w
  <dbl> <dbl> <dbl> <dbl>
    6     2     7     9
    2     6     7    10
    4     5     8    12
    4     5     8     3

我想发现df2中哪些行在df1中匹配,其中匹配意味着在至少n / 2列中相同。

因此,在此示例中,df2中的第1行与df1中的第4行匹配(第1列和第3列),df2中的第2行与第2列和第3列的df1中的第2行以及第2,3列中的第3行匹配, 4等等。

我还必须保存重复行的位置以及它们匹配的列。

对于小数据集,我可以复制两个数据集并减去它们并计算零。但是我需要的是一个可以处理非常大的数据集(~20K行)的解决方案。

有什么想法吗? dplyr解决方案(而不是data.table)将受到高度赞赏。

4 个答案:

答案 0 :(得分:1)

这个最终输出可能不是理想的格式,但它至少应该包含您正在寻找的信息,并且可以使用更多的字段/列。

df1 <- read.table(text =
             "x     y     z     w
              4     5     8     9
              4     6     7     4
              3     6     7    10
              8     2     8     9",
              header = T)

df2 <- read.table(text =
             "x     y     z     w
              6     2     7     9
              2     6     7    10
              4     5     8    12
              4     5     8     3",
              header = T)


library(dplyr)
library(tidyr)

为每个数据框添加行ID编号,并使用gather从宽到长重新整形数据。 (我假设每一行都可以被视为一个唯一的ID):

df1 <- df1 %>% 
  mutate(df1_id = row_number()) %>%
  gather(field, value, x:w) %>% 
  arrange(df1_id)

df2 <- df2 %>% 
  mutate(df2_id = row_number()) %>% 
  gather(field, value, x:w) %>% 
  arrange(df2_id)

使用inner_join字段/列和值加入两个数据帧。然后使用groupfilter仅获取包含两个或多个匹配项的字段和值组合

df2 %>% 
  inner_join(df1, by = c('value', 'field')) %>%
  group_by(df2_id, df1_id) %>% 
  filter(n()>=2) %>%  # where 2 is the minimum number of matches
  arrange(df2_id, df1_id, value) %>% 
  select(df2_id, df1_id, field, value)

# A tibble: 13 x 4
# Groups:   df2_id, df1_id [5]
   df2_id df1_id field value
    <int>  <int> <chr> <int>
 1      1      4 y         2
 2      1      4 w         9
 3      2      2 y         6
 4      2      2 z         7
 5      2      3 y         6
 6      2      3 z         7
 7      2      3 w        10
 8      3      1 x         4
 9      3      1 y         5
10      3      1 z         8
11      4      1 x         4
12      4      1 y         5
13      4      1 z         8

你可以看到df2 row id 1匹配字段y和w上的df1 row 4, df2第2行匹配字段y和z上的df1第2行, df2第2行也匹配字段y,x和w上的df1第3行。 df2第3行和第4行在x,y和z上匹配df1第1行。

arrangeselect实际上只是更容易查看数据所必需的。

答案 1 :(得分:0)

这是怎么回事?使用dplyrpurrr,我们会添加id.1 / id.2个字段,并将.1.2附加到两个数据框的现有字段中。然后我们为by参数创建一个向量列表。我们将在inner_join - df2df1时迭代每个向量,连接inner_join的所有结果,并从中选择id s两个数据框。

require(dplyr)
require(purrr)

df1 <- tibble(
  x = c(4, 4, 3, 8),
  y = c(5, 6, 6, 2),
  z = c(8, 7, 7, 8),
  w = c(9, 4, 10, 9)
)

df2 <- tibble(
  x = c(6, 2, 4, 4),
  y = c(2, 6, 5, 5),
  z = c(7, 7, 8, 8),
  w = c(9, 10, 12, 13)
)

df1 <- df1 %>%
  mutate(id.1 = 1:length(.)) %>%
  rename(
    x.1 = x,
    y.1 = y,
    z.1 = z,
    w.1 = w
  )

df2 <- df2 %>%
  mutate(id.2 = 1:length(.)) %>%
  rename(
    x.2 = x,
    y.2 = y,
    z.2 = z,
    w.2 = w
  )

inner_join_by <-
  list(
    c("x.1" = "x.2", "y.1" = "y.2"),
    c("x.1" = "x.2", "z.1" = "z.2"),
    c("x.1" = "x.2", "w.1" = "w.2"),
    c("y.1" = "y.2", "z.1" = "z.2"),
    c("y.1" = "y.2", "w.1" = "w.2"),
    c("z.1" = "z.2", "w.1" = "w.2")
  )

filtered <- inner_join_by %>%
  map_df(.f = ~inner_join(x = df1, y = df2, by = .x)) %>%
  select(id.1, id.2) %>%
  distinct()

答案 2 :(得分:0)

一个选项可能是apply逐行使用:

apply(df1, 1, function(x)apply(df2,1,function(y)x==y))

#      [,1]  [,2]  [,3]  [,4]
# [1,] FALSE FALSE FALSE FALSE
# [2,] FALSE FALSE FALSE  TRUE
# [3,] FALSE  TRUE  TRUE FALSE
# [4,]  TRUE FALSE FALSE  TRUE
# [5,] FALSE FALSE FALSE FALSE
# [6,] FALSE  TRUE  TRUE FALSE
# [7,] FALSE  TRUE  TRUE FALSE
# [8,] FALSE FALSE  TRUE FALSE
# [9,]  TRUE  TRUE FALSE FALSE
# [10,]  TRUE FALSE FALSE FALSE
# [11,]  TRUE FALSE FALSE  TRUE
# [12,] FALSE FALSE FALSE FALSE
# [13,]  TRUE  TRUE FALSE FALSE
# [14,]  TRUE FALSE FALSE FALSE
# [15,]  TRUE FALSE FALSE  TRUE
# [16,] FALSE FALSE FALSE FALSE

答案 3 :(得分:0)

以下解决方案(仍然涉及循环):

这里给定行检查和返回的函数匹配:

fct <- function(x, dat){
  M1logical <- t(unlist(x) == t(dat))
  n <- which(rowSums(M1logical) > 1)
  if(length(n) > 0){
    return(n)
  }
  if(length(n) == 0){
    return(0)
  }
}

现在应用迭代:

mylist <- rep(list(NA), nrow(df2))
for(k in 1:nrow(df2)){
  mylist[[k]] <- fct(df2[k,], df1)
}

我的计算机需要23.14秒(microbenchmark)来计算两个大小为20000x4的数据帧,请参阅此处了解虚拟数据(旧设备上大约45秒):

df1 <- data.frame(x=sample(1:20,20000, replace = T), y=sample(1:20,20000, replace = T), 
              z=sample(1:20,20000, replace = T), w=sample(1:20,20000, replace = T),
              stringsAsFactors = F)
df2 <- data.frame(x=sample(1:20,20000, replace = T), y=sample(1:20,20000, replace = T), 
              z=sample(1:20,20000, replace = T), w=sample(1:20,20000, replace = T),
              stringsAsFactors = F)