在生成dicts时有效地处理大量字符串列表

时间:2015-04-01 09:29:06

标签: python python-3.x

我是Python的新手,尤其是处理大量数据的新手。我正在开展一个有趣的项目,这实际上是我以前用另一种语言做过的事情的高档。

现在,我正在加载一个相当大的(100mb +)文本文档,将其分解为单词,然后确定每个前缀后面的单词的频率(每个前缀是一个或多个单词)。在Python中实现相当简单和有趣,我最终得到了以下内容:

def prefix(symbols):
    relationships = {}

    for i in reversed(range(len(symbols))):
        prefix = seperator.join(symbols[i:i+samples])
        suffix = None

        if i+samples < len(symbols):
            suffix = symbols[i+samples]

        if prefix not in relations:
            relations[prefix] = {}

        if suffix not in relations[prefix]:
            relations[prefix][suffix] = 1
        else:
            relations[prefix][suffix] += 1

    return relations

(函数名称,它的参数和全局“样本”的使用只是暂时的,当我解决问题时)

这很有效,大约需要20秒左右才能处理来自维基百科的60mb明文文章。然而,将样本大小(“样本”变量)从1增加到甚至4或5会大大增加内存使用量(正如预期的那样 - 大约有1000万个单词,对于每个单词,“样本”很多单词被切片并加入到一个新的字符串)。这很快就会接近并达到2千兆字节的内存限制。

我用来缓解这个问题的一种方法是在迭代时从内存中删除初始单词,因为它们不再需要(单词列表可以简单地构造为函数的一部分,所以我不是修改传入的任何内容。)

def prefix(symbols):
    relationships = {}

    n = len(symbols)
    for i in range(n):
        prefix = seperator.join(symbols[0:samples])

        suffix = None
        if samples < len(symbols):
            suffix = symbols[samples]

        if prefix not in relationships:
            relationships[prefix] = {}

        if suffix not in relationships[prefix]:
            relationships[prefix][suffix] = 1
        else:
            relationships[prefix][suffix] += 1

        del symbols[0]
    return relationships

这确实有帮助,但不是很多,而是以某种表现为代价。

所以我要问的是这种方法是否相当有效或推荐,如果没有,哪种方法更合适?我可能会错过一些避免冗余创建字符串和复制列表的方法,因为大部分内容对我来说都是新的。 我在考虑:

  • 对符号/单词列表进行分块,处理,将关系转储到磁盘并在事后将它们组合
  • 使用像Redis这样的东西,而不是在整个时间内保持Python内部的关系

欢呼任何建议或协助!

3 个答案:

答案 0 :(得分:1)

在Python中使用大字符串时,如果需要进行大量更改,主要的建议是:

  1. 将字符串转换为列表
  2. 使用列表
  3. 完成所有工作
  4. 完成后,转换回字符串
  5. 原因是Python中的字符串是不可变的。例如,symbols[i:i+samples]的每个操作都会强制Python分配新内存,复制所需的字符串,并将其作为新的字符串对象返回。因此,当您需要对字符串进行许多更改(通过索引更改,拆分)时,您最好使用可变的列表。

答案 1 :(得分:0)

重新。加快这个过程,我发现使用try / except块来更新哈希表很有用。例如:

try:
    relationships[prefix][suffix] += 1
except KeyError:
    relationships[prefix][suffix] = 1

上述代码不会使用'in'来检查密钥,然后更新/创建需要对该密钥进行另一次检查的密钥,而是消除了一次检查,因此工作得更快。

答案 2 :(得分:0)

使用iterator_of_symbols = iter(list_of_symbols),然后next()使用iterator_of_symbols.next()

了解更多Which is more efficient, a for-each loop, or an iterator?

虽然用Java解释过,但我认为概念是相同的。