在 python 列表中查找相似条目
Posted
技术标签:
【中文标题】在 python 列表中查找相似条目【英文标题】:Finding similar entries in python lists 【发布时间】:2020-09-07 11:45:54 【问题描述】:我有 2 个元组列表 list1 = [(1.332, 3.23344, 3.22), (2.122, 2.11, 2.33), ... (1, 2, 3)]
和 list2 = [(4.23, 12.2, 3.333), (1.234, 3.21, 4.342), ... (1.1, 2.2, 3.3)]
。这些列表都很长,两个列表都有数百万。对于上下文,这些数据点中的每一个都是对两个不同数据集中的位置的某种度量。现在我想将list1
中的每个条目对应到list2
中的一个条目,如果它“足够接近”的话。足够接近是指位置之间的距离小于某个阈值(例如 0.1)。我最初的想法是在list1
的每个条目上使用min
函数。也就是如下:
import numpy as np
import random
def dist(pt1, pt2):
return np.sqrt( ((pt2[0] - pt1[0]) ** 2) + ((pt2[1] - pt1[1]) ** 2) + ((pt2[2] - pt1[2]) ** 2) )
list1 = [(random.random(), random.random(), random.random()) for _ in range(25)]
list2 = [(random.random(), random.random(), random.random()) for _ in range(20)]
threshold = .5
linker = []
for i, entry in enumerate(list1):
m = min(list2, key=lambda x: dist(entry, x))
if dist(entry, m) < threshold:
linker.append((i, list2.index(m))
所以这会将list1
中的每个索引链接到list2
中的索引。但我觉得肯定有一些已经开发出来的算法专门针对这个任务,速度要快得多,是吗?
【问题讨论】:
【参考方案1】:您正在寻找数据集中每个点与第二个数据集的最近邻。
-
您发布的方法复杂度为 O(N^2)
由于 N ~ 100 万,这变得站不住脚。
对于大型数据集nearest neighbor approaches 更好,因为它们的复杂度为 O(N*log(N))
Python 中比较流行的两个是KDTree and BallTree
使用 BallTree 解决此问题的示例
sklearn BallTree doc
import numpy as np
from sklearn.neighbors import BallTree
# Generate Dataset 1 (random positions in 3D)
rng = np.random.RandomState(0)
X = rng.random_sample((10, 3)) # 10 points in 3 dimensions
# Setup nearest neighbor tree for dataset 1
# to process nearest neighbor queries
tree = BallTree(X, leaf_size=2)
# Generate Dataset 2 (random positions in 3D)
Y = rng.random_sample((10, 3))
# For each point in Dataset 2
# find the index and distance to the closest
# point in Dataset 1 (using the nearest neighbor tree
# for dataset 1)
dist, ind = tree.query(Y, k=1) # nearest neighbor
# Results
for i, (ind, d) in enumerate(zip(ind, dist)):
print(f'Y index i, closest index X is ind, dist d')
输出
Y index 0, closest index X is [3], dist [0.14046915]
Y index 1, closest index X is [1], dist [0.40653272]
Y index 2, closest index X is [7], dist [0.29291477]
Y index 3, closest index X is [1], dist [0.25785655]
Y index 4, closest index X is [1], dist [0.39477652]
Y index 5, closest index X is [9], dist [0.50373484]
Y index 6, closest index X is [1], dist [0.24894356]
Y index 7, closest index X is [4], dist [0.14716665]
Y index 8, closest index X is [5], dist [0.25875381]
Y index 9, closest index X is [8], dist [0.24204497]
【讨论】:
【参考方案2】:是的,这绝对是一种耗时的方法,因为首先 python 没有针对这些计算(数据类型等)进行优化,其次这些计算需要在任何语言中进行优化。 您必须使用库来处理 numpy 和 pandas 等矩阵。 例如,在您的情况下,我推荐此解决方案: 首先:将您的数据转换为熊猫的数据框,如下所示: List of Tuples to DataFrame Conversion 第二:在使用熊猫进行转换之后,这是一个常规且简单的计算。 例如: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.pow.html
pandas 使用 numpy 并且 numpy 针对这些计算进行了优化。
【讨论】:
【参考方案3】:一个简单的解决方案是保留一个 3d 单元格数组以将您的条目分组。例如,(1.332, 3.23344, 3.22)
可能被分组到单元格(13, 32, 32)
。打包该数据结构后,您可以通过查看 (13, 32, 32)
(以及它的 26 个邻居的一些子集)找到 (1.332, 3.23344, 3.22)
附近的所有点。
如果您真的需要这个速度很快,那么您将进入一组称为“空间分区器”的算法。您可能会研究一种称为“kd-tree”的东西,它非常适合以超紧凑的方式存储点的非均匀分布(并且针对检索某个位置的邻域中的点进行了优化。)
【讨论】:
感谢您的回答和解释查看 kd-trees :)以上是关于在 python 列表中查找相似条目的主要内容,如果未能解决你的问题,请参考以下文章