热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

随着累积计数器大小的增加,Python中累积计数器的计数变慢

我有一个collections.Counter()对象,该对象不断在循环中获取(累积)添加的Counter对象.随着循环的通过和累加计数器的增加(更多条目),累加()操作将变慢.一

我有一个collections.Counter()对象,该对象不断在循环中获取(累积)添加的Counter对象.随着循环的通过和累加计数器的增加(更多条目),累加(=)操作将变慢.

一种解决方法是分批使用Counter并累积部分计数器以最后添加(减少)它们.但是我想知道为什么会发生这种情况(也许底层实现使用哈希映射并且存储区大小不是动态的,因此冲突发生的频率越来越高?)

cnt = Counter()
for i in range(len(list_files_txt)):
t0 = time()
f = list_files_txt[i]
print('[{}/{}]'.format(i, len(list_files_txt)))
with open(f, 'r') as txt_f:
cnt += Counter(txt_f.read().lower().replace('\n', ' ').split(' '))
d_t = time() - t0
print('Time: ', d_t)
with open('times.txt', 'a') as times_f:
times_f.write(str(d_t)+'\n')

预期结果:在整个循环中,打印时间恒定不变

实际结果:随着循环的进行,打印时间增加

实际结果(代码执行):

[0/185187]
Time: 0.0009126663208007812
[1/185187]
Time: 0.0011148452758789062
[2/185187]
Time: 0.0006835460662841797
[3/185187]
Time: 0.0009150505065917969
[4/185187]
Time: 0.0005855560302734375
# A few thousand iterations later...
[14268/185187]
Time: 0.1499614715576172
[14269/185187]
Time: 0.14177680015563965
[14270/185187]
Time: 0.1480724811553955
[14271/185187]
Time: 0.14731359481811523
[14272/185187]
Time: 0.15594100952148438

这是说明趋势的图表:

Time cost per iteration

解决方法:

Counter .__ iadd__包括对self Counter的线性扫描,以删除具有非正数的项目.从cpython/blob/master/Lib/collections/__init__.py

def _keep_positive(self):
'''Internal method to strip elements with a negative or zero count'''
nOnpositive= [elem for elem, count in self.items() if not count > 0]
for elem in nonpositive:
del self[elem]
return self
def __iadd__(self, other):
'''Inplace add from another counter, keeping only positive counts.
>>> c = Counter('abbb')
>>> c += Counter('bcc')
>>> c
Counter({'b': 4, 'c': 2, 'a': 1})
'''
for elem, count in other.items():
self[elem] += count
return self._keep_positive()

当然,执行此操作所需的时间将随着结果Counter的大小线性增长.如果要避免这种行为,请使用update而不是=.像=(与dict.update不同)一样,Counter.update添加计数而不是替换条目.与=不同,它不会删除非正数.

# Instead of cnt += Counter(...)
cnt.update(Counter(txt_f.read().lower().replace('\n', ' ').split(' ')))

实际上,您甚至不需要构建第二个Counter即可添加.您只需传递一个可迭代的元素即可直接更新,它将元素计数添加到Counter中的现有计数中:

cnt.update(txt_f.read().lower().replace('\n', ' ').split(' '))


推荐阅读
author-avatar
手机用户2602881441
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有