【问题标题】:Find matching points in 2 separate numpy arrays在 2 个单独的 numpy 数组中查找匹配点
【发布时间】:2015-04-08 16:04:00
【问题描述】:

我有两个包含 3d 点的不同大小的数组。我想有效地比较两个数组并找到匹配的点并最终返回一个简单数量的匹配点。

pA=[[0,0,0],[0,1,0],[1,2,4],[10,3,4],[1,20,1],[5,3,2]]
pB=[[14,1,0],[1,2,4],[1,20,1],[15,1,0]]

#returns 2

目前我有一个草率的循环来解决这个问题,但考虑到我正在尝试匹配具有大量点的多对数组,它对性能不是很友好,这是一个问题

t= np.array([pA[x]==pB for x in range(len(pA))]).sum(2)
print np.sum(t==3)

我只是不确定如何有效地比较两个不同大小的多维数组。然后是如何对大量对进行多次迭代。

编辑

找到了一种解决方法,该方法非常快,可以组合数组,制作数组的唯一版本,然后比较两个数组的长度。

pts=np.concatenate((pA,pB),axis=0)
pts2 = np.unique(pts.view([('', pts.dtype)]*pts.shape[1]))
return len(pts)-len(pts2)

【问题讨论】:

  • 每个列表中会不会有重复的点?

标签: python arrays performance numpy compare


【解决方案1】:

不知道这如何在您的完整数据集上执行,但请尝试使用 Scipy 的 kdtree:

from scipy.spatial import cKDTree

pA=[[0,0,0],[0,1,0],[1,2,4],[10,3,4],[1,20,1],[5,3,2]]
pB=[[14,1,0],[1,2,4],[1,20,1],[15,1,0]]

kdtree = cKDTree(pA)
dists, inds = kdtree.query(pB, distance_upper_bound=1e-5)
result = (dists == 0).sum()

【讨论】:

  • Scipy 似乎有一些工具可以很好地解决这个问题。唯一的问题是这是一个要在 Autodesk Maya 中运行的脚本,我需要为这个特定的 Maya 版本编译 Scipy 模块(我没有这样做的经验)。如果有必要,可能不会太难。
  • 我明白了。那么 numpy 是否与 Maya 一起使用?
  • Numpy 我找到了 Maya 的编译版本。在我短暂的搜索中,我找不到 Scipy 的。不过,我可能需要付出更多努力才能让 Scipy 在 Maya 中工作,因为据我所知,它似乎有一些更好的 3D 功能。
  • 你可能会幸运地使用这样的纯 Python 实现:github.com/stefankoegl/kdtree。或者也许还有另一种简单有效的方法。不过,值得在问题中提及您的 Maya 约束。
  • 似乎 kdtree 对于numpy 非常有用。很高兴知道它!
【解决方案2】:

这是一种仅使用 numpy 操作的方法。这里的基本思想是我们将这两个列表连接成一个 numpy 数组。然后,我们按行对其进行排序,以将匹配点放在连续的行中。接下来,我们使用diff 来获取匹配行的所有零行,这是由np.all(...==0,1)提取的。我们对所有这些事件进行计数,以便为我们提供这两个列表之间匹配点计数的所需输出。

下面列出了实现-

import numpy as np

# Inputs
pA=[[0,0,0],[0,1,0],[1,2,4],[10,3,4],[1,20,1],[5,3,2]]
pB=[[14,1,0],[1,2,4],[1,20,1],[15,1,0]]

# Form concatenate array of pA and pB
pts = np.concatenate((pA,pB),axis=0)

# Sort pts by rows
spts = pts[pts[:,1].argsort(),]

# Finally get counts by DIFFing along rows and counting all zero rows
counts = np.sum(np.diff(np.all(np.diff(spts,axis=0)==0,1)+0)==1)

输出 -

In [152]: counts
Out[152]: 2

即使您在任一列表中有重复的点,上述代码也有效。所以,让我们在前面代码的输入中添加一些重复的点 -

# Inputs
pA=[[0,0,0],[0,1,0],[1,2,4],[10,3,4],[1,20,1],[5,3,2],[1,2,4]]
pB=[[14,1,0],[1,2,4],[1,20,1],[15,1,0],[1,2,4]]

使用修改后的输入运行代码后,输出仍保持为2,这是预期的输出。

如果您确定任一列表中没有重复条目,可以使用简化版本替换最后一步-

counts = np.sum(np.all(np.diff(spts,axis=0)==0,1))

【讨论】:

  • 这个想法基本上是我目前正在使用的,虽然我相信你的更优雅。我的变体连接数组,然后创建一个删除所有重复条目的新数组,并比较两个数组长度以获得数字。 pts=np.concatenate((pA,pB),axis=0) pts2 = np.unique(pts.view([('', pts.dtype)]*pts.shape[1])) counts = len(pts)-len(pts2)
  • @AlexRideout 是的,all + diff 部分本质上是uniqueraw 版本中找到的,并且可能是有效的,因为它还避免了中间变量的创建。在对没有重复条目的列表的解决方案的新编辑结束时添加了简化版本。只是好奇,您是否有机会测试这些方法的运行时性能?
  • 你的方法肯定比我的unique 方法更优雅。就确切的时间而言,我还没有机会进行任何官方测量。大多数人只对我的 Maya 场景中的几何图形进行了主观测试。我目前正在使用一个循环来遍历我生成的所有点数组对(也许是某种方式来对该步骤进行矢量化?)这大约每秒运行 6,000 对,这对于我的实现来说是可以接受的。虽然我已经处理了超过 200,000 双,但并不完美。
猜你喜欢
  • 2014-11-07
  • 1970-01-01
  • 2018-02-22
  • 2015-08-05
  • 2016-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-12
相关资源
最近更新 更多