查找 "similar" 行执行与 sqldf 的条件连接

Finding "similar" rows performing a conditional join with sqldf

假设我有一个 data.table(也可以是 data.frame,对我来说无关紧要)它有数字列 a、b、c、d 和 e。 table 的每一行代表一篇文章,a-e 是文章的数字特征。

我想根据a、b和c列找出哪些文章彼此相似。 我通过允许 a、b 和 c 最多变化 +/- 1 来定义 "similar"。 也就是说,如果 a、b 和 c 的差异均不超过 1,则文章 x 与文章 y 相似。它们的 d 和 e 值无关紧要,可能差异很大。

我已经尝试了几种方法,但没有得到想要的结果。我想要实现的是得到一个结果 table ,它只包含那些至少与其他行相似的行。另外,必须排除重复项。

特别是,我想知道是否可以使用 sqldf 库。我的想法是在给定条件下以某种方式将 table 与自身连接起来,但我没有正确地将它们组合在一起。任何想法(不一定使用 sqldf)?

我对 R 还很陌生,所以不要期望太高。

如果您根据您的值(基本上是向量)创建一个矩阵,其中包含两个值的距离会怎样。所以你可以找到那些彼此相差小于 1 的组合。通过这种方式,您可以找到匹配的 (a)-pairs。对 (b) 和 (c) 重复此操作并找到所有对中包含的那些。

或者,这也可以作为立方体来完成。

只是一个思想提示。

假设我们的输入数据框是 built-in 11x8 anscombe 数据框。它的前三个列名称是 x1x2x3。那么这里有一些解决方案。

1)sqldf这个returns相似行的行号对:

library(sqldf)

ans <- anscombe
ans$id <- 1:nrow(ans)

sqldf("select a.id, b.id 
       from ans a 
       join ans b on abs(a.x1 - b.x1) <= 1 and 
                     abs(a.x2 - b.x2) <= 1 and 
                     abs(a.x3 - b.x3) <= 1")

添加另一个条件 and a.id < b.id 如果每一行不应与其自身配对并且如果我们想要排除每对的反向或添加 and not a.id = b.id 以仅排除自身对。

2) dist 这 returns 一个矩阵 m 其 i,j-th 元素为 1 如果行 i 和 j 相似并且如果不是基于第 1、2 和 3 列,则为 0。

# matrix of pairs (1 = similar, 0 = not)
m <- (as.matrix(dist(anscombe[1:3], method = "maximum")) <= 1) + 0

给予:

   1 2 3 4 5 6 7 8 9 10 11
1  1 0 0 1 1 0 0 0 0  0  0
2  0 1 0 1 0 0 0 0 0  1  0
3  0 0 1 0 0 1 0 0 1  0  0
4  1 1 0 1 0 0 0 0 0  0  0
5  1 0 0 0 1 0 0 0 1  0  0
6  0 0 1 0 0 1 0 0 0  0  0
7  0 0 0 0 0 0 1 0 0  1  1
8  0 0 0 0 0 0 0 1 0  0  1
9  0 0 1 0 1 0 0 0 1  0  0
10 0 1 0 0 0 0 1 0 0  1  0
11 0 0 0 0 0 0 1 1 0  0  1

如果需要,我们可以添加 m[lower.tri(m, diag = TRUE)] <- 0 来排除自身对和每对的反向,或者 diag(m) <- 0 只排除自身对。

我们可以像这样创建类似行号对的数据框。为了保持输出简短,我们排除了自身对和每对的反向。

# two-column data.frame of pairs excluding self pairs and reverses
subset(as.data.frame.table(m), c(Var1) < c(Var2) & Freq == 1)[1:2]

给予:

    Var1 Var2
34     1    4
35     2    4
45     1    5
58     3    6
91     3    9
93     5    9
101    2   10
106    7   10
117    7   11
118    8   11

这是上面的网络图。请注意,答案在图表之后继续:

# network graph
library(igraph)
g <- graph.adjacency(m)
plot(g)

# raster plot
library(ggplot2)
ggplot(as.data.frame.table(m), aes(Var1, Var2, fill = factor(Freq))) + 
       geom_raster()