如何让这个python函数更快?

时间:2016-04-02 02:58:40

标签: python performance

我编写的以下代码包含一组68,000个项目,并尝试根据字符串中的文本位置查找类似的项目。这个过程需要一点点i3 4130我暂时用来编码 - 有什么方法可以加快速度吗?我正在制作一种'你的意思吗?'功能,所以我需要对用户输入的内容进行排序。

我不是试图通过使用关键字创建的字典中的相似性进行比较,我试图比较用户即时输入和所有现有密钥之间的相似之处。用户可能会错误输入密钥,这就是为什么它会说“你的意思是什么?”,就像Google搜索一样。

根据平均测试,排序不会影响时间。

def similar_movies(movie):
    start=time.clock()
    movie=capitalize(movie)
    similarmovies={}
    allmovies=all_movies() #returns set of all 68000 movies
    for item in allmovies:
        '''if similar(movie.lower(),item.lower())>.5 or movie in item: #older algorithm
            similarmovies[item]=similar(movie.lower(),item.lower())'''
        if movie in item: #newer algorithm,
                similarmovies[item]=1.0
                print item
        else:
            similarmovies[item]=similar(movie.lower(),item.lower())
    similarmovieshigh=sorted(similarmovies, key=similarmovies.get, reverse=True)[:10]
    print time.clock()-start
    return similarmovieshigh

使用的其他功能:

from difflib import SequenceMatcher
def similar(a, b):
    output=SequenceMatcher(None, a, b).ratio()
    return output

def all_movies(): #returns set of all keys in sub dicts(movies)
    people=list(ratings.keys())
    allmovies=[]
    for item in people:
        for i in ratings[item]:
            allmovies.append(i)
    allmovies=set(allmovies)
    return allmovies

字典采用这种格式,但有数千个名称:

评分= {'Shane':{'阿凡达':4.2,'127小时':4.7},'乔':{'进入野外':4.5,'不可阻挡':3.0}}

3 个答案:

答案 0 :(得分:2)

你的算法将是O(n 2 ),因为在每个标题中,in运算符必须检查标题的每个子字符串以确定输入的文本是否在它里面。所以,是的,我可以理解为什么你希望它更快地运行。

i3不能提供太多的计算能力,因此尽可能预先计算是唯一的解决方案,并且运行额外的软件(如数据库)可能会导致效果不佳,这也是由于功能的原因。

您可以考虑使用标题词词典(可能使用预先计算的语音更改来消除最常见的拼写错误 - Porter Stemmer算法应提供一些有用的缩减规则,例如允许“unstop”匹配“不可阻挡”)。

因此,例如,字典中的一个键将是“狂野”(或语音调整),与该键相关联的值将是包含“wild”的所有标题的列表;你会对你的68,000个标题列表中的“the”,“into”,“avatar”,“hours”,“127”和所有其他单词都有相同的看法。举个例子,你的词典的“狂野”条目可能如下:

"wild": ["Into The Wild", "Wild Wild West", "Wild Things"]

(是的,我在IMDB搜索“狂野”只是因为这个列表可能有更多的条目 - 可能不是最好的选择,但并不是很多标题都有“头像”,“不可阻挡”或“小时”)。

诸如“the”之类的常用词可能有足够的条目,您可能希望将它们排除在外,因此字典的持久副本可能有助于您进行特定的调整,尽管不是必需的,并且计算启动时应该相对较快。

当用户键入某些文本时,您将文本拆分为单词,如果选择使用它们,则应用任何语音缩减,然后连接用户所有单词的所有标题列表,包括重复项。< / p>

然后,计算重复项并按标题匹配的次数排序。如果用户输入“The Wild”,你就会有两个匹配“Into the Wild”(“the”和“wild”),所以它应该比只有“the”或“wild”的标题排序更高,但不能同时排序在他们中间。

在构建最终排序列表后,可以搜索您的评级列表,并在每个条目后附加评级;此操作应该很快,因为您的评级已经在字典中,按名称键入。

这会将O(n 2 )搜索转换为O(log(n))搜索输入的每个单词,如果它符合您的需要,这应该会对性能产生很大的影响。< / p>

答案 1 :(得分:1)

all_movies()中:您可以添加到集合中,而不是附加到列表,而不是将键()转换为列表:

def all_movies():
    allmovies = set()
    for item in ratings.keys():
        for i in ratings[item]:
            allmovies.add(i)
    return allmovies

编辑:或仅使用一个for循环:

def all_movies():
    result = []
    for rating_dict in ratings.values()
        result += rating_dict.keys()
    return result

我无法在similar_movies找到任何内容。

另请查看芹菜:http://docs.celeryproject.org/en/latest/进行多处理,
特别是chunks概念:http://docs.celeryproject.org/en/latest/userguide/canvas.html#chunks

答案 2 :(得分:1)

如果您正在为生产系统进行开发,我建议您使用全文搜索引擎,例如Whoosh (Python)Elastic Search (Java)Apache Solr (Java)。全文搜索引擎是一种服务器,它构建索引以实现全文搜索,包括有效的模糊搜索或邻近搜索。许多流行的数据库系统还具有完整的搜索文本引擎,如PostgreSQL FTSMySQL FTS,如果您已经在使用这些数据库引擎,这可能是一个可接受的选择。

如果此代码主要用于自学习,并且您想学习如何实现模糊搜索,则可能需要查看索引和搜索术语中的电影标题的规范化。有一些方法,如SoundexMetaphone,可以根据搜索词的英语听起来如何规范化,并且可以使用此标准化术语创建搜索索引。 PostgreSQL有implementation of these algorithms。请注意,这些算法是非常基本的构建块,正确的全文搜索引擎将考虑拼写错误,同义词,停用词,语言特定怪癖以及并行/分布式处理等优化。