python - 通过允许容差匹配两个包含稍微不同的浮点值的列表
问题描述
我有两个包含浮点值的排序列表。第一个包含我感兴趣的值 ( l1
),第二个列表包含我想要搜索的值 ( l2
)。但是,我不是在寻找精确匹配,而是容忍基于函数的差异。由于我经常进行此搜索(>>100000)并且列表可能非常大(~5000 和~200000 个元素),我对运行时非常感兴趣。起初,我以为我可以以某种方式使用numpy.isclose()
,但我的容忍度不是固定的,而是取决于感兴趣的值。几个嵌套的 for 循环工作,但真的很慢。我确信有一些有效的方法可以做到这一点。
#check if two floats are close enough to match
def matching(mz1, mz2):
if abs( (1-mz1/mz2) * 1000000) <= 2:
return True
return False
#imagine another huge for loop around everything
l1 = [132.0317, 132.8677, 132.8862, 133.5852, 133.7507]
l2 = [132.0317, 132.0318, 132.8678, 132.8861, 132.8862, 133.5851999, 133.7500]
d = {i:[] for i in l1}
for i in l1:
for j in l2:
if matching(i, j):
d[i].append(j)
仅供参考:作为匹配功能的替代方案,我还可以先创建一个字典,将感兴趣的值从我允许l1
的窗口映射。(min ,max)
例如{132.0317:(132.0314359366, 132.0319640634), ...}
,但我认为检查每个值l2
是否位于该字典中的一个窗口内会更慢......
这将是如何为 l1 中的每个值生成包含最小/最大值的字典:
def calcMinMaxMZ(mz, delta_ppm=2):
minmz = mz- (mz* +delta_ppm)/1000000
maxmz = mz- (mz* -delta_ppm)/1000000
return minmz, maxmz
minmax_d = {mz:calcMinMaxMZ(mz, delta_ppm=2) for mz in l1}
结果可能是这样的字典:
d = {132.0317: [132.0317, 132.0318], 132.8677: [132.8678], 132.8862: [132.8862, 132.8861], 133.5852: [133.5851999], 133.7507: []}
但实际上,当有匹配时,我会做更多的事情。
任何帮助表示赞赏!
解决方案
我重新实现了 for 循环使用itertools
. 为了使其正常工作,必须对输入进行排序。对于基准测试,我从 <130.0, 135.0> 生成了 1000 个项目,从 <130.0, 135.0> 生成了l1
100_000 个项目l2
:
from timeit import timeit
from itertools import tee
from random import uniform
#check if two floats are close enough to match
def matching(mz1, mz2):
if abs( (1-mz1/mz2) * 1000000) <= 2:
return True
return False
#imagine another huge for loop around everything
l1 = sorted([uniform(130.00, 135.00) for _ in range(1000)])
l2 = sorted([uniform(130.00, 135.00) for _ in range(100_000)])
def method1():
d = {i:[] for i in l1}
for i in l1:
for j in l2:
if matching(i, j):
d[i].append(j)
return d
def method2():
iter_2, last_match = tee(iter(l2))
d = {}
for i in l1:
d.setdefault(i, [])
found = False
while True:
j = next(iter_2, None)
if j is None:
break
if matching(i, j):
d[i].append(j)
if not found:
iter_2, last_match = tee(iter_2)
found = True
else:
if found:
break
iter_2, last_match = tee(last_match)
return d
print(timeit(lambda: method1(), number=1))
print(timeit(lambda: method2(), number=1))
印刷:
16.900722101010615
0.030588202003855258
推荐阅读
- oop - 关于何时使用 lua 冒号语法的问题
- reactjs - 为什么反应组件CSS会覆盖另一个组件的CSS
- javascript - 按键分组,其中键是动态的
- android - Gradle 同步失败:安装项目失败:RunConfigurationChecker
- fortran - 关于 fortran 到 python/numpy 的探索性问题
- javascript - FirebaseError:时间戳超出范围
- perl - 嵌套的 if 循环未按预期计算
- stripe-payments - 创建新的 Stripe 订阅时如何向 SetupIntent 提供 return_url?
- database-design - 如何将我的表转换为规范化结构?
- php - JWT 和 PHP:验证传递的令牌 (Lcobucci\JWT)