python中的高效字符串比较,包括数值评估

时间:2012-07-23 17:52:19

标签: python optimization string-comparison

我有两个中等大小的ascii文件,其中包含固定格式的数据。我需要测试第一个文件的一行中的6个给定字段是否匹配(在给定容差内)第二个文件的任何一行上的六个字段然后输出一个公共行以继续处理。

我目前正在使用fortran样式行读取器拆分文件中的每一行,并为每个列表中的每个元素生成一个列表正确的列表。我将两个文件中的列表列表存储在内存中,而我会对它们进行操作

我需要比较的字段都是浮点数,我目前正在使用以下类型的流程:

tol = 0.01
for entry1 in file1List:
    for entry2 in file2List:
        if (abs(entry1[1] - entry2[1]) < tol and abs(entry1[2] - entry2[2]) < tol 
            and abs(entry1[3] - entry2[3]) < tol and abs(entry1[4] - entry2[4]) < tol
            and abs(entry1[5] - entry2[5]) < tol and abs(entry1[6] - entry2[6]) < tol):
            print entry1,entry2

执行此操作对于仅包含少量行的文件很好,但超过30000行仅执行此部分超过1分钟!

我相当肯定必须有一个更快的比较方法,但我很难找到它,任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:2)

如果您可以将file1listfile2list中的元素存储为numpy数组,那么您的比较会变得更简单(也可能更快):

for entry1 in file1list:
    for entry2 in file2list:
        if(np.all(np.abs(entry1[1:7] - entry2[1:7]) > tol)):
            print entry1,entry2

转换为numpy数组是无痛的:

file1list = [ np.array(entry) for entry in file1list ]

对于已排序的file2list

,这会更好一些
file2list=sorted(file2list,key=operator.itemgetter(1,2,3,4,5,6))
for entry1 in file1list:
    for entry2 in file2list:
        d=np.abs(entry1[1:7]-entry2[1:7])
        if(np.all(d < tol)):
            print entry1,entry2
        elif(d[0] > tol):
            break 

答案 1 :(得分:1)

您当前的处理是O(n m),其中n是文件1中的行数,m是文件2中的数字。当n ~ m ~ 30,000时,它正在进行900,000,000次比较:不用担心需要一分钟!

由于允许你被一个容差所取消,这个问题变得更加复杂:如果它是完全匹配的,你可以从其中一个文件中创建一个字典,然后{{ 1}}构建字典的时间和O(m)时间进行查找,因为基于散列的字典具有常量查找。

有点类似的一种可能性是制作一个舍入值的字典,以便O(n)中的内容用相同的值键入,然后在找到时{1}}内确保所有内容都在tol内可能的比赛。你可以通过将每个条目四舍五入到比tol略大的值来做到这一点:也就是说,如果toltol,则根据舍入到1e-3的条目键。这有效程度取决于您的值与1e-2的分布情况,但它应该非常好。

也就是说,做这样的事情(未经测试,但它应该可行):

tol

答案 2 :(得分:1)

您当前方法的问题在于您将第一个文件中的每一行与第二个文件中的每一行进行比较。为了减少运行时间,你需要一种方法来短路第二个for循环,使用一些逻辑,如果“如果这个迭代符合某些条件,那么我可以打破这个循环,因为它不可能随后的条目可以匹配“。

要支持此逻辑,首先需要对两个列表进行排序,例如:

from operator import itemgetter
comp_fields = itemgetter(1, 2, 3, 4, 5, 6)
file1List.sort(key=comp_fields)
file2List.sort(key=comp_fields)
for entry1 in file1List:
    for entry2 in file2List:
        if (abs(entry1[1] - entry2[1]) < tol and abs(entry1[2] - entry2[2]) < tol 
            and abs(entry1[3] - entry2[3]) < tol and abs(entry1[4] - entry2[4]) < tol
            and abs(entry1[5] - entry2[5]) < tol and abs(entry1[6] - entry2[6]) < tol):
            print entry1,entry2
        elif entry2[1] - entry1[1] >= tol:
            # we know subsequent lines in file2List can't match due to ordering
            break

这是一个非常天真的解决方案,例如,一个可能的改进是跟踪起点,例如,如果在file1List的上一次迭代中,我们在找到一个file2List之前将2000行转换为file1List匹配,在file2List的下一次迭代中,我们可以在第2000行开始{{1}}的迭代。它也只在第一列上进行短路,并且您可以添加一些额外的逻辑让它在后续列上短路(由于存在容差而不需要完全匹配,这会变得棘手)。

答案 3 :(得分:0)

您可以根据

的值对file1List和file2List进行排序
entry1[1]^2 + entry1[2]^2 + ... + entry1[6]^2

这是六个空间中的两个矢量指标列表。给定file1List中的向量,您可以使用Newton-Raphson方法找到相同长度的向量的位置(或者也可以使用二分法:Python [已经支持] [1]。

扫描file2List中与file1List的下一个值匹配的下一个值,您只需要向前扫描,file2List中的第一个值超过tol将意味着搜索file1List的特定值的结束。

我认为原始JOIN实用程序的算法或多或少相似。