在python中有增长字典的有效替代方法吗?

时间:2015-05-28 22:06:15

标签: python dictionary bigdata

我正在读取xml格式的大型文本语料库,并在字典中存储一些单词出现次数,其中键是三个元素{('a','b','c'):1}的元组。该词典的大小不断增大,其值也会更新。 在将其写入hdf文件之前,我需要在内存中保留一个字典~25GB。

我试图找到一些关于哪些数据类型可以实际反映当前字典结构但没有找到任何具体答案的信息。我最关心的是内存大小。 python中是否有任何可以缓解这些约束的数据结构?我已经阅读过关于pyjudy库的内容,但看起来它是32位,并且几乎不再开发。我很感激任何建议。

4 个答案:

答案 0 :(得分:2)

我不知道是否有其他dict实现,但我说你有2.5个选项:

  1. 在本地优化您的编码 - 分别为您的单词编制索引,以便您获得{'a': 1, 'b': 2, ...}的字典,然后使用{(1,2,3): 1}替换三元组字典。这将减少内存使用量,因为字符串不会重复多次。
  2. 2.1。用其他语言扩展实现上述内容。

    2.2。只需使用其他语言。与您存储的小值相比,python中的整个字典和值总是会产生严重的开销。

    编辑:对das-g评论的更长回答,因为我认为它应该得到一个。 Python擅长于仅复制更改的数据。当它们被分配给新变量时,不可变值仍保留在一个位置。这允许以下操作几乎没有新的分配:

    # VmRSS:       27504 kB
    In [1]: a=['a'*1024]
    # VmRSS:       27540 kB
    In [2]: a=['a'*1024]*10000
    # VmRSS:       27540 kB
    

    但对于来自不同地方的相同价值观并非如此。在 - 他们每次都是从头开始创建(例如从文件中读取),而不是从现有值复制:

    # VmRSS:       27540 kB
    In [4]: a=['a'*1024 for _ in range(10000)]
    # VmRSS:       38280 kB
    In [5]: b=['a'*1024 for _ in range(10000)]
    # VmRSS:       48840 kB
    

    这就是为什么如果从一些进程外的源读取这些单词,那么值得自己重复删除它们,因为Python不会自动为你做这些。

    所以在实践中,你甚至可以通过做一些看似愚蠢的事情来节省记忆:

    def increase_triple(a, b, c):
        triples[(a,b,c)] += 1
    

    使用:

    WORDS = {}
    def dedup(s):
        s_dedup = WORDS.get(s)
        if s_dedup is None:
            WORDS[s] = s
            return s
        else:
            return s_dedup
    
    def increase_triple(a, b, c):
        triples[(dedup(a),dedup(b),dedup(c))] += 1
    

    正如@StefanPochmann在评论中提到的那样,标准函数intren()几乎完成了上面dedup()所做的事情。更好。

答案 1 :(得分:2)

在效率和可维护性方面,使用传统的处理中小型数据的方法处理大数据通常是错误的方法。即使您今天完成此操作,也无法保证您明天可以出于多种原因(例如,您的数据增长大于可用内存,数据分区等)。

取决于您输入的行为,您应该查看批处理引擎(Hadoop / Mapreduce,Apache Spark)或流处理引擎(Apache Storm,Spark Streaming)。

如果你想继续使用python,Apache Spark有python接口。

最后,有一个名为Apache Zeppelin的项目用于交互式大数据分析(我的论文主题)。它支持Apache Spark和其他几个平台。

答案 2 :(得分:1)

  

我需要在内存中保留字典~25GB之前   把它写到hdf文件。

这是否意味着数据是25GB,或者结果字典是25GB内存?这意味着如果元组中的每个元素都是单词,那么这些3元组中的很多。我认为你真的不需要记忆中的所有这些。但是,我真的怀疑三字组的整数字典是25GB。

根据我/ usr / share / dict / words,平均单词约为10个字符。每个都是最常见情况下的一个字节。每个记录30个字节没有整数,你可能有4个字节的密钥。所以每条记录34个字节。当然,字典会增加开销。但我们仍然很容易谈论超过6亿个3元组。当然,在这种情况下,这是一个独特的单词元组,因为你在计算字典值中的每一个。

不完全明白你的问题是什么,我会指着你shelve。它给你一些看起来像字典(界面明智)但是磁盘支持的东西。

你真的试过这个吗?过早优化是所有邪恶的根源:)

答案 3 :(得分:0)

老实说,我建议使用一个数据库,但是如果你在Python中保留这个数据库就死定...

从单词到索引的映射可能会有所帮助。将(' a',''' c')的键替换为(1,2,3),其中(1,2,3)是查找表中的值。

public class Fund
//and
public class TrackFund : Fund

如果您拥有的大部分单词都很长并且重复很多,那么这将是主要用途。如果你有(a,b,c),(a,c,b),(b,a,c),(b,c,a),(c,a,b)和(c,b,a) ),每个单词只存储一次而不是6次。

编辑:这取决于你如何生成字符串。

lookup_table = {'a':1, 'b':2, 'c':3}

另一种方法是读取文件,但当输出增长到某一点时,对键(a-z)进行排序,然后输出到文件:

"ab c" is "ab c" : True
"a"+"b c" is "ab c" : False

然后擦除字典并继续处理。文件处理完毕后,您可以合并这些值。这并没有使用太多内存,因为所有文件都已排序;你只需要在内存中保留每行一行。 (想想mergesort。)

或者您可以使用数据库,让它担心这一点。