读取和写入文件#

本页讨论了常见的应用;有关完整的 I/O 例程集合,请参见 输入和输出 .

读取文本和 CSV 文件#

没有缺失值#

使用 numpy.loadtxt .

有缺失值#

使用 numpy.genfromtxt .

numpy.genfromtxt 将会

  • 返回一个 masked array ,屏蔽掉缺失值 (如果 usemask=True ),或者

  • filling_values 中指定的值填充缺失值 (对于 float,默认为 np.nan ,对于 int,默认为 -1).

使用非空白分隔符#

>>> with open("csv.txt", "r") as f:
...     print(f.read())
1, 2, 3
4,, 6
7, 8, 9
Masked-array 输出#
>>> np.genfromtxt("csv.txt", delimiter=",", usemask=True)
masked_array(
  data=[[1.0, 2.0, 3.0],
        [4.0, --, 6.0],
        [7.0, 8.0, 9.0]],
  mask=[[False, False, False],
        [False,  True, False],
        [False, False, False]],
  fill_value=1e+20)
数组输出#
>>> np.genfromtxt("csv.txt", delimiter=",")
array([[ 1.,  2.,  3.],
       [ 4., nan,  6.],
       [ 7.,  8.,  9.]])
数组输出,指定填充值#
>>> np.genfromtxt("csv.txt", delimiter=",", dtype=np.int8, filling_values=99)
array([[ 1,  2,  3],
       [ 4, 99,  6],
       [ 7,  8,  9]], dtype=int8)

空白分隔#

如果满足以下条件, numpy.genfromtxt 也可以解析具有缺失值的空白分隔数据文件:

  • 每个字段都有一个固定的宽度:使用该宽度作为 delimiter 参数.:

    # File with width=4. The data does not have to be justified (for example,
    # the 2 in row 1), the last column can be less than width (for example, the 6
    # in row 2), and no delimiting character is required (for instance 8888 and 9
    # in row 3)
    
    >>> with open("fixedwidth.txt", "r") as f:
    ...    data = (f.read())
    >>> print(data)
    1   2      3
    44      6
    7   88889
    
    # Showing spaces as ^
    >>> print(data.replace(" ","^"))
    1^^^2^^^^^^3
    44^^^^^^6
    7^^^88889
    
    >>> np.genfromtxt("fixedwidth.txt", delimiter=4)
    array([[1.000e+00, 2.000e+00, 3.000e+00],
           [4.400e+01,       nan, 6.000e+00],
           [7.000e+00, 8.888e+03, 9.000e+00]])
    
  • 一个特殊的值 (例如 “x”) 指示一个缺失字段:使用它作为 missing_values 参数.

    >>> with open("nan.txt", "r") as f:
    ...     print(f.read())
    1 2 3
    44 x 6
    7  8888 9
    
    >>> np.genfromtxt("nan.txt", missing_values="x")
    array([[1.000e+00, 2.000e+00, 3.000e+00],
           [4.400e+01,       nan, 6.000e+00],
           [7.000e+00, 8.888e+03, 9.000e+00]])
    
  • 你想跳过带有缺失值的行:设置 invalid_raise=False .

    >>> with open("skip.txt", "r") as f:
    ...     print(f.read())
    1 2   3
    44    6
    7 888 9
    
    >>> np.genfromtxt("skip.txt", invalid_raise=False)  
    __main__:1: ConversionWarning: Some errors were detected !
        Line #2 (got 2 columns instead of 3)
    array([[  1.,   2.,   3.],
           [  7., 888.,   9.]])
    
  • 分隔符空白字符与指示缺失数据的空白不同.例如,如果列由 \t 分隔,那么如果缺失数据由一个或多个空格组成,则可以识别缺失数据.:

    >>> with open("tabs.txt", "r") as f:
    ...    data = (f.read())
    >>> print(data)
    1       2       3
    44              6
    7       888     9
    
    # Tabs vs. spaces
    >>> print(data.replace("\t","^"))
    1^2^3
    44^ ^6
    7^888^9
    
    >>> np.genfromtxt("tabs.txt", delimiter="\t", missing_values=" +")
    array([[  1.,   2.,   3.],
           [ 44.,  nan,   6.],
           [  7., 888.,   9.]])
    

读取 .npy 或 .npz 格式的文件#

选项:

写入文件以便 NumPy 读回#

二进制#

使用 numpy.save ,或要存储多个数组,请使用 numpy.saveznumpy.savez_compressed .

为了 security and portability ,设置 allow_pickle=False ,除非 dtype 包含 Python 对象,这需要进行 pickle 操作.

屏蔽数组 can't currently be saved ,其他任意数组子类也不行.

人类可读#

numpy.savenumpy.savez 创建二进制文件.要写入人类可读的文件,请使用 numpy.savetxt .数组只能是 1 维或 2 维的,并且没有用于多个文件的 ` savetxtz` .

大型数组#

请参阅 写入或读取大型数组 .

读取任意格式的二进制文件("二进制 blob")#

使用 structured array .

示例:

.wav 文件头是 44 字节的块,位于实际声音数据的 data_size 字节之前:

chunk_id         "RIFF"
chunk_size       4-byte unsigned little-endian integer
format           "WAVE"
fmt_id           "fmt "
fmt_size         4-byte unsigned little-endian integer
audio_fmt        2-byte unsigned little-endian integer
num_channels     2-byte unsigned little-endian integer
sample_rate      4-byte unsigned little-endian integer
byte_rate        4-byte unsigned little-endian integer
block_align      2-byte unsigned little-endian integer
bits_per_sample  2-byte unsigned little-endian integer
data_id          "data"
data_size        4-byte unsigned little-endian integer

.wav 文件头作为 NumPy 结构化 dtype:

wav_header_dtype = np.dtype([
    ("chunk_id", (bytes, 4)), # flexible-sized scalar type, item size 4
    ("chunk_size", "<u4"),    # little-endian unsigned 32-bit integer
    ("format", "S4"),         # 4-byte string, alternate spelling of (bytes, 4)
    ("fmt_id", "S4"),
    ("fmt_size", "<u4"),
    ("audio_fmt", "<u2"),     #
    ("num_channels", "<u2"),  # .. more of the same ...
    ("sample_rate", "<u4"),   #
    ("byte_rate", "<u4"),
    ("block_align", "<u2"),
    ("bits_per_sample", "<u2"),
    ("data_id", "S4"),
    ("data_size", "<u4"),
    #
    # the sound data itself cannot be represented here:
    # it does not have a fixed size
])

header = np.fromfile(f, dtype=wave_header_dtype, count=1)[0]

这个 .wav 示例仅用于说明;要在实际应用中读取 .wav 文件,请使用 Python 的内置模块 wave .

(改编自 Pauli Virtanen, Advanced NumPy ,根据 CC BY 4.0 许可.)

写入或读取大型数组#

可以使用内存映射将大到无法放入内存的数组像普通的内存数组一样处理.

  • 可以使用 numpy.ndarray.tofile 读取使用 numpy.ndarray.tobytesnumpy.memmap 写入的原始数组数据:

    array = numpy.memmap("mydata/myarray.arr", mode="r", dtype=np.int16, shape=(1024, 1024))
    
  • 可以使用带有 mmap_mode 关键字参数的 numpy.save 读取 numpy.load 输出的文件(即使用 numpy 格式):

    large_array[some_slice] = np.load("path/to/small_array", mmap_mode="r")
    

内存映射缺乏数据分块和压缩等功能;可与 NumPy 一起使用的功能更全的格式和库包括:

对于 memmap,Zarr 和 HDF5 之间的权衡,请参阅 pythonspeed.com .

写入文件以供其他(非 NumPy)工具读取#

与其他工具交换数据的格式包括 HDF5,Zarr 和 NetCDF(请参阅 写入或读取大型数组 ).

写入或读取 JSON 文件#

NumPy 数组和大多数 NumPy 标量不能直接进行 JSON serializable .而是使用自定义的 json.JSONEncoder 处理 NumPy 类型,可以使用您喜欢的搜索引擎找到它.

使用 pickle 文件保存/恢复#

尽可能避免; pickles 对于错误的或恶意构造的数据是不安全的.

使用 numpy.savenumpy.load .设置 allow_pickle=False ,除非阵列 dtype 包含 Python 对象,在这种情况下,需要进行 pickle.

numpy.loadpickle 子模块也支持 unpickling 使用 NumPy 1.26 创建的文件.

从 pandas DataFrame 转换为 NumPy 数组#

请参阅 pandas.Series.to_numpy .

使用 tofilefromfile 保存/恢复#

通常,首选 numpy.savenumpy.load .

numpy.ndarray.tofilenumpy.fromfile 丢失了关于字节序和精度的信息,因此不适合除临时存储之外的任何用途.