如何在Python编程中减少for循环的数量以缩短运行时间?

时间:2014-01-14 07:11:38

标签: python python-2.7

我正在研究Python编程。 问题是我的代码太慢,无法在几天内获取数据。

我的代码如下。而词典数据就像这样; dic [0] = ['happy',100,[1234,1245,1515,1785,...... up to 100]]也就是说,dic [0] [1]表示dic [0]的长度[2] ]。我想要做的是计算DICE系数(单词相似度)(dic [i] [0]表示一个单词(在上面的例子中,'happy'),dic [i] [1]表示dic [i]的长度] [2](只是len(dic [i] [2])),dic [i] [2]表示该单词(dic [i] [0])出现的行号列表。这里的行仅表示语料库中的行号)

以这种方式计算DICE系数:句子中两个单词(word1,word2)的出现次数/(word1的总出现次数+ word2的总出现次数)。

总数据很大。我的程序已经工作了2天..但还没有结果......我必须尽快使用结果,因为这项工作的截止日期是下周...

我可以立即实施任何替代(更好)的算法吗? 谢谢。

for j in range(len(dic)):
            for k in range(len(dic)):

                score_temp = 0

                for r in range(len(dic[j][2])):
                    if(dic[j][2][r] in dic[k][2]):
                        score_temp += 1
                score_final = float(score_temp) / (dic[j][1] + dic[k][1])
                dice_cursor.execute('insert into dices values(?,?,?)', (dic[j][0], dic[k][0], score_final))

2 个答案:

答案 0 :(得分:3)

问题不是你的算法;这是你的数据结构。

如果我了解您的问题,则必须迭代所有j, k组合;根本没有办法解决这个问题。因此,可能的最佳算法将是dic的长度的二次方。

然而,对于每一对,您反复为dic[j][2][r] in dic[k][2]进行一系列线性搜索。 部分是不必要的。如果您只是将每个dic[*][2]列表更改为集合,则相同的查找将立即生效。

因此,代替O(N^2 * M^2),其中N的长度为dic,而M的长度为dic[*][2]的{​​平均值?},&#{1}} 39;将是O(N^2 * M)。仍然很慢,但速度要快得多。

您还没有向我们展示您构建此巨型列表的位置,因此我无法向您展示如何以不同方式构建它...但通常只需要从{{1}开始并调用set()而不是以.add开头并调用[]

或者,如果您无法改变其构建方式,您可以随时更改它:

.append

我在这里假设你没有计算两次重复。如果您应该这样做,我认为您做错了 - 您计算dic = [[a, b, set(c)] for a, b, c in dic] 中的重复项,而不是j中的重复项。但无论如何,你可以通过使用" multiset"来解决这个问题。类型;通常k是最简单的方法。


您还可以通过使用集合交集而不是迭代一个集合来检查另一个集合,使其更简单(尽管只是更快一点)。而不是:

collections.Counter

......这样做:

for r in range(len(dic[j][2])):
    if(dic[j][2][r] in dic[k][2]):
        temp_score += 1

虽然我们不是在做temp_score += len(dic[j][2] & dic[k][2]) ,而是在整个地方使用for j in range(len(dic)),但您可以使用dic[j]并使用for x in dic 。像这样:

x

或者,更简洁:

for x in dic:
    for y in dic:
        score_temp = len(x[2] & y[2])
        score_final = float(score_temp) / (x[1] + y[1])
        dice_cursor.execute('insert into dices values(?,?,?)', 
                            (x[0], y[0], score_final))

答案 1 :(得分:1)

您的代码存在很多问题:

由于你正在使用range()迭代你的dict的键,从0开始,看起来你最好只使用一个列表,实际上,这只是一个整数的映射到值,其中整数是连续的并从0开始。此外,键似乎在您的代码中没有扮演其他角色,而是为了解决词典中的条目。这意味着,您根本不必迭代range()。相反,你应该像这样迭代(假设你使用列表而不是字典):

for a in the_list:
    for b in the_list:
        ...
        for value in a[2]:
            if value in b[2]:
                ...

尽管如此,这只是稍好一些。如果您可以使用集合而不是列表作为数据中的第三个条目,那会更好。列表上的in运算符的时间复杂度为O(n)。在套装上它平均只有O(1)。此外,您可以使用标准库中的正确功能。然后你会得到这样的东西:

from itertools import combinations

the_list = [
    ['happy', 100, set([<100 elements>)]],
    ['unhappy', 90, set([<90 elements>)]],
    ['green', 120, set([<120 elements>)]],
    ['red', 50, set([<50 elements>)]],
    ...
]

for a, b in combinations(the_list, 2):

    score = len(a[2] & b[2])
    dice_cursor.execute('insert into dices values(?,?,?)', (a[0], b[0], score))
    dice_cursor.execute('insert into dices values(?,?,?)', (b[0], a[0], score))

# now the pairings we didn't generate so far:
for a in the_list:
    dice_cursor.execute('insert into dices values(?,?,?)', (a[0], a[0], len(a[2])))