【问题标题】:can I do fast set difference with floats using numpy if elements are equal up to some tolerance如果元素等于某个容差,我可以使用 numpy 对浮点数进行快速设置差异吗
【发布时间】:2014-06-15 20:48:50
【问题描述】:

我有两个浮点数列表,我想计算它们之间的差值。

我最初使用 numpy 编写了以下代码:

aprows = allpoints.view([('',allpoints.dtype)]*allpoints.shape[1])
rprows = toberemovedpoints.view([('',toberemovedpoints.dtype)]*toberemovedpoints.shape[1])
diff = setdiff1d(aprows, rprows).view(allpoints.dtype).reshape(-1, 2)

这适用于整数之类的东西。如果 2d 点的浮点坐标是某些几何计算的结果,则存在有限精度和舍入误差的问题,导致设置的差异错过了一些等式。现在我使用了慢得多的方法:

diff = []
for a in allpoints: 
    remove = False
    for p in toberemovedpoints:
        if norm(p-a) < 0.1:
            remove = True
    if not remove:
        diff.append(a)
return array(diff)

但是有没有办法用 numpy 写这个并恢复速度?

请注意,我希望剩余的点仍然具有完整的精度,所以首先对数字进行四舍五入然后做一个设定的差异可能不是前进的方向(或者是吗?:))

编辑添加了一个基于 scipy.KDTree 的解决方案,似乎可行:

def remove_points_fast(allpoints, toberemovedpoints):
    diff = []
    removed = 0
    # prepare a KDTree
    from scipy.spatial import KDTree
    tree = KDTree(toberemovedpoints,  leafsize=allpoints.shape[0]+1)
    for p in allpoints:
        distance, ndx = tree.query([p], k=1)
        if distance < 0.1:
            removed += 1
        else:
            diff.append(p)
    return array(diff), removed

【问题讨论】:

  • from scipy.spatial import cKDTree as KDTree 是一个更快的 cython KDtree。

标签: python numpy floating-point-precision set-difference


【解决方案1】:

如果您想使用矩阵形式执行此操作,则较大的数组会消耗大量内存。如果这无关紧要,那么您可以通过以下方式获得差异矩阵:

diff_array = allpoints[:,None] - toberemovedpoints[None,:]

结果数组的行数与 allpoints 中的点数一样多,列数与 tobermovedpoints 中的点数一样多。然后你可以用任何你想要的方式来操作它(例如计算绝对值),这会给你一个布尔数组。要查找哪些行有任何命中(绝对差异 numpy.any:

hits = numpy.any(numpy.abs(diff_array) < .1, axis=1)

现在你有了一个向量,它的项数与差异数组中的行数相同。您可以使用该向量来索引所有点(否定,因为我们想要不匹配的点):

return allpoints[-hits]

这是一种麻木的方式。但是,正如我上面所说,它需要大量内存。


如果您有更大的数据,那么您最好逐点进行。像这样的:

return allpoints[-numpy.array([numpy.any(numpy.abs(a-toberemoved) < .1) for a in allpoints ])]

这在大多数情况下应该表现良好,并且内存使用比矩阵解决方案低得多。 (出于文体原因,您可能希望使用 numpy.all 而不是 numpy.any 并翻转比较以摆脱否定。)

(请注意,代码中可能存在打印错误。)

【讨论】:

  • 感谢您的解决方案@DrV 我需要调查为什么它会在我的代码中造成一些问题(但我很确定错误会在我这边,因为您的解决方案看起来很优雅)。
  • 我有打印错误和愚蠢思维错误的倾向。将其分成小块并使用简单的数字示例来消除皱纹。我在最后一行更正了一个(将转换添加到数组中)。如果您对我的代码有任何其他问题,请告诉我。
  • 今晚我似乎真的有这种倾向。现在代码也已经测试过了:)
  • 如果内存是diff_array 的问题,那么先过滤掉明显的故障怎么样。例如,将值缩放为整数,在一维中执行setdiff1d。在第二次重复通过的值。然后在剩下的地方做diff_array
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多