【问题标题】:Most efficient histogram code in pythonpython中最有效的直方图代码
【发布时间】:2013-05-18 21:22:22
【问题描述】:

我已经看到了许多关于在干净的单线中制作直方图的问题,但我还没有发现有人试图尽可能高效地制作直方图。我目前正在为搜索算法创建大量 tfidf 向量,这涉及创建许多直方图和我当前的代码,虽然非常短且可读性不如我想的那么快。可悲的是,我尝试了许多其他方法,但结果要慢得多。你能做得更快吗? cleanStringVector 是一个字符串列表(全小写,没有标点符号),masterWordList 也是一个单词列表,应该包含 cleanStringVector 中的每个单词。

from collections import Counter
def tfidfVector(cleanStringVector, masterWordList):
    frequencyHistogram = Counter(cleanStringVector)
    featureVector = [frequencyHistogram[word] for word in masterWordList]
    return featureVector

值得注意的是,Counter 对象为不存在的键返回零而不是引发 KeyError 是一个严重的优点,其他问题中的大多数直方图方法都未通过此测试。

示例:如果我有以下数据:

["apple", "orange", "tomato", "apple", "apple"]
["tomato", "tomato", "orange"]
["apple", "apple", "apple", "cucumber"]
["tomato", "orange", "apple", "apple", "tomato", "orange"]
["orange", "cucumber", "orange", "cucumber", "tomato"]

还有一个主要的词表:

["apple", "orange", "tomato", "cucumber"]

我想分别从每个测试用例返回以下内容:

[3, 1, 1, 0]
[0, 1, 2, 0]
[3, 0, 0, 1]
[2, 2, 2, 0]
[0, 2, 1, 2]

希望对你有帮助。

大概的最终结果:

Original Method: 3.213
OrderedDict: 5.529
UnorderedDict: 0.190

【问题讨论】:

  • cleanStringVector 长什么样子?
  • 哦,这只是一个字符串列表。现在是一个直接的 python 列表,但如果你愿意,可以假设它是一个 numpy 数组。
  • 你对here的方法进行了基准测试吗?
  • 我已经运行了大部分,而不是全部。我删除了一些完全无法阅读的内容。这似乎是其中最快的,但仍然很慢。
  • 你看到this 一个了吗?虽然关于字母的方法可能有用。

标签: python performance histogram tf-idf


【解决方案1】:

这使用 Python 3 将我不具代表性的微基准测试中的运行时间提高了 1 个数量级:

mapping = dict((w, i) for i, w in enumerate(masterWordList))

def tfidfVector(cleanStringVector, masterWordList):    
    featureVector = [0] * len(masterWordList)
    for w in cleanStringVector:
        featureVector[mapping[w]] += 1
    return featureVector

【讨论】:

  • 与我在回答中试图实现的想法相同.. 但更优雅(可能更快),很好
  • 哦,太棒了。在调用它的代码中对缓存局部性进行了一些小调整,并设法将速度提高了大约 20 倍。
【解决方案2】:

我认为遍历 Master Word 列表是个问题。每次制作直方图时,您都必须对主单词列表中的每个单词进行散列(这些散列中的大多数只是丢失了,这是一种返回 0 的计算成本高的方法)。

我会先对主单词表进行哈希处理,然后使用该哈希创建每个直方图,这样您只需对字符串向量中的每个单词进行哈希处理(两次,一次获取计数,一次重置主单词列表哈希) .如果字符串向量小于主词表,则哈希操作会少很多:

from itertools import repeat

stringvecs=[["apple", "orange", "tomato", "apple", "apple"],
["tomato", "tomato", "orange"],
["apple", "apple", "apple", "cucumber"],
["tomato", "orange", "apple", "apple", "tomato", "orange"],
["orange", "cucumber", "orange", "cucumber", "tomato"]]

m=["apple", "orange", "tomato", "cucumber"]

md = dict(zip(m, repeat(0)))

def tfidfVector(stringvec, md):
    for item in stringvec:
        md[item]+=1
    out=md.values()
    for item in stringvec:
        md[item]=0
    return out

for stringvec in stringvecs:
    print tfidfVector(stringvec, md)

注意:只要我们不添加键,md.values() 应该是稳定的..

【讨论】:

  • 我喜欢这个想法,但它比当前的实现要慢得多。 (大约需要两倍的时间)
  • 是的,我刚刚检查过,使用 OrderedDict 比使用 dict 慢 10 倍,并且没有必要,在没有 OrderedDict 的情况下进行测试这是接近 Thomas Jung 的答案,但仍然有点慢。
猜你喜欢
  • 1970-01-01
  • 2018-04-10
  • 1970-01-01
  • 2014-04-09
  • 2020-09-08
  • 2015-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多