【问题标题】:python sampling using readline gives memory error使用 readline 的 python 采样会产生内存错误
【发布时间】:2018-11-06 01:06:17
【问题描述】:

我尝试对一个包含超过 2.6 亿行的数据文件进行采样,创建一个固定大小为 1000 个样本的均匀分布的样本。

我做了以下事情:

import random

file = "input.txt"
output = open("output.txt", "w+", encoding = "utf-8")

samples = random.sample(range(1, 264000000), 1000)
samples.sort(reverse=False)

with open(file, encoding = "utf-8") as fp:
    line = fp.readline()
    count = 0
    while line:
        if count in samples:
            output.write(line)
            samples.remove(count)
        count += 1
        line = fp.readline()

此代码导致内存错误,没有进一步的描述。这段代码怎么会出现内存错误?

据我所知,它应该逐行读取我的文件。该文件为 28.4GB,因此无法整体读取,这就是我采用 readline() 方法的原因。我该如何解决这个问题,以便处理整个文件,无论其大小如何?\

编辑: 最近的尝试抛出了这个错误,这实际上与我目前收到的每个先前的错误消息相同

MemoryError                               Traceback (most recent call last)
<ipython-input-1-a772dad1ea5a> in <module>()
     12 with open(file, encoding = "utf-8") as fp:
     13     count = 0
---> 14     for line in fp:
     15         if count in samples:
     16             output.write(line)

~\Anaconda3\lib\codecs.py in decode(self, input, final)
    320         # decode input (taking the buffer into account)
    321         data = self.buffer + input
--> 322         (result, consumed) = self._buffer_decode(data, self.errors, final)
    323         # keep undecoded input until the next call
    324         self.buffer = data[consumed:]

MemoryError: 

【问题讨论】:

    标签: python memory readline sampling


    【解决方案1】:

    所以看起来这条线导致了巨大的内存峰值:

    samples = random.sample(range(1, 264000000), 1000)
    

    我的猜测是,这个调用会强制 python 在进行采样之前创建该范围内的所有 264M 个整数。尝试使用此代码代替在相同范围内进行采样而不进行替换:

    from random import randint
    
    file = "input.txt"
    output = open("output.txt", "w+", encoding = "utf-8")
    
    samples = set()
    while len(samples) < 1000:
        random_num = randint(0, 264000000)
        if random_num not in samples:
            samples.add(random_num)
    
    with open(file, encoding = "utf-8") as fp:
        count = 0
        for line in fp:
            if count in samples:
                output.write(line)
                samples.remove(count)
            count += 1
    
            if not samples: break
    

    【讨论】:

    • 感谢您的清晰解释!不幸的是,这种方法导致了同样的内存错误......
    • 啊,我想我发现了错误。我在解释器中只运行了这一行,内存使用量飙升samples = random.sample(range(1, 264000000), 1000)。请改用我编辑的代码。我还更新了我的答案,说明为什么这行可能会导致内存错误。
    • 其实你是在运行python2还是python3?
    • 我使用 Python 3。不过,该过程开始使用超过 6GB 的 RAM(在我拥有的 8 个 RAM 中),然后它开始变慢,直到它引发另一个内存错误......
    • 好的,在 python3 中 samples = random.sample(range(1, 264000000), 1000) 无论如何应该没问题。这在我的机器上运行得很快。原始评论认为python2使用了更天真的range函数。我今天要访问一台更大的机器进行一些测试,我稍后再回复。
    【解决方案2】:

    已解决

    我终于解决了这个问题:这里的所有代码都可以正常工作, 范围问题确实只存在于 3.0 之前的版本中, 它应该是 xrange(1, 264000000)。

    输入文件是在不同的代码文件中构建的, 它的写法如下:

    with open(file, encoding = "utf-8", errors = 'ignore') as fp:  
    line = fp.readline()
        while line:
            input_line = line.split(sep="\t")
            output.write(input_line[1] + "," + input_line[2])
            line = fp.readline()
    

    这里的问题是,这段代码没有构造一个带行的文件,而只是在第一行添加了信息。因此,整个文件被读取为一个大行,而不是一个包含很多行需要迭代的文件。

    非常感谢您的帮助,对于问题出在我项目的其他地方这一事实,我深表歉意。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-20
      • 1970-01-01
      • 1970-01-01
      • 2022-08-04
      • 2017-01-18
      • 2017-11-07
      • 2018-06-12
      • 1970-01-01
      相关资源
      最近更新 更多