两组间隔的相似性

时间:2016-11-04 17:58:24

标签: algorithm precision intervals interval-intersection

可以使用哪种算法/解决方案来指示两组范围的相似性(重叠/精确度/召回/ ...)。

我可以想到(或在网上找到)数百个类似的问题,但从来没有确切,但肯定是这个" wheel"必须已经发明了......

让我们说输入数据类似于:

Real      [ ## ###  #     ] or [(1,2),(4,6),(9,10)]  
Predicted [ ## #          ] or [(1,2),(4,4)]  

输出应为~50%

我应该使用例如AND位图,使用间隔树或什么? 是否有一个很好的功能或简单的算法?任何有意义的相似性度量都可以,任何合理的输入格式也是如此。

谢谢。

(实际长度~4000,每组<50个间隔)

3 个答案:

答案 0 :(得分:1)

尽管您在评论中表示担心区间交叉算法很复杂,但事实并非如此。这里的矿井适合于通过计算交叉口的大小而不是其中的实际间隔来确定相似性。它具有很好的对称性。

该算法为O(| a | + | b |),假设输入间隔已经排序。

def similarity(a, b):
  ia = ib = prevParity = unionLen = isectLen = 0
  while True:
    aVal = a[ia / 2][ia % 2] if ia < 2 * len(a) else None
    bVal = b[ib / 2][ib % 2] if ib < 2 * len(b) else None
    if not aVal and not bVal: break
    if not bVal or aVal < bVal or (aVal == bVal and ia % 2 == 0):
      parity = prevParity ^ 1
      val = aVal
      ia += 1
    else:
      parity = prevParity ^ 2
      val = bVal
      ib += 1
    if prevParity == 0: unionStart = val
    elif parity == 0: unionLen += val - unionStart + 1
    if parity == 3: isectStart = val
    elif prevParity == 3: isectLen += val - isectStart + 1
    prevParity = parity
  return (0.0 + unionLen - isectLen) / unionLen

print similarity(a, b)

注意这是计算@TimothyShields提出的Jaccard索引,但它的运行时间和空间取决于间隔的数量,其中取决于间隔的总大小

答案 1 :(得分:0)

您可以将细分分为单个点,并将每个点标记为实际/预测和开始/结束。

然后对点进行排序,遍历排序列表并跟踪重叠。

您甚至无需跟踪间隔是否来自RealPredicted - 您只需要跟踪每个点是否有一个或两个间隔。

示例:

Real      [(1,2),(4,6),(9,10)]  
Predicted [(1,2),(4,4)]  

分解为点并排序(S表示开始,E表示结束):

[(1,S),(1,S),(2,E),(2,E),(4,S),(4,S),(4,E),(6,E),(9,S),(10,E)]

然后浏览数组 - 跟踪“打开”的段数,并计算total open2 segments open的长度。

结果为2 segments open / total open

答案 2 :(得分:0)

您可以使用Jaccard index来衡量相似度,也称为“交叉过度”。它是0到1之间的数字,其中0表示“这两个集合根本不重叠”,1表示“这两个集合完全相同。”

在Python 3中,它易于实现:

def jaccard(A, B):
    if A or B:
        return len(A & B) / len(A | B)
    else:
        return 1.0

AB是两组值。虽然理论上不是最佳的,但以下方法可能足够快,足以满足您的需求。

real = [(1,2), (4,6), (9,10)]  
predicted = [(1,2), (4,4)]
real_set = set(x for a, b in real for x in range(a, b + 1))
predicted_set = set(x for a, b in predicted for x in range(a, b + 1))
print(jaccard(real_set, predicted_set))

这将为您提供0.5

用于计算线段的交集和并集的更有效的算法确实存在,其中没有中间转换为整数元素的枚举,但我会坚持这种更简单的方法,除非你有线段{{ 1}}其中(a,b)是一个非常大的数字。