在 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 列表中查找相似条目的主要内容,如果未能解决你的问题,请参考以下文章

我可以使用啥正则表达式在逗号分隔列表中查找 Nᵗʰ 条目?

在 Python 中查找将一个集群列表转换为另一个集群的映射

使用二分搜索查找多个条目

在 Python 中迭代和更改嵌套列表条目

从Java中具有不同大小的2个数组列表中查找非相似元素

Python,查找范围是否包含范围列表中的另一个较小范围