我试图计算两组之间的一种模糊Jaccard指数,具有以下基本原理:作为Jaccard指数,我想计算两组共有的项目数与总数之间的比率两组中的不同项目。问题是我想使用具有阈值的相似性函数来确定两个集合中的“相同”项目是什么,以便相似的项目:
我在这里有一个有效的实现(在python中):
def fuzzy_jaccard(set1, set2, similarity, threshold):
intersection_size = union_size = len(set1 & set2)
shorter_difference, longer_difference = sorted([set2 - set1, set1 - set2], key=len)
while len(shorter_difference) > 0:
item1, item2 = max(
itertools.product(longer_difference, shorter_difference),
key=lambda (a, b): similarity(a, b)
)
longer_difference.remove(item1)
shorter_difference.remove(item2)
if similarity(item1, item2) > threshold:
union_size += 1
intersection_size += 1
else:
union_size += 2
union_size = union_size + len(longer_difference)
return intersection_size / union_size
这里的问题是这是集合大小的二次方,因为在itertools.product
中我迭代从每个集合(*)中取一个的所有可能的项目对。现在,我认为我必须这样做,因为我希望将来自a
的每个项set1
与来自b
的最佳候选set2
相匹配来自a'
的{{1}}项。
我有一种感觉,应该有set1
这样做的方式,我不会抓住。你有什么建议吗?
还有其他两个问题,例如在我获得最佳匹配后重新计算每对的相似度,但我并不关心它们。
答案 0 :(得分:1)
我怀疑在一般情况下是否有O(n),但至少在大多数情况下,你可能比O(n ^ 2)好很多。
相似性是否可传递?我的意思是:你能假设距离(a,c)< =距离(a,b)+距离(b,c)?如果没有,这个答案可能不会有帮助。我正在处理像距离这样的相似之处。
尝试聚集数据:
选择半径r。基于直觉,我建议将r设置为你计算的前5个相似度的平均值的三分之一。
你在set1中选择的第一个点成为你第一个丛的中心。将set2中的点分类为在丛中(与中心点的相似性< = r)或在丛外。还要跟踪丛集中心2r范围内的点。
您可以要求丛集中心点彼此至少相距2r;在这种情况下,某些点可能不在任何丛中。我建议至少让他们互相攻击。 (如果您处理大量维度,可能会少一些。)您可以将每个点视为一个丛集中心,但是您不会节省任何处理时间。
当你选择一个新点时,首先将它与丛中心点进行比较(即使它们在同一组中)。无论是在已经存在的丛中,还是它成为一个新的丛集中心(或者如果它在一个丛集中心的r和2r之间,也可能都不是)。如果它在丛中心的r内,则将其与另一组中距离该丛中心2r范围内的所有点进行比较。您可以忽略丛中心以外的2r点以上的点。如果你在丛中没有找到类似的点(也许是因为丛没有点),那么你可能必须扫描所有其余的点。希望这只会在集合中没有多点时才会发生。如果效果很好,那么在大多数情况下,你会发现丛中最相似的点,并且知道它是最相似的点。
这个想法可能需要一些调整。
如果涉及大量的尺寸,那么你可能会发现,对于给定的半径r,令人沮丧的是,许多点在彼此的2r之内,而很少在彼此的r之内。
这是另一种算法。计算相似度函数的时间越长(与维护已排序的点列表所花费的时间相比),您可能希望拥有的索引点越多。如果您知道维度的数量,则使用该数量的索引点可能是有意义的。如果一个点与另一个索引点太相似,则可以拒绝该点作为候选索引点。
对于您使用的第一个点以及您决定用作索引点的任何其他点,生成另一个集合中所有剩余点的列表,按照与索引点的距离的顺序排序,
当您将点P1与另一组中的点进行比较时,我认为您可以跳过集合,原因有两个。考虑一下您在P1中找到的最相似的点P2。如果P2类似于索引点,则可以跳过与该索引点完全不同的所有点。如果P2与索引点不同,那么您可以跳过与该索引点足够相似的所有点。我认为在某些情况下,您可以跳过同一索引点的两种类型的点。