python 在追加模式下保存numpy数组

8i9zcol2  于 2023-04-10  发布在  Python
关注(0)|答案(7)|浏览(274)

是否可以保存一个numpy数组,并将其附加到一个已经存在的npy文件中---类似于np.save(filename,arr,mode='a')
我有几个函数必须遍历一个大数组的行。由于内存限制,我不能一次创建数组。为了避免一次又一次地创建行,我想创建一次每一行,并将其保存到文件中,将其附加到文件中的前一行。稍后,我可以在mmap_mode中加载npy文件,在需要时访问切片。

5rgfhyps

5rgfhyps1#

内置的.npy文件格式非常适合处理小型数据集,而无需依赖numpy以外的外部模块。
但是,当您开始拥有大量数据时,使用旨在处理此类数据集的文件格式(如HDF5)是首选1(https://stackoverflow.com/a/16660821/1791279)。
例如,下面是在HDF5中使用PyTables保存numpy阵列的解决方案,

  • 步骤1:创建可扩展的EArray存储 *
import tables
import numpy as np

filename = 'outarray.h5'
ROW_SIZE = 100
NUM_COLUMNS = 200

f = tables.open_file(filename, mode='w')
atom = tables.Float64Atom()

array_c = f.create_earray(f.root, 'data', atom, (0, ROW_SIZE))

for idx in range(NUM_COLUMNS):
    x = np.random.rand(1, ROW_SIZE)
    array_c.append(x)
f.close()
  • 第2步:向现有数据集追加行(如果需要)*
f = tables.open_file(filename, mode='a')
f.root.data.append(x)
  • 第3步:回读数据的子集 *
f = tables.open_file(filename, mode='r')
print(f.root.data[1:10,2:20]) # e.g. read from disk only this part of the dataset
nom7f22z

nom7f22z2#

我做了一个库来追加到Numpy .npy文件中。
https://pypi.org/project/npy-append-array

Npy追加数组

通过在增长轴上追加来创建Numpy .npy文件(0表示C顺序,-1表示Fortran顺序)。它的行为与numpy.concatenate类似,不同之处在于结果存储在.npy文件中的内存外,并且可以重复用于进一步追加。创建后,然后,可以利用存储器Map(例如,通过添加mmap_mode="r")来读取文件,这完全允许创建和读取(可选地)大于机器的主存储器的文件。

安装

conda install -c conda-forge npy-append-array

pip install npy-append-array

示例

from npy_append_array import NpyAppendArray
import numpy as np

arr1 = np.array([[1,2],[3,4]])
arr2 = np.array([[1,2],[3,4],[5,6]])

filename = 'out.npy'

with NpyAppendArray(filename) as npaa:
    npaa.append(arr1)
    npaa.append(arr2)
    npaa.append(arr2)
    
data = np.load(filename, mmap_mode="r")

print(data)

实现详情

NpyAppendArray包含Numpy包中format.py的修改后的部分版本。它确保使用21(=len(str(8*2**64-1)))字节的空闲空间创建数组头。这允许在不增加数组头大小的情况下适应最大尺寸的数组(对于64位机器)。这允许在我们将数据附加到.npy文件的末尾时简单地重写头。

1cosmwyk

1cosmwyk3#

这是Mohit Pandey的答案的扩展,显示了一个完整的保存/加载示例。它使用Python 3.6和Numpy 1.11.3进行了测试。

from pathlib import Path
import numpy as np
import os

p = Path('temp.npy')
with p.open('ab') as f:
    np.save(f, np.zeros(2))
    np.save(f, np.ones(2))

with p.open('rb') as f:
    fsz = os.fstat(f.fileno()).st_size
    out = np.load(f)
    while f.tell() < fsz:
        out = np.vstack((out, np.load(f)))

out = array([[ 0.,0.],[ 1.,1.]])

niknxzdl

niknxzdl4#

.npy文件包含头文件,头文件中有数组的形状和数据类型。如果你知道你的结果数组是什么样子的,你可以自己写头文件,然后写数据块。例如,下面是连接2d矩阵的代码:

import numpy as np
import numpy.lib.format as fmt

def get_header(fnames):
    dtype = None
    shape_0 = 0
    shape_1 = None
    for i, fname in enumerate(fnames):
        m = np.load(fname, mmap_mode='r') # mmap so we read only header really fast
        if i == 0:
            dtype = m.dtype
            shape_1 = m.shape[1]
        else:
            assert m.dtype == dtype
            assert m.shape[1] == shape_1
        shape_0 += m.shape[0]
    return {'descr': fmt.dtype_to_descr(dtype), 'fortran_order': False, 'shape': (shape_0, shape_1)}

def concatenate(res_fname, input_fnames):
    header = get_header(input_fnames)
    with open(res_fname, 'wb') as f:
        fmt.write_array_header_2_0(f, header)
        for fname in input_fnames:
            m = np.load(fname)
            f.write(m.tostring('C'))

如果你需要一个更通用的解决方案(在添加的同时编辑标题),你必须求助于fseek技巧,如[1]。
灵感来自
[1]:https://mail.scipy.org/pipermail/numpy-discussion/2009-August/044570.html(开箱即用不工作)
[2]:https://docs.scipy.org/doc/numpy/neps/npy-format.html
[3]:https://github.com/numpy/numpy/blob/master/numpy/lib/format.py

z0qdvdin

z0qdvdin5#

要使用www.example.com将数据附加到已经存在的文件中numpy.save,我们应该用途:

f_handle = file(filename, 'a')
numpy.save(f_handle, arr)
f_handle.close()

我已经检查了它在python2.7和numpy1.10.4中工作
我改编了here中的代码,其中谈到了savetxt方法。

6yt4nkrj

6yt4nkrj6#

您可以尝试阅读文件,然后添加新数据

import numpy as np
import os.path

x = np.arange(10) #[0 1 2 3 4 5 6 7 8 9]

y = np.load("save.npy") if os.path.isfile("save.npy") else [] #get data if exist
np.save("save.npy",np.append(y,x)) #save the new

2次手术后:

print(np.load("save.npy")) #[0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9]
amrnrhlw

amrnrhlw7#

以下是基于PaxRomana99的答案。它创建了一个类,您可以使用它来保存和加载数组。理想情况下,每次添加新数组时,也会更改npy文件的头部,以便修改形状的描述(有关头部的描述,请参阅here

import numpy as np
import pickle

from pathlib import Path
import os

class npyAppendableFile():
    def __init__(self, fname, newfile=True):
        '''
        Creates a new instance of the appendable filetype
        If newfile is True, recreate the file even if already exists
        '''
        self.fname=Path(fname)
        if newfile:
            with open(self.fname, "wb") as fh:
                fh.close()
        
    def write(self, data):
        '''
        append a new array to the file
        note that this will not change the header
        '''
        with open(self.fname, "ab") as fh:
            np.save(fh, data)
            
    def load(self, axis=2):
        '''
        Load the whole file, returning all the arrays that were consecutively
        saved on top of each other
        axis defines how the arrays should be concatenated
        '''
        
        with open(self.fname, "rb") as fh:
            fsz = os.fstat(fh.fileno()).st_size
            out = np.load(fh)
            while fh.tell() < fsz:
                out = np.concatenate((out, np.load(fh)), axis=axis)
            
        return out
    
    
    def update_content(self):
        '''
        '''
        content = self.load()
        with open(self.fname, "wb") as fh:
            np.save(fh, content)

    @property
    def _dtype(self):
        return self.load().dtype

    @property
    def _actual_shape(self):
        return self.load().shape
    
    @property
    def header(self):
        '''
        Reads the header of the npy file
        '''
        with open(self.fname, "rb") as fh:
            version = np.lib.format.read_magic(fh)
            shape, fortran, dtype = np.lib.format._read_array_header(fh, version)
        
        return version, {'descr': dtype,
                         'fortran_order' : fortran,
                         'shape' : shape}
                
        
      
arr_a = np.random.rand(5,40,10)
arr_b = np.random.rand(5,40,7)    
arr_c = np.random.rand(5,40,3)    

f = npyAppendableFile("testfile.npy", True)        

f.write(arr_a)
f.write(arr_b)
f.write(arr_c)

out = f.load()

print (f.header)
print (f._actual_shape)

# after update we can load with regular np.load()
f.update_content()

new_content = np.load('testfile.npy')
print (new_content.shape)

相关问题