文件 I/O (scipy.io)#

另请参阅

NumPy I/O 例程

MATLAB 文件#

loadmat(file_name[, mdict, appendmat])

加载 MATLAB 文件。

savemat(file_name, mdict[, appendmat, ...])

将名称和数组的字典保存到 MATLAB 风格的 .mat 文件中。

whosmat(file_name[, appendmat])

列出 MATLAB 文件中的变量。

基本函数#

首先导入 scipy.io 并将其称为 sio 以方便起见

>>> import scipy.io as sio

如果使用的是 IPython,请尝试对 sio 进行制表符补全。在众多选项中,你会发现

sio.loadmat
sio.savemat
sio.whosmat

这些是你在处理 MATLAB 文件时最有可能使用的顶级函数。你还会发现

sio.matlab

这是 loadmatsavematwhosmat 从中导入的包。在 sio.matlab 中,你会发现 mio 模块。该模块包含 loadmatsavemat 使用的机制。你可能会发现自己偶尔会重复使用此机制。

如何开始?#

你可能有一个 .mat 文件,你想将其读入 SciPy。或者,你想将一些变量从 SciPy/NumPy 传递到 MATLAB 中。

为了避免使用 MATLAB 许可证,让我们从 Octave 开始。Octave 具有与 MATLAB 兼容的保存和加载函数。启动 Octave(对于我来说,在命令行中为 octave

octave:1> a = 1:12
a =

   1   2   3   4   5   6   7   8   9  10  11  12

octave:2> a = reshape(a, [1 3 4])
a =

ans(:,:,1) =

   1   2   3

ans(:,:,2) =

   4   5   6

ans(:,:,3) =

   7   8   9

ans(:,:,4) =

   10   11   12

octave:3> save -6 octave_a.mat a % MATLAB 6 compatible
octave:4> ls octave_a.mat
octave_a.mat

现在,转到 Python

>>> mat_contents = sio.loadmat('octave_a.mat')
>>> mat_contents
{'__header__': b'MATLAB 5.0 MAT-file, written
 by Octave 3.2.3, 2010-05-30 02:13:40 UTC',
 '__version__': '1.0',
 '__globals__': [],
 'a': array([[[ 1.,  4.,  7., 10.],
              [ 2.,  5.,  8., 11.],
              [ 3.,  6.,  9., 12.]]])}
>>> oct_a = mat_contents['a']
>>> oct_a
array([[[  1.,   4.,   7.,  10.],
        [  2.,   5.,   8.,  11.],
        [  3.,   6.,   9.,  12.]]])
>>> oct_a.shape
(1, 3, 4)

现在让我们尝试反过来

>>> import numpy as np
>>> vect = np.arange(10)
>>> vect.shape
(10,)
>>> sio.savemat('np_vector.mat', {'vect':vect})

然后返回 Octave

octave:8> load np_vector.mat
octave:9> vect
vect =

  0  1  2  3  4  5  6  7  8  9

octave:10> size(vect)
ans =

    1   10

如果想在不将数据读入内存的情况下检查 MATLAB 文件的内容,请使用 whosmat 命令

>>> sio.whosmat('octave_a.mat')
[('a', (1, 3, 4), 'double')]

whosmat 返回一个元组列表,每个元组对应文件中一个数组(或其他对象)。每个元组包含数组的名称、形状和数据类型。

MATLAB 结构体#

MATLAB 结构体有点像 Python 字典,但字段名称必须是字符串。任何 MATLAB 对象都可以作为字段的值。对于 MATLAB 中的所有对象,结构体实际上是结构体数组,其中单个结构体是形状为 (1, 1) 的数组。

octave:11> my_struct = struct('field1', 1, 'field2', 2)
my_struct =
{
  field1 =  1
  field2 =  2
}

octave:12> save -6 octave_struct.mat my_struct

我们可以在 Python 中加载它

>>> mat_contents = sio.loadmat('octave_struct.mat')
>>> mat_contents
 {'__header__': b'MATLAB 5.0 MAT-file, written by Octave 3.2.3, 2010-05-30 02:00:26 UTC',
  '__version__': '1.0',
  '__globals__': [],
  'my_struct': array([[(array([[1.]]), array([[2.]]))]], dtype=[('field1', 'O'), ('field2', 'O')])
 }
>>> oct_struct = mat_contents['my_struct']
>>> oct_struct.shape
(1, 1)
>>> val = oct_struct[0,0]
>>> val
([[1.0]], [[2.0]])
>>> val['field1']
array([[ 1.]])
>>> val['field2']
array([[ 2.]])
>>> val.dtype
dtype([('field1', 'O'), ('field2', 'O')])

在 0.12.0 版及之后的 SciPy 版本中,MATLAB 结构体以 NumPy 结构化数组的形式返回,字段名为结构体字段。你可以在上面的 dtype 输出中看到字段名称。还要注意

>>> val = oct_struct[0,0]

octave:13> size(my_struct)
ans =

   1   1

因此,在 MATLAB 中,结构体数组必须至少是二维的,我们在读入 SciPy 时也会复制这一点。如果你想将所有长度为 1 的维度挤出来,请尝试以下操作

>>> mat_contents = sio.loadmat('octave_struct.mat', squeeze_me=True)
>>> oct_struct = mat_contents['my_struct']
>>> oct_struct.shape
()

有时,将 MATLAB 结构体加载为 Python 对象而不是 NumPy 结构化数组会更方便——这可以使 Python 中的访问语法更类似于 MATLAB 中的语法。为了做到这一点,请将 struct_as_record=False 参数设置为 loadmat

>>> mat_contents = sio.loadmat('octave_struct.mat', struct_as_record=False)
>>> oct_struct = mat_contents['my_struct']
>>> oct_struct[0,0].field1
array([[ 1.]])

struct_as_record=Falsesqueeze_me 配合得很好

>>> mat_contents = sio.loadmat('octave_struct.mat', struct_as_record=False, squeeze_me=True)
>>> oct_struct = mat_contents['my_struct']
>>> oct_struct.shape # but no - it's a scalar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'mat_struct' object has no attribute 'shape'
>>> type(oct_struct)
<class 'scipy.io.matlab._mio5_params.mat_struct'>
>>> oct_struct.field1
1.0

保存结构体数组可以通过多种方式完成。一种简单的方法是使用字典

>>> a_dict = {'field1': 0.5, 'field2': 'a string'}
>>> sio.savemat('saved_struct.mat', {'a_dict': a_dict})

加载为

octave:21> load saved_struct
octave:22> a_dict
a_dict =

  scalar structure containing the fields:

    field2 = a string
    field1 =  0.50000

你也可以像这样将结构体保存回 MATLAB(或我们的情况下的 Octave)

>>> dt = [('f1', 'f8'), ('f2', 'S10')]
>>> arr = np.zeros((2,), dtype=dt)
>>> arr
array([(0.0, ''), (0.0, '')],
      dtype=[('f1', '<f8'), ('f2', 'S10')])
>>> arr[0]['f1'] = 0.5
>>> arr[0]['f2'] = 'python'
>>> arr[1]['f1'] = 99
>>> arr[1]['f2'] = 'not perl'
>>> sio.savemat('np_struct_arr.mat', {'arr': arr})

MATLAB 元胞数组#

MATLAB 中的元胞数组有点像 Python 列表,因为数组中的元素可以包含任何类型的 MATLAB 对象。实际上,它们最类似于 NumPy 对象数组,这就是我们将其加载到 NumPy 的方式。

octave:14> my_cells = {1, [2, 3]}
my_cells =
{
  [1,1] =  1
  [1,2] =

     2   3

}

octave:15> save -6 octave_cells.mat my_cells

回到 Python

>>> mat_contents = sio.loadmat('octave_cells.mat')
>>> oct_cells = mat_contents['my_cells']
>>> print(oct_cells.dtype)
object
>>> val = oct_cells[0,0]
>>> val
array([[ 1.]])
>>> print(val.dtype)
float64

保存到 MATLAB 元胞数组只是制作一个 NumPy 对象数组

>>> obj_arr = np.zeros((2,), dtype=object)
>>> obj_arr[0] = 1
>>> obj_arr[1] = 'a string'
>>> obj_arr
array([1, 'a string'], dtype=object)
>>> sio.savemat('np_cells.mat', {'obj_arr': obj_arr})
octave:16> load np_cells.mat
octave:17> obj_arr
obj_arr =
{
  [1,1] = 1
  [2,1] = a string
}

IDL 文件#

readsav(file_name[, idict, python_dict, ...])

读取 IDL .sav 文件。

Matrix Market 文件#

mminfo(source)

从类似文件的 Matrix Market 文件 'source' 返回大小和存储参数。

mmread(source)

将类似文件的 Matrix Market 文件 'source' 的内容读入矩阵中。

mmwrite(target, a[, comment, field, ...])

将稀疏或密集数组 a 写入类似文件的 Matrix Market 文件 target 中。

Wav 音频文件 (scipy.io.wavfile)#

read(filename[, mmap])

打开 WAV 文件。

write(filename, rate, data)

将 NumPy 数组写入 WAV 文件。

Arff 文件 (scipy.io.arff)#

loadarff(f)

读取 arff 文件。

Netcdf#

netcdf_file(filename[, mode, mmap, version, ...])

用于 NetCDF 数据的文件对象。

允许读取 NetCDF 文件(pupynere 包的版本)