Python统计字典大于1的值的频次并生成对应重复元素列表
问题原因
原代码有两个逻辑错误导致结果不符合预期:
reps_list初始化位置错误:放在n值遍历的循环内部,每次处理不同长度ngram时都会被清空,最终仅返回n=6的最后一轮处理结果- 筛选逻辑错误:使用集合推导式(外层包裹
{})筛选计数值,集合自带去重特性,既会丢失重复的计数值,也无法保留ngram文本和计数的对应关系
修改方案
场景1:获取每个重复ngram对应的出现次数
如果需要拿到「重复出现的ngram内容、对应出现次数」的完整结果,把列表初始化移到循环外,遍历字典键值对筛选计数大于1的项即可:
import nltk def get_repetitions(text): n_grams_lengths = [1,2,3,4,5,6] ngrams_count = {} reps_list = [] # 列表初始化移到循环外,避免每次遍历n值时被重置 for n in n_grams_lengths: ngrams = tuple(nltk.ngrams(text.split(' '), n=n)) current_ngram_count = {' '.join(i) : ngrams.count(i) for i in ngrams} ngrams_count.update(current_ngram_count) # 所有长度ngram统计完成后,统一筛选符合条件的项 for ngram_text, count in ngrams_count.items(): if count > 1: reps_list.append( (ngram_text, count) ) # 存储格式为(ngram内容, 出现次数) return reps_list
如果不需要保留ngram文本,只需要所有大于1的计数值(不去重),把append的参数改成count即可。
场景2:生成计数值按频次展开的列表
要实现「值2共出现3次就存3个2、值5共出现4次就存4个5」的效果,可以先统计每个计数值本身的出现频次,再按频次展开追加到列表:
import nltk from collections import Counter def get_expanded_reps(text): n_grams_lengths = [1,2,3,4,5,6] ngrams_count = {} expanded_reps = [] for n in n_grams_lengths: ngrams = tuple(nltk.ngrams(text.split(' '), n=n)) current_ngram_count = {' '.join(i) : ngrams.count(i) for i in ngrams} ngrams_count.update(current_ngram_count) # 统计每个计数值对应的出现次数 count_frequency = Counter([cnt for cnt in ngrams_count.values() if cnt > 1]) # 按频次展开生成目标列表 for count, freq in count_frequency.items(): expanded_reps.extend([count] * freq) # 需要有序结果可以放开下面的排序注释 # expanded_reps.sort() return expanded_reps
如果统计结果中值为2的ngram共3个、值为5的ngram共4个,上述函数返回结果就是[2,2,2,5,5,5,5],完全匹配需求格式。
效率优化提示:原代码中用
ngrams.count(i)统计频次的时间复杂度很高,每个元素都要遍历整个ngram元组计数,处理长文本时速度很慢,可以直接用Counter统计ngram频次替换原有逻辑,性能提升明显:current_ngram_count = Counter(' '.join(i) for i in ngrams)
内容的提问来源于stack exchange,提问作者user17169994
相关产品推荐
相关产品推荐

