如何重构从Simulink .mat文件读取的嵌套Numpy结构化数组?
问题描述
我用Python的scipy.io.loadmat()读取了Simulink导出的.mat数据结构,想在Python中程序化重建这个结构,但始终无法正确实现多层嵌套。读取后的mat['rtp']['internal']结构如下:
>>> mat['rtp']['internal'] array( [[ array( [[ ( array( [[ array( [[ (array(['Br'], dtype='<U2'), array([[1]], dtype=uint8), array([[2]], dtype=uint8), array([[0]], dtype=uint8)), (array(['Ari'], dtype='<U3'), array([[1]], dtype=uint8), array([[3]], dtype=uint8), array([[0]], dtype=uint8)) ]], dtype=[('name', 'O'), ('transitionIdx', 'O'), ('mapIdx', 'O'), ('isStruct', 'O')] ) ]], dtype=object), ) ]], dtype=[('tunedParameters', 'O')] ) ]], dtype=object )
我已经写出了创建内部参数部分的代码(变量a):
import numpy as np dt = np.dtype([('name','O'),('transitionIdx','O'),('mapIdx','O'),('isStruct','O')]) all_entries = np.empty( 0, dtype=dt) # Br PARAMETERS: paramName = 'Br' transitionIdx = 1 paramIdx = 2 isStruct = 0 new_entry = np.empty( 1, dtype=dt) new_entry['name'] = [np.array( np.array([paramName]))] new_entry['transitionIdx'] = [np.array([np.array([transitionIdx])],dtype=np.uint8)] new_entry['mapIdx'] = [np.array([np.array([paramIdx])],dtype=np.uint8)] new_entry['isStruct'] = [np.array([np.array([isStruct])],dtype=np.uint8)] all_entries = np.append(all_entries, new_entry) # Ari PARAMETERS: paramName = 'Ari' transitionIdx = 1 paramIdx = 3 isStruct = 0 new_entry = np.empty( 1, dtype=dt) new_entry['name'] = [np.array( np.array([paramName]))] new_entry['transitionIdx'] = [np.array([np.array([transitionIdx])],dtype=np.uint8)] new_entry['mapIdx'] = [np.array([np.array([paramIdx])],dtype=np.uint8)] new_entry['isStruct'] = [np.array([np.array([isStruct])],dtype=np.uint8)] all_entries = np.append(all_entries, new_entry) print( f"all_entries = {all_entries}" ) print( f"all_entries.dtype = {all_entries.dtype}" ) a = np.array([all_entries,]) print( f"a = {a}" ) print( f"a.dtype = {a.dtype}" )
这段代码的输出是:
a = [[(array(['Br'], dtype='<U2'), array([[1]], dtype=uint8), array([[2]], dtype=uint8), array([[0]], dtype=uint8)) (array(['Ari'], dtype='<U3'), array([[1]], dtype=uint8), array([[3]], dtype=uint8), array([[0]], dtype=uint8))]] a.dtype = [('name', 'O'), ('transitionIdx', 'O'), ('mapIdx', 'O'), ('isStruct', 'O')]
但我没法实现类似array( [[ array( [[ array( [[的多层嵌套结构,不知道怎么完整重构这个数据结构。
编辑补充
根据建议,我写了一个遍历结构并打印数组类型和形状的脚本:
import numpy as np import scipy mat = scipy.io.loadmat( "simulink_model_input.mat", mat_dtype=True ) def traverse( mat_str ): mat = eval( mat_str ) if type( mat ) not in [str,np.str_]: print( f"{mat_str} type: {type(mat)} shape: {np.shape(mat)}, dtype: {mat.dtype}" ) traverse( mat_str + "[0]" ) traverse( "mat['rtp']['internal']" )
输出结果:
mat['rtp']['internal'] type: <class 'numpy.ndarray'> shape: (1, 1), dtype: object mat['rtp']['internal'][0] type: <class 'numpy.ndarray'> shape: (1,), dtype: object mat['rtp']['internal'][0][0] type: <class 'numpy.ndarray'> shape: (1, 1), dtype: [('tunedParameters', 'O')] mat['rtp']['internal'][0][0][0] type: <class 'numpy.ndarray'> shape: (1,), dtype: [('tunedParameters', 'O')] mat['rtp']['internal'][0][0][0][0] type: <class 'numpy.void'> shape: (), dtype: [('tunedParameters', 'O')] mat['rtp']['internal'][0][0][0][0][0] type: <class 'numpy.ndarray'> shape: (1, 1), dtype: object mat['rtp']['internal'][0][0][0][0][0][0] type: <class 'numpy.ndarray'> shape: (1,), dtype: object mat['rtp']['internal'][0][0][0][0][0][0][0] type: <class 'numpy.ndarray'> shape: (1, 2), dtype: [('name', 'O'), ('transitionIdx', 'O'), ('mapIdx', 'O'), ('isStruct', 'O')] mat['rtp']['internal'][0][0][0][0][0][0][0][0] type: <class 'numpy.ndarray'> shape: (2,), dtype: [('name', 'O'), ('transitionIdx', 'O'), ('mapIdx', 'O'), ('isStruct', 'O')] mat['rtp']['internal'][0][0][0][0][0][0][0][0][0] type: <class 'numpy.void'> shape: (), dtype: [('name', 'O'), ('transitionIdx', 'O'), ('mapIdx', 'O'), ('isStruct', 'O')] mat['rtp']['internal'][0][0][0][0][0][0][0][0][0][0] type: <class 'numpy.ndarray'> shape: (1,), dtype: <U2
我还是不清楚怎么推进,只要能搞懂一层嵌套的实现方式,应该就能完成剩下的部分。
解决方案
核心思路是从内到外逐层嵌套,每一层都严格匹配遍历结果中的shape和dtype:
import numpy as np # --- 保留你已有的参数生成代码 --- dt = np.dtype([('name','O'),('transitionIdx','O'),('mapIdx','O'),('isStruct','O')]) all_entries = np.empty(0, dtype=dt) # Br参数 paramName = 'Br' transitionIdx = 1 paramIdx = 2 isStruct = 0 new_entry = np.empty(1, dtype=dt) new_entry['name'] = [np.array([paramName])] new_entry['transitionIdx'] = [np.array([[transitionIdx]], dtype=np.uint8)] new_entry['mapIdx'] = [np.array([[paramIdx]], dtype=np.uint8)] new_entry['isStruct'] = [np.array([[isStruct]], dtype=np.uint8)] all_entries = np.append(all_entries, new_entry) # Ari参数 paramName = 'Ari' transitionIdx = 1 paramIdx = 3 isStruct = 0 new_entry = np.empty(1, dtype=dt) new_entry['name'] = [np.array([paramName])] new_entry['transitionIdx'] = [np.array([[transitionIdx]], dtype=np.uint8)] new_entry['mapIdx'] = [np.array([[paramIdx]], dtype=np.uint8)] new_entry['isStruct'] = [np.array([[isStruct]], dtype=np.uint8)] all_entries = np.append(all_entries, new_entry) # --- 已有代码结束 --- # 逐层构建嵌套结构 # 1. 包成(1,2)的结构化数组(对应遍历中的最内层参数数组上层) level7 = np.array([all_entries], dtype=dt) # 2. 包成(1,)的object数组 level6 = np.array([level7], dtype=object) # 3. 包成(1,1)的object数组 level5 = np.array([level6], dtype=object) # 4. 创建tunedParameters结构化类型,生成(1,1)的该类型数组并赋值 dt_tuned = np.dtype([('tunedParameters', 'O')]) level4 = np.empty((1,1), dtype=dt_tuned) level4['tunedParameters'] = level5 # 5. 包成(1,)的tunedParameters类型数组 level3 = np.array([level4[0][0]], dtype=dt_tuned) # 6. 包成(1,1)的object数组 level2 = np.array([level3], dtype=object) # 7. 包成(1,)的object数组 level1 = np.array([level2], dtype=object) # 8. 最外层:(1,1)的object数组,即目标结构 final_internal = np.array([level1], dtype=object) # 验证结构(用你之前的遍历逻辑) def traverse(obj, path="final_internal"): if not isinstance(obj, (str, np.str_)): print(f"{path} type: {type(obj)} shape: {np.shape(obj)}, dtype: {obj.dtype}") if hasattr(obj, '__getitem__') and np.shape(obj) != (): traverse(obj[0], path + "[0]") traverse(final_internal)
关键说明
- 每一层嵌套都用
np.array()包裹上一层数组,同时指定对应的dtype:要么是结构化类型(如dt、dt_tuned),要么是object类型(用于存放任意数组) - 结构化数组的赋值必须通过字段名(如
level4['tunedParameters'] = level5),确保嵌套数组被放到正确的字段中 - 严格匹配遍历结果中的
shape,比如最外层是(1,1)的object数组,每一层的形状都要和遍历输出对应
内容的提问来源于stack exchange,提问作者nwhite43
相关产品推荐
相关产品推荐

