首页 > 解决方案 > 逐像素读取数组,得到 UnpicklingError

问题描述

我之前已经将数千个 2D numpy 数组(600x600)保存到带有pickle. 由于内存限制,我将它们一一保存,现在我想将它们一一读取,执行一些操作并将新数组(也是一一)保存到新文件中。然后我的最后一个目标是逐个读取这些新数组,并将像素值附加到与给定位置对应的新列表中。但由于某种原因,我得到了一个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'.

我究竟做错了什么?

标签: pythonarrayspython-3.xnumpypickle

解决方案


您有一个完全有效的 pickle 文件,final_images.data您已将 pickle 转储附加到该文件中。所以,第一次通过循环,array = pickle.load(f)就可以了。

但是然后你映射同一个文件:

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

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

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

fp[:] = array[:]

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

因此,下次通过循环时,当您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]会期望您正在索引一个(可能是锯齿状的)序列序列,并且必须弄清楚它实际上是一个二维数组。


推荐阅读