在Python中合并字典

2 投票
3 回答
1019 浏览
提问于 2025-04-15 19:22

抱歉标题有点笼统,但我会尽量具体一些。

我正在开发一个文本挖掘的应用程序。我有很多成对的数据,格式是((单词, 语料库) -> 出现次数)(这些都是整数),我把它们存储在多个Python字典里(元组->整数)。这些数据分散在多个文件中(我把它们进行了序列化)。为了理解这些数据,我需要把这些字典里的信息整合起来。简单来说,我需要找到每个字典中某个特定键的所有出现次数,然后把它们加起来,得到一个总数。

但是,如果我一次加载多个字典,就会耗尽内存,这也是我最开始要把它们分开的原因。当我尝试这样做时,性能也出现了问题。目前,我正在尝试把这些值存储到数据库(mysql)中,同时处理多个字典,因为mysql提供了行级锁定,这样做有好处(意味着我可以并行处理),也有坏处(因为这会减慢插入查询的速度)。

我有哪些选择呢?写一个部分基于磁盘的字典,这样我可以一次处理一个字典,是否是个好主意?使用LRU替换策略?还有什么我完全没想到的东西吗?

谢谢!

3 个回答

0
  1. 如果我理解你的问题没错,你有单词和语料库的整数ID,那么你可以通过把字典换成列表,甚至更好的是换成numpy数组来提高性能。这可能会让人觉得麻烦!

    基本上,你需要把元组替换成一个单独的整数,我们可以叫它newid。你希望所有的newid都对应一个单词和语料库的组合,所以我建议你先统计每个语料库中的单词数量,然后为每个语料库设定一个起始的newid。这样,(单词, 语料库)的newid就可以表示为单词加上start_newid[语料库]。

    如果我理解错了,假设你没有这样的ID,那么我觉得这个建议可能还是有用的,但你需要对数据进行处理,把它转换成整数元组的格式。

  2. 你还可以尝试重新分块数据。

    假设你只能在内存中放下1.1个这样的庞然大物。那么,你可以先加载一个,然后创建一个只对应前10%(单词, 语料库)组合的小字典或数组。你可以扫描加载的字典,处理前10%中的任何一个。当你完成后,可以把结果写回磁盘,然后再处理第二个10%。这需要进行10次处理,但这对你来说可能没问题。

    如果你之前的分块是根据能放进内存的大小来选择的,那么你需要随意把旧字典分成两半,这样你就可以在内存中同时保持一个字典和结果字典/数组。

0

如果我理解你的问题没错的话,可以这样做:

from collections import defaultdict
import pickle

result = defaultdict(int)
for fn in filenames:
    data_dict = pickle.load(open(fn))
    for k,count in data_dict.items():
        word,corpus = k
        result[k]+=count
2

有一种基于磁盘的字典类型,叫做 shelve 模块。这个模块的键必须是字符串,但你可以简单地把你的元组用 str 转换成字符串,这样就能得到相应的字符串键。而且,我理解你的问题是你只想用 word 作为键,这样就更简单了(用 str 转换就可以,或者对于小于 4GB 的词汇量,可以用 struct.pack 也行)。

一个好的关系型数据库引擎(特别是 PostgreSQL)会对你很有帮助,不过你也可以一次处理一个字典,把每个单词在所有语料库中的出现次数汇总到一个 shelf 对象里,这样也可以(虽然速度没那么快,但代码更简单,因为 shelfdict 非常相似,只是键的类型有限制[[还有一个关于可变值的注意事项,但因为你的值是 int,所以这对你来说不需要担心)。

撰写回答