【问题标题】:Reading arrays pixel by pixel, getting UnpicklingError逐像素读取数组,得到 UnpicklingError
【发布时间】:2018-08-29 20:12:38
【问题描述】:

我之前使用pickle 将数千个 2D numpy 数组 (600x600) 保存到二进制文件中。由于内存限制,我将它们一一保存,现在我想将它们一一读取,执行一些操作并将新数组(也是一一)保存到新文件中。然后我的最后一个目标是逐个读取这些新数组,并将像素值附加到与给定位置对应的新列表中。但由于某种原因,我收到了UnpickingError,但我不确定为什么。

import numpy as np
import pickle

def normalize(data_set):
    data_set *= 1/data_set.max()
    with open('final_images.data', 'a+b') as f:
        pickle.dump(data_set, f)
    return data_set

with open('initial_data.data', 'rb') as f:
    while True:
        try:
            data_set = pickle.load(f)
            # other operations
            final_img = normalize(data_set)
        except EOFError:
            break

filename = 'final_images.data'
def sort_by_pixel(i, j):
    pixels_at_position = []
    with open(filename, 'rb') as f:
        while True:
            try:
                array = pickle.load(f) #GET ERROR HERE
                fp = np.memmap(filename, dtype='float32', mode='w+', shape=(600,600))
                fp[:] = array[:]
                pixels_at_position.append(fp[i][j])
            except EOFError:
                break
    return pixels_at_position

stacked = []
for i in range(600):
    for j in range(600):
        stacked.append(np.median(sort_by_pixel(i, j)))

我在我指出的那一行得到的错误是:

pickle.UnpicklingError: invalid load key, '\x00'.

我做错了什么?

【问题讨论】:

  • 当您np.memmap(filename, …) 时,这与您用于泡菜文件的文件名相同。因此,一旦您fp[:] = array[:],您将用原始数组数据替换所有泡菜数据。但是随后您尝试解开原始数组数据,就好像它是一个泡菜一样,但事实并非如此(除非您真的很不幸),所以它失败了。
  • 我不确定您要在这里做什么,但修复可能就像拥有单独的 final_images.pkl 和 final_images.bin 文件或其他东西一样简单。或者,它可能就像一开始不使用memmap,而只是附加array[i][j](或者,可能更好,array[i, j])一样简单。
  • 我不太确定您的意思,但无论如何都会在 memmap 行之前发生错误。而memmap 我只是想生成一个数组(不会保存在内存中)
  • 但是(a)为什么你甚至需要那个 mmap,当你首先在内存中有完全相同的数组时,以及(b)你为什么要尝试使用同一个文件作为 mmap 的后备存储正在读取中?
  • 您的代码在其他方面也令人困惑。您的normalize 函数将某些内容保存到文件中并执行没有值的return,因此它只返回None,但随后您使用final_img = normalize(data_set) 调用它。我不确定那应该做什么,但我怀疑这与它实际做的不一样。

标签: python arrays python-3.x numpy pickle


【解决方案1】:

您有一个完全有效的 pickle 文件 final_images.data,您已将 pickle 转储附加到该文件中。因此,第一次循环时,array = pickle.load(f) 将起作用。

但是你映射同一个文件:

fp = np.memmap(filename, dtype='float32', mode='w+', shape=(600,600))

这个fp 将充满垃圾,试图将泡菜流解释为原始数组数据,但由于您实际上并未使用该数据,所以没关系。

然后你用你加载的最后一个泡菜的原始数组数据覆盖整个文件:

fp[:] = array[:]

现在,该文件不再是有效的 pickle 文件,而是原始数据。

因此,下一次循环时,当您从中 pickle.load 时,它将失败,并提供您所看到的错误。1。


如果你真的需要一个mmap,你想把它存储在一个不同的文件中,而不是覆盖你正在阅读的pickle文件:

fp = np.memmap(filename + '.raw', dtype='float32', mode='w+', shape=(600,600))

但实际上,我一开始看不出 mmap 有什么好处。您已经在内存中获得了与array 完全相同的数组。制作memmap,然后将数据复制到其中只是浪费资源,而我看不到任何好处。如果您只是完全删除该行并执行pixels_at_position.append(array[i][j]),它应该具有您所追求的效果。2

我实际上并不确定这就是你所追求的,因为你的代码似乎试图做的是构建一个列表,其中包含泡菜中每个数组的 (i, j)th 值,但是函数的名称 sort_by_pixel 听起来你真正想要的东西与它完全不同(一方面是排序的东西)。


1。实际上,只有运气好才会失败。如果原始数据足够小。 f 文件指针可能超出末尾,而您只会得到一个 EOF。如果你真的不走运,原始数据可能恰好可以解释为日期时间对象元组的泡菜或一些疯狂的东西,你只会默默地产生大量垃圾。子>

2。除了你真的应该使用[i, j],而不是[i][j]。后者必须创建一个行对象才能对其进行索引。这并不太贵,因为该行只是与原始数组相同的内存中的一个切片,但它仍然不是免费的。而且它也不太惯用,因此不太清楚——阅读[i, j] 的人知道您正在索引一个二维数组;阅读[i][j] 的人会期望您正在索引一个(可能是锯齿状的)序列序列,并且必须弄清楚它实际上是一个二维数组。

【讨论】:

    猜你喜欢
    • 2019-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-26
    • 1970-01-01
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多