列表中的Python计数发生:如何使其更快?

问题描述:

我有一个包含大约6百万个项目的字符串列表,并且我正在计算每个唯一值的发生次数。列表中的Python计数发生:如何使其更快?

这里是我的代码:

lines = [6 million strings] 
unique_val = list(set(lines)) # contains around 500k items 

mydict = {} 
for val in unique_val: 
    mydict[val] = lines.count(val) 

我发现上面的代码工作非常缓慢因为我指望名单是巨大的。

我想知道是否有办法让它更快?

非常感谢

+0

这对于'pyspark'来说可能足够大了,它将非常适合这类问题。 –

+0

是否愿意使用非纯Python包(如numpy或pyspark?)。 –

+0

另外,我编辑了你的代码,以便它可以通过使用正确的大括号正确运行 - 我知道编辑代码通常不被看好(它看起来像是一个非常明显的错字),但是如果你的意思是由于某种原因,原始回退编辑 –

如果你不想使用collections模块。

counts = dict() 
for line in lines: 
    counts[line] = counts.get(line,0) + 1 

或者,如果你只是不想使用Counter

from collection import defaultdict 
counts = defaultdict(int) 
for line in lines: 
    counts[line] += 1 
+0

嗨迈克尔,那第一个工作怎么样?它看起来像计数没有初始化任何东西,所以我不知道它是如何得到更新? (当我运行它时,它似乎也不工作...)。 “get”函数查找一个键并返回0,如果该键不存在,但由于我们从不添加任何键,它不会总是0吗? –

+0

@en_Knight,:)它显然不起作用。最后我错过了'+ 1'。我现在编辑它 –

这个怎么样,

from collections import defaultdict 
import collections 

lines = [600 million strings] 

d = defaultdict(int) 
for line in lines: 
    for word, count in collections.Counter(line).items(): 
     d[word] += count 
+0

为什么你会在DeepSpace的时候这样做,当他看起来更简洁的结果呢? (当然,我认为他不应该打电话给他) –

+0

@en_Knight,thx指出这一点。我刚刚编辑了我的答案。 – SparkAndShine

+0

嗯,我还是不明白这比'd = Counter(lines)'更好。为什么我们循环,多次调用Counter和字典拷贝?有没有你正在做的内存优化? –

numpy的解决方案

我认为numpy的给你最快的答案,使用unique

result = dict(zip(*np.unique(lines, return_counts=True))) 

numpy在引擎盖下非常严格优化。每个链接的文档,在魔术界围绕return_counts标志:

return_counts:BOOL,可选

如果真,也返回的次数每一个独特的价值AR出现。


定时

我计时你原来的做法,柜台办法

result = Counter(lines) 

N = 1000000 
lines = [chr(i%100) for i in range(N) ] 

Obviousl生成一组的numpy的方法这个测试不是很好的报道,但这是一个开始。

你正在0.584s操作的方法; DeepSpace的计数器在0.162(3.5x加速)和0.0861(7x加速)的numpy。再次,这可能取决于很多因素,包括您拥有的数据类型:结论可能是numpy或Counter会提供加速,不需要外部库的计数器

调用list.count非常昂贵。字典访问(O(1)摊销时间)和in运营商,但是相对便宜。以下片段显示了更好的时间复杂度。

def stats(lines): 
    histogram = {} 
    for s in lines: 
     if s in histogram: 
      histogram[s] += 1 
     else: 
      histogram[s] = 1 
    return histogram