
本文详解如何使用scipy.io.loadmat读取包含嵌套结构体(struct)的matlab .mat文件,并将其中的fanmap和fanmap1d等复合字段批量提取为独立的numpy数组,适用于科学计算与机器学习数据预处理场景。
MATLAB .mat 文件(尤其是v7.3以下版本)常以结构体(struct)形式存储多组异构数组,例如本例中的 'fanmap' 和 'fanmap1D'。它们并非普通NumPy兼容的数组,而是numpy.ndarray类型的0维结构数组(shape (1,) 或 (1, 1)),内部通过 dtype.names 定义字段名,需先解包再转为标准NumPy数组。
正确做法是:先访问结构体字段(如 mat['fanmap'][0, 0]),再遍历其 dtype.names 获取所有子数组名,最后逐个索引并显式调用 np.array() 转换(确保去除MATLAB特有的对象包装,获得原生 ndarray)。以下是完整可运行代码:
from scipy.io import loadmat
import numpy as np
# 加载.mat文件
mat = loadmat("FanMap_data.mat")
# 提取fanmap结构体中的所有字段(每个字段对应一个NumPy数组)
if 'fanmap' in mat and mat['fanmap'].size > 0:
fanmap_struct = mat['fanmap'][0, 0] # 解包0维结构数组
fanmap_arrays = {
key: np.array(fanmap_struct[key]).squeeze() # .squeeze()可选:移除长度为1的维度(如(1,15)→(15,))
for key in fanmap_struct.dtype.names
}
else:
fanmap_arrays = {}
# 同理处理fanmap1D
if 'fanmap1D' in mat and mat['fanmap1D'].size > 0:
fanmap1D_struct = mat['fanmap1D'][0, 0]
fanmap1D_arrays = {
key: np.array(fanmap1D_struct[key]).squeeze()
for key in fanmap1D_struct.dtype.names
}
else:
fanmap1D_arrays = {}
# 打印结果验证形状
print("Arrays in 'fanmap':")
for name, arr in fanmap_arrays.items():
print(f" {name}: shape = {arr.shape}, dtype = {arr.dtype}")
print("\nArrays in 'fanmap1D':")
for name, arr in fanmap1D_arrays.items():
print(f" {name}: shape = {arr.shape}, dtype = {arr.dtype}")⚠️ 关键注意事项:
- mat['fanmap'] 返回的是形状为 (1, 1) 的结构数组,必须通过 [0, 0] 索引获取内部结构体对象;
- 直接对 mat['fanmap'][0, 0][key] 调用 np.array() 是必要的——MATLAB结构体字段可能返回 numpy.matrix 或嵌套对象,np.array() 确保统一为 ndarray;
- 使用 .squeeze() 可智能压缩单维(如 (1, 15) → (15,)),便于后续广播运算;若需保留原始维度,请移除该调用;
- 若.mat文件为v7.3+格式(HDF5),则需改用 h5py 库读取,scipy.io.loadmat 将失效。
最终,所有数组均以字典形式组织(键为MATLAB字段名,值为标准NumPy数组),可直接用于SciPy、Scikit-learn或PyTorch等框架,实现MATLAB工作流到Python科学计算生态的无缝迁移。










