我想使用Jaccard距离计算距离矩阵。并尽快这样做。我曾经使用scikit-learn的pairwise_distances功能。但是scikit-learn并不打算支持GPU,甚至还有一个已知的错误,使函数在并行运行时变慢。
我唯一的限制是,生成的距离矩阵可以提供给scikit-learn的DBSCAN聚类算法。我正在考虑用 tensorflow 实现计算,但找不到一种漂亮而简单的方法来做到这一点。
PS:我有理由预先计算距离矩阵,而不是让DBSCAN根据需要进行操作。
Hej 我面临着同样的问题。
鉴于 jaccard 相似性是真正极 (tp) 与真阳性、假阴性 (fn) 和假阳性 (fp) 之和之和的比率,我想出了这个解决方案:
def jaccard_distance(self):
tp = tf.reduce_sum(tf.mul(self.target, self.prediction), 1)
fn = tf.reduce_sum(tf.mul(self.target, 1-self.prediction), 1)
fp = tf.reduce_sum(tf.mul(1-self.target, self.prediction), 1)
return 1 - (tp / (tp + fn + fp))
希望这有帮助!
我不是张量流专家,但这是我得到的解决方案。据我所知,在 tensorflow 中对列表的所有对进行计算的唯一方法是进行矩阵乘法或使用广播规则,该解决方案在某些时候同时使用两者。
因此,假设我们有一个输入布尔矩阵,由n_samples
行组成,每组一个,n_features
列,每个可能的元素一个。第 i 行中True
的值,第 j 列表示第 i个集合包含元素j。就像scikit-learn pairwise_distances期望的那样。然后,我们可以按以下步骤进行。
- 将矩阵转换为数字,得到 1 表示
True
,0 表示False
。 - 将矩阵乘以其自身的转置。这将生成一个矩阵,其中每个元素
M[i][j]
包含第i个和第j个集合之间的交集的大小。 - 通过按行对输入矩阵求和来计算包含所有集合的基数的
cardv
向量。 - 从
cardv
制作行和列向量。 - 计算
1 - M / (cardvrow + cardvcol - M)
.广播规则将在添加行和列向量时完成所有工作。
这个算法作为一个整体看起来有点黑客,但它在与scikit-learn的pairwise_distances
函数计算的结果的合理范围内工作并产生结果。更好的算法应该对每对输入向量进行一次传递,并且只计算矩阵的一半,因为它是对称的。欢迎任何改进。
setsin = tf.placeholder(tf.bool, shape=(N, M))
sets = tf.cast(setsin, tf.float16)
mat = tf.matmul(sets, sets, transpose_b=True, name="Main_matmul")
#mat = tf.cast(mat, tf.float32, name="Upgrade_mat")
#sets = tf.cast(sets, tf.float32, name="Upgrade_sets")
cardinal = tf.reduce_sum(sets, 1, name="Richelieu")
cardinalrow = tf.expand_dims(cardinal, 0)
cardinalcol = tf.expand_dims(cardinal, 1)
mat = 1 - mat / (cardinalrow + cardinalcol - mat)
我使用了float16
类型,因为它似乎比float32
快得多。仅当基数大到足以使其不准确或在执行除法时需要更高精度时,转换为float32
才有用。但即使需要强制转换,将矩阵乘法作为float16
似乎仍然相关。