使用scipy.io.savemat保存嵌套列表

时间:2016-08-15 18:05:25

标签: python python-2.7 scipy

这与我的上一个问题有关,可以找到here。我处理类似于我在该链接中描述的列表的列表作为markerList - 所以列表有三个级别。我需要将此信息保存为.mat文件,但我无法将其保存为正确的类型。当使用scipy.io.savemat时,它将列表保存为200x40x2单,当它应该是一组200个单元格,每个单元格包含一个40x2单元格。

我用来保存它的代码是:

matdict = dict(markers = (markerList), sorted = (finalStack))
scipy.io.savemat('C:\pathname\\sortedMarkers.mat', matdict)

让我感到困惑的是,它以正确的格式保存markerList(1x200单元,每个单元格大小不同),但不是finalStack(保存为200 x 40 x 2单)。最重要的是,在我弄清楚其余代码之前,它会正确地保存finalStack - 这让我觉得,当它保存的数据大小不均匀时,它可能会保存为单元格。 (finalStack的大小是统一的; markerList不是。)

有没有办法将像这样复杂的数据结构保存为.mat文件?

2 个答案:

答案 0 :(得分:3)

根据savemat documentation,转换为'对象'的numpy数组:

from scipy.io import savemat
import numpy

a = numpy.array([[1,2,3],[1,2,3]])
b = numpy.array([[2,3,4],[2,3,4]])
c = numpy.array([[3,4,5],[3,4,5]])
L = [a,b,c]

FrameStack = numpy.empty((len(L),), dtype=numpy.object)
for i in range(len(L)):
    FrameStack[i] = L[i]

savemat("myfile.mat", {"FrameStack":FrameStack})

八度音阶:

>> load myfile.mat 

>> whos FrameStack
Variables in the current scope:

   Attr Name            Size                     Bytes  Class
   ==== ====            ====                     =====  ===== 
        FrameStack      1x3                        144  cell

Total is 3 elements using 144 bytes

>> whos FrameStack{1}
Variables in the current scope:

   Attr Name               Size                     Bytes  Class
   ==== ====               ====                     =====  ===== 
        FrameStack{1}      2x3                         48  int64

Total is 6 elements using 48 bytes

答案 1 :(得分:1)

如果不再查看上一个问题,我怀疑现在问题是numpy.array从子列表或数组列表中创建数组。

您注意到markerList已按预期保存,且单元格大小不一。

尝试

np.array(markerList)

并查看其形状和dtype。我猜测它将是1d(200,)和对象dtype。

np.array(finalStack)
另一方面,

可能是它保存的3d数组。

savemat被设置为保存numpy数组,而不是python词典和列表 - 之后,所有人都在谈论MATLAB,其中所有东西都是二维矩阵。 MATLAB单元概括了这一点;它们更像是dd对象的2d numpy数组。

经常出现从大小一致的元素创建对象数组的问题。通常的解决方案是创建所需大小的empty数组(例如(200,))和对象类型,并将子数组加载到其中。

https://stackoverflow.com/a/38776674/901925

=============

我将演示。制作3个数组,2个一个大小,不同的第三个:

In [59]: from scipy import io

In [60]: A=np.ones((40,2))    
In [61]: B=np.ones((40,2))
In [62]: C=np.ones((30,2))

保存两个列表,一个只有两个数组,另一个包含所有三个:

In [63]: io.savemat('test.mat', {'AB':[A,B],'ABC':[A,B,C]})

加载它;我可以在octave中执行此操作:

In [65]: D=io.loadmat('test.mat')

In [66]: D.keys()
Out[66]: dict_keys(['ABC', '__header__', 'AB', '__globals__', '__version__'])

ABC是一个包含3个元素的二维数组

In [68]: D['ABC'].shape
Out[68]: (1, 3)
In [71]: D['ABC'][0,0].shape
Out[71]: (40, 2)

AB已转换为3d数组:

In [69]: D['AB'].shape
Out[69]: (2, 40, 2)
In [70]: np.array([A,B]).shape
Out[70]: (2, 40, 2)

如果我改为创建一个1d对象数组来保存A和B,它将被保留:

In [72]: AB=np.empty((2,),object)
In [73]: AB[...]=[A,B]
In [74]: AB.shape
Out[74]: (2,)

In [75]: io.savemat('test.mat', {'AB':AB,'ABC':[A,B,C]})
In [76]: D=io.loadmat('test.mat')

In [77]: D['AB'].shape
Out[77]: (1, 2)
In [78]: D['AB'][0,0].shape
Out[78]: (40, 2)

一个很好的选择是将数组保存为字典的项目

io.savemat('test.mat',{'A':A, 'B':B, 'C':C})

鉴于将MATLAB结构转换为numpy结构并将其转化为困难,最好保持平坦和简单,而不是创建对双方都有用的复合对象。

===============

我安装了Octave。加载此test.mat

io.savemat('test.mat', {'AB':AB,'ABs':[A,B]})

给出

>> whos
Variables in the current scope:

   Attr Name        Size                     Bytes  Class
   ==== ====        ====                     =====  =====
        AB          1x2                       1280  cell
        ABs         2x40x2                    1280  double

将对象dtype数组保存为matlab单元格;其他数组作为matlab矩阵。 (我必须回顾一下前面的答案,回忆一下matlab结构的等价物。)