简体   繁体   English

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

[英]How can I create a Matlab file from Python with multi-dimensional arrays in a Matlab data structure?

I am trying to create a Matlab file (*.mat) from Python that contains a Matlab data structure that would look like: 我正在尝试从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 

If I use savemat and a dictionary, the Matlab output is a cell array rather than a Matlab data structure. 如果我使用savemat和字典,则Matlab输出是一个单元格数组而不是Matlab数据结构。

I have tried using 我尝试使用

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

but this doesn't seem to work for keys with 2D arrays. 但这似乎不适用于带有2D数组的键。 I have both 2D and 3D arrays that need to be in a Matlab structure for compatibility with an existing file format. 我有2D和3D阵列,都需要采用Matlab结构才能与现有文件格式兼容。 Is there a way to do this in Python? 有没有办法在Python中做到这一点?

Thanks 谢谢

Here's a stab at the task: 这是该任务的一个刺路:

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})

In Octave: 在八度音阶中:

>> 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

Back in ipython : 回到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')])}

So while a created a numpy structured array with dtypes like int and int(3) , the loaded array has object dtype for all fields. 因此,当使用intint(3)等dtypes创建numpy结构化数组时,加载的数组的所有字段都具有dtype对象。 loadmat makes heavy use of object dtype arrays to handle the generality of MATLAB cells and struct. loadmat大量使用对象dtype数组来处理MATLAB单元和结构的一般性。 loadmat has various loading parameters, which we can play with. loadmat具有各种加载参数,我们可以使用它们。

This was just a guess based on previous experience loading MATLAB files. 这只是基于以前加载MATLAB文件的经验所做的猜测。 If this isn't what you want, I'd suggest constructing sample data in MATLAB, save that, and then load to see how loadmat constructs it. 如果这不是您想要的,我建议您在MATLAB中构造示例数据,将其保存,然后加载以查看loadmat如何构造它。 You may have to go back and forth a few times to work out the bugs. 您可能需要来回几次才能找出错误。

Given the direction provided by hpaulj, I developed the following function that created a structure from a list of objects. 根据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

To complete what I needed to do to create a Matlab file from a complex nesting of objects I also wrote the following functions. 为了完成从复杂的对象嵌套创建Matlab文件所需的工作,我还编写了以下函数。 Perhaps this will help others facing similar tasks. 也许这将帮助其他面临类似任务的人。 There may be better ways, but this worked for me. 也许有更好的方法,但这对我有用。

    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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM