我有大量的对象,我需要弄清楚它们之间的相似之处。
准确地说:给定两个对象,我可以将它们的不相似性计算为数字,metric - 较高的值表示较少的相似性,0表示对象具有相同的内容。计算此数字的成本与较小对象的大小成比例(每个对象具有给定的大小)。
我需要能够在给定对象的情况下快速找到与其类似的对象集。
确切地说:我需要生成一个数据结构,将任何对象映射到对象集合,与o不同,对于某些不相似度值d,这样列出集合中的对象不再需要时间比如果他们在数组或链表中(也许他们实际上是)。通常,该集合将远小于对象的总数,因此执行此计算确实是值得的。如果数据结构采用固定的d,那就足够了,但如果它适用于任意d,那就更好了。
你以前见过这个问题,还是类似的问题?什么是好的解决方案?
确切地说:一个直接的解决方案涉及计算所有对象之间的不相似性,但这很慢 - O(n 2 )其中n是对象的数量。是否存在复杂度较低的通用解决方案?
答案 0 :(得分:2)
我需要生成一个数据结构 将任何对象o映射到该集合 对象与o不同于 d,对于某些不相似的值d。
当小计变得大于d
时,放弃相似度计算可能是最快的。例如,如果您的相似性基于余弦或hausdorff距离,则可以轻松完成。
PS:如果无法做到这一点,你的问题可能与k-最近邻居问题有关(或者更确切地说是与阈值邻域的最近邻居问题)。您应该寻找能够在不计算所有距离的情况下找到附近成员的算法(可能使用三角不等式)。维基百科应该帮助您探索合适的算法。
答案 1 :(得分:1)
如果您的相似性度量是可传递的,则不必计算所有对象对的相似性,因为对象a,b,c:
similarity(a,c) = similarity(a,b) op similarity(b,c)
其中op
是二元运算符,例如乘法或加法。
答案 2 :(得分:1)
在不了解指标的更多细节的情况下,很难说。我没有任何关于消除O(n ^ 2)方面的想法,但可能有一种方法可以减少所涉及的一些常量。例如,如果您有欧几里德度量d(p,q)= sqrt((p_1-q_1)^ 2 + .. +(p_n-q_n)^ 2),您可以将距离d平方并将其与部分距离进行比较(p_i-q_i)^ 2的和,当你超过d ^ 2时停止。
这实际上是否会节省您的时间取决于比较对于计算命令的成本以及您可以期望通过这样做避免多少个加数计算(显然,d越小越好)。
答案 3 :(得分:1)
我认为解决方案取决于有关问题性质的更多细节。
您是否需要多次为同一个对象找到相似的对象,或者只需要查找一次?如果它已经多次,那么创建一个数据结构,您可以为每个对计算一次差异,然后将对象连接到类似对象,以便您可以快速检索列表而无需重新计算,这可能是一个非常有用的性能增强。
计算的性质是什么?在一个极端情况下,如果差异的性质是,例如,两个人之间的高度差异,那么维护按高度排序的列表将使您能够非常快速地找到相似的对象。我假设真正的问题比这更复杂,但是遵循这个逻辑,如果差异是几个线性量的总和,你可以创建一个多维数组,然后在概念上想象一组类似的对象作为那些在以参考物体为中心的n维球体(即圆形,球形,超球形等)内,并再次直接找到它们。实际上,如果半径计算太复杂或者运行时间过长,我会发现,一个很好的近似是在参考对象周围创建一个n维立方体(即方形,立方体,tesseract等),检索所有位于该立方体内的对象作为“候选人”,然后对候选人进行实际计算。
例如,假设“差异”是三个属性(例如a1,a2和a3)差异的绝对值之和。您可以创建一个三维数组,并使用这些值(如果有)将数组的每个节点的值设置为对象。然后,如果要从对象o中找到差异小于d的所有对象,可以写:
for (x1=o.a1-d;x1<o.a1+d;++x1)
{
for (x2=o.a2-d;x1<o.a2+d;++x2)
{
for (x3=o.a3-d;x1<o.a3+d;++x3)
{
if (array[x1][x2][x3]!=null
&& (abs(x1-o.a1)+abs(x2-o.a2)+abs(x3-o.a3)<=d)
{
... found a match ...
}
}
}
}
我怀疑差异规则比这更复杂,但很好,只是增加算法的复杂性以匹配规则的复杂性。关键是要使用数组来限制你必须检查的对象集。
答案 4 :(得分:1)
是否无法使用 k d-tree?
可能需要(如果可能)规范尺寸。之后,您只需要填充树,并使用“最近的N邻居”搜索,并尝试在某个范围内找到任何对象。
答案 5 :(得分:1)
对象示例: 图像,文件。当然,使用这些对象的原始表示大多没有用。通常会预先处理原始形式并将其转换为某种标准化形式(对于文档,例如,每个条目代表某个单词出现的次数/百分比的向量,对于图像,它可以表示找到的视觉特征在图像中)。
如果d是固定的并且n ^ 2预计算是可行的,则可以使用例如每个对象的链表来使用图表表示。 使用近似最近邻算法,您可以以精确度为代价获得更有效的解决方案。
答案 6 :(得分:0)
我们可以假设相似性是可传递的,即。 diff(a,c) == diff(a,b) + diff(b,c)
?如果是这样,您可以尝试以下方法:
s
至o
的对象,请在排序列表中找到o
,然后向左和向右搜索,直到差异大于{{1 }}。这样做的好处是排序可以完成一次,后续的设置构建与集合中的成员数量成比例。
答案 7 :(得分:0)
听起来像BK-Tree。 Here is a small example。你基本上创建树并检查哪个分支应该用于类似的对象搜索,哪些不是,所以你要阻止O(n2)