如何从 Python 创建具有 Matlab 数据结构中的多维数组的 Matlab 文件?



我正在尝试从Python创建一个Matlab文件(*.mat(,其中包含一个Matlab数据结构,如下所示:

s.key1 where key1 is an array of values
s.key2 where key2 is an array of 1D arrays 
s.key3 where key3 is an array of 2D arrays 

如果我使用 savemat 和字典,Matlab 输出是一个单元格数组,而不是 Matlab 数据结构。

我试过使用

np.core.records.fromarrays(data_list, names=q_keys)

但这似乎不适用于带有 2D 数组的键。我有 2D 和 3D 数组,它们需要采用 Matlab 结构才能与现有文件格式兼容。有没有办法在Python中做到这一点?

谢谢

这是对任务的尝试:

In [292]: dt = np.dtype([('key1',int),('key2',int, (3,)),('key3',object)])
In [293]: arr = np.zeros((5,), dt)
In [294]: arr
Out[294]: 
array([(0, [0, 0, 0], 0), (0, [0, 0, 0], 0), (0, [0, 0, 0], 0),
(0, [0, 0, 0], 0), (0, [0, 0, 0], 0)],
dtype=[('key1', '<i8'), ('key2', '<i8', (3,)), ('key3', 'O')])
In [295]: arr['key1']=np.arange(5)
In [296]: arr['key2']=np.arange(15).reshape(5,3)
In [302]: arr['key3']=[1,np.arange(5),np.ones((2,3),int),'astring',[['a','b']]]
In [303]: io.savemat('test.mat', {'astruct':arr})

八度:

>> load test.mat
>> format compact
>> astruct
astruct =
1x5 struct array containing the fields:
key1
key2
key3
>> astruc.key1
error: 'astruc' undefined near line 1 column 1
>> astruct.key1
ans = 0
ans = 1
ans = 2
ans = 3
ans = 4
>> astruct.key2
ans =
0  1  2
ans =
3  4  5
ans =
6  7  8
ans =
9  10  11
ans =
12  13  14
>> astruct.key3
ans = 1
ans =
0  1  2  3  4
ans =
1  1  1
1  1  1
ans = astring
ans = ab

回到ipython

In [304]: d = io.loadmat('test.mat')
In [305]: d
Out[305]: 
{'__header__': b'MATLAB 5.0 MAT-file Platform: posix, Created on: Wed Jun  6 15:36:23 2018',
'__version__': '1.0',
'__globals__': [],
'astruct': array([[(array([[0]]), array([[0, 1, 2]]), array([[1]])),
(array([[1]]), array([[3, 4, 5]]), array([[0, 1, 2, 3, 4]])),
(array([[2]]), array([[6, 7, 8]]), array([[1, 1, 1],
[1, 1, 1]])),
(array([[3]]), array([[ 9, 10, 11]]), array(['astring'], dtype='<U7')),
(array([[4]]), array([[12, 13, 14]]), array([['a', 'b']], dtype='<U1'))]],
dtype=[('key1', 'O'), ('key2', 'O'), ('key3', 'O')])}

因此,当一个创建了一个numpy结构化数组,其中包含intint(3)等 dtype,但加载的数组具有所有字段的对象 dtype。loadmat大量使用对象dtype数组来处理MATLAB单元和结构的通用性。loadmat具有各种加载参数,我们可以使用这些参数。

这只是基于以前加载 MATLAB 文件的经验的猜测。 如果这不是您想要的,我建议在 MATLAB 中构建示例数据,保存它,然后加载以查看loadmat如何构造它。 您可能需要来回几次才能解决错误。

根据 hpaulj 提供的方向,我开发了以下函数,该函数从对象列表创建了一个结构。

def listobj2struct(list_in):
"""Converts a list of objects to a structured array.
Parameters
----------
list_in: list
List of objects
Returns
-------
struct: np.array
Structured array
"""
# Create data type for each variable in object
keys = list(vars(list_in[0]).keys())
data_type = []
for key in keys:
data_type.append((key, list))
# Create structured array based on data type and length of list
dt = np.dtype(data_type)
struct = np.zeros((len(list_in),), dt)
# Populate the structure with data from the objects
for n, item in enumerate(list_in):
new_dict = vars(item)
for key in new_dict:
struct[key][n] = new_dict[key]
return struct

为了完成从复杂的对象嵌套创建 Matlab 文件所需的操作,我还编写了以下函数。也许这将帮助其他面临类似任务的人。可能有更好的方法,但这对我有用。

def obj2dict(obj):
"""Converts object variables to dictionaries. Works recursively to all levels of objects.
Parameters
----------
obj: object
Object of some class
Returns
-------
obj_dict: dict
Dictionary of all object variables
"""
obj_dict = vars(obj)
for key in obj_dict:
# Clean out NoneTypes
if obj_dict[key] is None:
obj_dict[key] = []
# If variable is another object convert to dictionary recursively
elif str(type(obj_dict[key]))[8:13] == 'Class':
obj_dict[key]=obj2dict(obj_dict[key])
return obj_dict

def listobj2dict(list_in):
"""Converts list of objects to list of dictionaries. Works recursively to all levels of objects.
Parameters
----------
obj: object
Object of some class
Returns
-------
new_list: list
List of dictionaries
"""
new_list = []
for obj in list_in:
new_list.append(obj2dict(obj))
return new_list

def listdict2struct(list_in):
"""Converts a list of dictionaries to a structured array.
Parameters
----------
list_in: list
List of dictionaries
Returns
-------
struct: np.array
Structured array
"""
# Create data type for each variable in object
keys = list(list_in[0].keys())
data_type = []
for key in keys:
data_type.append((key, list))
# Create structured array based on data type and length of list
dt = np.dtype(data_type)
struct = np.zeros((len(list_in),), dt)
# Populate the structure with data from the objects
for n, item in enumerate(list_in):
new_dict = item
for key in new_dict:
struct[key][n] = new_dict[key]
return struct

最新更新