【问题标题】:Finding the Most Similar Match in a Set在一组中找到最相似的匹配
【发布时间】:2012-11-01 22:44:44
【问题描述】:

我有一个动物数据库,每个动物都有许多属性,范围从 0 到 1——这些属性是大小、速度、毛羽等。给定一组输入属性和每种属性的权重,我需要在一组动物中找到“最接近”的匹配项。有没有一种算法可以在 O(n) 时间内完成这个任务?

我特别想做的是为游戏中的遗传算法生成的“动物”找到合适的纹理,方法是将它们与已经存在的动物相匹配。我所说的“最接近”是指属性差异的加权和最小的动物。数据库和权重在应用程序启动时是已知的,因此可以投入大量时间来准备数据。

根据用户偏好,我找到了关于字符串匹配和产品匹配的算法,但要么我没有找到我正在寻找的东西,要么我不明白如何将这些概念重新应用到我的困境中。也许图论世界有什么东西可以帮助我?

任何帮助将不胜感激!

【问题讨论】:

  • 答案总是liger
  • @A.韦伯:哦,一个恒定时间的解决方案。感谢大家的回复,如果有什么我可以做的来改善这个问题(以便其他有类似问题的人可以找到它),请告诉我!

标签: database algorithm search


【解决方案1】:

您可以将项目视为高维空间中的点,并将它们全部插入到 BSP 树中,例如k-d tree。要使用属性权重,只需将它们乘以相应的坐标即可:(w1*x, w2*y, ...)

准备工作:(来自wikipedia,python代码)

def kdtree(point_list, depth=0):

    if not point_list:
        return None

    # Select axis based on depth so that axis cycles through all valid values
    k = len(point_list[0]) # assumes all points have the same dimension
    axis = depth % k

    # Sort point list and choose median as pivot element
    point_list.sort(key=lambda point: point[axis])
    median = len(point_list) // 2 # choose median

    # Create node and construct subtrees
    node = Node()
    node.location = point_list[median]
    node.left_child = kdtree(point_list[:median], depth + 1)
    node.right_child = kdtree(point_list[median + 1:], depth + 1)
    return node

搜索:(来自gist,基于wikipedia algorithm

# method of the Node-class

def closest_point(self, target, point, best=None):
    if target is None:
        return best

    if best is None:
        best = target

    # consider the current node
    if distance(target, point) < distance(best, point):
        best = target

    # search the near branch
    best = self.child_near(point).closest_point(point, best)

    # search the away branch - maybe
    if self.distance_axis(point) < distance(best, point):
        best = self.child_away(point).closest_point(target, point, best)

    return best

了解更多:

【讨论】:

  • 这看起来很有希望,谢谢!将其诊断为“最近邻”问题正是我所需要的,即使我最终没有使用 k-d 树。
【解决方案2】:

如果您可以花时间整理数据,您可以按分数对动物进行排序(在O(nlogn) 时间,但只完成一次),然后应用对分数进行二分搜索 strong> 在O(logn) 时间找到最接近的匹配项。

如果您从 SQL 数据库中获取动物列表,则可以通过在查询中使用 ASCDESC 关键字来获取排序列表。

【讨论】:

  • 这将解决一个一维问题——单一属性。你如何扩展它来解决m维问题?在每个维度中找到最接近的匹配通常不会这样做。
  • 很难看出评分函数会允许您只排序一次并搜索任意数量的动物(输入属性)。似乎评分功能将基于动物(输入属性)。那么,这是一个O(n log n) 解决方案——为您正在寻找的每只动物重新评分和重新排序——还是您有其他想法?
  • 我认为这行不通,因为对于所有可能的输入,没有绝对的顺序可以强加给动物(因为有多个属性。)但是,我确实想知道是否将动物安排成多个最小/最大树(每个属性一个)可能会产生有用的东西......
  • @A.Webb 正如 OP 所说的“每个属性都有属性和权重”,我认为每只动物的分数是其加权属性的总和。
【解决方案3】:

您可以将其视为最大权重匹配问题,但找到最小此类匹配的复杂性下限将比O(n) 差得多。更像O(n^3)

如果我必须尝试解决这个问题,我会考虑根据权重成对匹配相同类型的属性(即,在输入的“hairy”属性和数据中的每个其他“hairy”属性之间创建加权边设置,使用输入权重的某个因子以及查询“hairy”值与匹配的“hairy”值之间的差异的倒数)。此时,您可以合并所有通往特定动物的边缘,并将边缘权重的总和作为匹配分数。

例如:

Monkey:  
A1: 0.5 
B1: 0.25
C1: 1.0

Giraffe:
A2: 0.2
C2: 0.9
D2: 0.1

Input query:
Ai: 0.4 with weight 0.8
Di: 0.2 with weight 0.25

所以我们创建了以下图表:

Ai --> A1 with weight 0.8 * 1/abs(0.5-0.4) (i.e., 8.0)
Ai --> A2 with weight 0.8 * 1/abs(0.2-0.4) (i.e., 4.0)

Di --> D2 with weight 0.25 * 1/abs(0.1-0.2) (i.e., 2.5)

然后我们折叠同一目标动物中具有属性的所有边,以获得我们的候选者:

Monkey: 8.0
Giraffe: 4.0 + 2.5

它并不漂亮,而且比O(n) 更差(可能是m 的某个因素,其中m 是您尝试匹配的属性数量),但这可能是一个起点开始优化更好的解决方案。

【讨论】:

  • 没错,最坏的情况非常糟糕,但如果有某种方法可以将其转换为图遍历,我敢打赌平均情况将几乎是恒定的如果我们开始生成动物的“父母”节点(因为在遗传算法中,孩子通常只会稍微偏离其父母。)嗯...
  • 实际上,生成输入属性与动物属性之间的关系恰好是动物数量的O(n*m)。除此之外,折叠和排序生成的关系可能被视为一个小的常数因素。诀窍可能是将计算出的相似度分数添加回图表中,以便使用这些链接来保存对多个查询的重复重新计算?
【解决方案4】:

如何找到线性反转的数量?因此,您将拥有 2 只动物的线性数据集,并且您想通过对它们进行排序来了解它们的相似或不同之处。复杂性与归并排序相同。对于“n”只动物,您将计算 nC2 倒位。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    • 2020-03-14
    • 1970-01-01
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多