python - Numpy在二维数组中查找公共点的索引
问题描述
系统
操作系统: Windows 10 (x64),Build 1909
Python 版本: 3.8.10
Numpy 版本: 1.21.2
问题
给定两个浮点数据点的 2D (N, 3)
Numpy 数组,(x, y, z)
在一个数组中查找点与另一个数组中的点相等的索引的 Pythonic(矢量化)方法是什么?
(注意: 我的问题不同之处在于我需要它来处理实际数据集,其中两个数据集可能因浮点错误而有所不同。请阅读下面的详细信息。)
历史
类似的问题已经被问过很多次了:
- 如何找到另一个二维数组中出现的二维numpy数组的索引
- 测试二维 numpy 数组中的成员资格
- 获取 Numpy 2d 数组相交行的索引
- 在另一个二维数组中查找 numpy 二维数组行的索引
- Numpy 2d Array 相交行的索引
- 在另一个二维数组中查找 numpy 二维数组行的索引
以前的尝试
SO Post 1提供了一个工作列表理解解决方案,但我正在寻找一种能够很好地扩展到大型数据集(即数百万点)的解决方案:
代码1:
import numpy as np
if __name__ == "__main__":
big_array = np.array(
[
[1.0, 2.0, 1.2],
[5.0, 3.0, 0.12],
[-1.0, 14.0, 0.0],
[-9.0, 0.0, 13.0],
]
)
small_array = np.array(
[
[5.0, 3.0, 0.12],
[-9.0, 0.0, 13.0],
]
)
inds = [
ndx
for ndx, barr in enumerate(big_array)
for sarr in small_array
if all(sarr == barr)
]
print(inds)
输出1:
[1, 2]
尝试SO Post 3的解决方案(类似于SO Post 2),但使用浮点数不起作用(我怀疑np.isclose
需要使用一些东西):
代码3:
import numpy as np
if __name__ == "__main__":
big_array = np.array(
[
[1.0, 2.0, 1.2],
[5.0, 3.0, 0.12],
[-1.0, 14.0, 0.0],
[-9.0, 0.0, 13.0],
],
dtype=float,
)
small_array = np.array(
[
[5.0, 3.0, 0.12],
[-9.0, 0.0, 13.0],
],
dtype=float,
)
inds = np.nonzero(
np.in1d(big_array.view("f,f").reshape(-1), small_array.view("f,f").reshape(-1))
)[0]
print(inds)
输出3:
[ 3 4 5 8 9 10 11]
我的尝试
我试过numpy.isin
和np.all
np.argwhere
inds = np.argwhere(np.all(np.isin(big_array, small_array), axis=1)).reshape(-1)
哪个有效(并且,我认为,更具可读性和可理解性;即pythonic),但不适用于包含浮点错误的真实数据集:
import numpy as np
if __name__ == "__main__":
big_array = np.array(
[
[1.0, 2.0, 1.2],
[5.0, 3.0, 0.12],
[-1.0, 14.0, 0.0],
[-9.0, 0.0, 13.0],
],
dtype=float,
)
small_array = np.array(
[
[5.0, 3.0, 0.12],
[-9.0, 0.0, 13.0],
],
dtype=float,
)
small_array_fpe = np.array(
[
[5.0 + 1e-9, 3.0 + 1e-9, 0.12 + 1e-9],
[-9.0 + 1e-9, 0.0 + 1e-9, 13.0 + 1e-9],
],
dtype=float,
)
inds_no_fpe = np.argwhere(np.all(np.isin(big_array, small_array), axis=1)).reshape(-1)
inds_with_fpe = np.argwhere(
np.all(np.isin(big_array, small_array_fpe), axis=1)
).reshape(-1)
print(f"No Floating Point Error: {inds_no_fpe}")
print(f"With Floating Point Error: {inds_with_fpe}")
print(f"Are 5.0 and 5.0+1e-9 close?: {np.isclose(5.0, 5.0 + 1e-9)}")
输出:
No Floating Point Error: [1 3]
With Floating Point Error: []
Are 5.0 and 5.0+1e-9 close?: True
如何通过合并使我的上述解决方案工作(在具有浮点错误的数据集上)np.isclose
?欢迎替代解决方案。
注意: 由于small_array
是 的子集big_array
,因此无法直接使用,np.isclose
因为形状不会广播:
np.isclose(big_array, small_array_fpe)
产量
ValueError: operands could not be broadcast together with shapes (4,3) (2,3)
更新
目前,我唯一可行的解决方案是
inds_with_fpe = [
ndx
for ndx, barr in enumerate(big_array)
for sarr in small_array_fpe
if np.all(np.isclose(sarr, barr))
]
解决方案
我不会给出任何代码,但我已经大规模处理过类似的问题。我怀疑要使用这些方法中的任何一种获得不错的性能,您需要在 C 中实现核心(您可能会使用 numba)。
如果您的两个阵列都很大,那么有几种方法可以工作。这些主要归结为构建一个结构,该结构可用于从其中一个数组中找到一个点的最近邻居,然后查询另一个数据集中的每个点。
为此,我之前使用了 Kd Tree 方法和基于网格的方法。
基于网格的方法的基础是
- 找到你的第一个数组的 3D 范围。
- 将该区域分成 L N M 个 bin。
- 对于第二个数组中的每个输入点,找到它的 bin。任何与它匹配的点都将在该 bin 中。
您需要处理的边缘情况是
- 如果该点落在一个 bin 的边缘,或者足够接近被认为等于它的 bin 的边界,则可能落在另一个 bin 中 - 那么您需要搜索多个 bin 来寻找它的“相等”。
- 如果该点落在所有 bin 之外,但靠近边缘,则“等于”它的点可能落在附近的 bin 中。
缺点是这对非均匀分布的数据不利。
好处是它相对简单。统一数据的预期运行时间为n1 * n2 / (L*N*M)
(与 n1*n2 相比)。通常,您选择 L,N,M 以使其变为O(n log(n))
。您还可以从对第二个数组进行排序以提高 bin 的重用性获得进一步的提升。并行化也相对容易(分箱和搜索)
Kd 树方法是类似的。IIRC 它提供了O(n log(n))
行为,但实现起来比较棘手,并且数据结构的构建很难并行化)。它往往对缓存不友好,这可能意味着尽管它的渐近运行时间比基于网格的方法更好,但它在实践中可能运行得更慢。然而,它确实为非均匀分布的数据提供了更好的保证。
推荐阅读
- flutter - Flutter中删除库的版本号有什么作用
- matlab - 为 writematrix 设置回车类型
- database - 行 ID 与位图索引一起存储在哪里?
- docker - 如何通过 RabbitMQ docker 禁用明文身份验证?
- python - 在python中附加具有不同列的excel文件
- python - 如何让母球移动到给定的航向?
- java - 具有枚举类型字段的 Java 枚举
- python - 如何将多个表格从 Excel 转换为 JSON
- gem5 - 如何在 gem5 中实现完美的分支预测器
- sql-server - SSIS 从带有 Where 条件的 Excel 工作表中选择