我有以下两个数据框:
> 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)将受到高度赞赏。
答案 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
字段/列和值加入两个数据帧。然后使用group
和filter
仅获取包含两个或多个匹配项的字段和值组合
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行。
arrange
和select
实际上只是更容易查看数据所必需的。
答案 1 :(得分:0)
这是怎么回事?使用dplyr
和purrr
,我们会添加id.1
/ id.2
个字段,并将.1
或.2
附加到两个数据框的现有字段中。然后我们为by
参数创建一个向量列表。我们将在inner_join
- df2
到df1
时迭代每个向量,连接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)