我正在编写一个脚本,需要在启动时处理一个相当大(62万字)的词典.输入词典逐字处理成a defaultdict(list),键为字母bi和trigrams,值为包含关键字母n-gram的单词列表
for word in lexicon_file:
word = word.lower()
for letter n-gram in word:
lexicon[n-gram].append(word)
Run Code Online (Sandbox Code Playgroud)
如
> lexicon["ab"]
["abracadabra", "abbey", "abnormal"]
Run Code Online (Sandbox Code Playgroud)
得到的结构包含25 000个键,每个键包含一个列表,其中包含1到133 000个字符串(平均值为500,中位数为20).所有字符串都在windows-1250编码中.
这种处理需要大量的时间(可忽略考虑到脚本的预期实际运行,但测试时一般征税),并且由于词汇本身永远不会改变,我想它可能会更快序列化所产生的defaultdict(list),然后反序列化在随后每次启动.
我发现即使在使用时cPickle,反序列化过程的速度也只是简单处理词典的两倍,平均值接近:
> normal lexicon creation
45 seconds
> cPickle deserialization
80 seconds
Run Code Online (Sandbox Code Playgroud)
我没有任何序列化的经验,但我期望反序列化比正常处理更快,至少对于cPickle模块而言.
我的问题是,这个结果可以预期吗?为什么?有没有办法更快地存储/加载我的结构?
我正在尝试优化脚本的性能,该脚本在给出的每个单词的词典中查找相似的单词.
每个唯一的单词将被分成字母n-gram,并且对于每个n-gram,词典返回包含相同字母n-gram的单词列表.然后将此列表中的每个单词作为键添加到字典中,并将其值加1.这给了我一个具有相应频率分数的类似单词的字典.
word_dict = {}
get = word_dict.get
for letter_n_gram in word:
for entry in lexicon[n_gram]:
word_dict[entry] = get(entry, 0) + 1
Run Code Online (Sandbox Code Playgroud)
这个实现有效,但是通过切换dictfor 可以更快地运行脚本collections.defaultdict.
word_dd = defaultdict(int)
for letter_n_gram in word:
for entry in lexicon[n_gram]:
word_dd[entry] += 1
Run Code Online (Sandbox Code Playgroud)
没有其他代码被更改.
我的印象是两个代码片段(最重要的是分数添加)应该以完全相同的方式工作,即如果密钥存在,将其值增加1,如果它不存在,则创建密钥并将值设置为1.
但是,在运行新代码之后,某些键的值为0,我觉得这在逻辑上是不可能的.
我的逻辑或defaultdict功能知识是否有缺陷?如果没有,如何将任何值word_dd设置为0?
编辑:我也非常确定脚本中没有其他部分会扭曲这些结果,因为我使用以下代码在显示代码后立即测试字典:
for item in word_dd.iteritems():
if item[1] == 0:
print "Found zero value element"
break
Run Code Online (Sandbox Code Playgroud)