Python(numpy / scipy)中类似Matlab的复杂数据结构

16

我目前在Matlab中有以下结构化的数据:

item{i}.attribute1(2,j)

其中item是i = 1 .. n中的单元格,每个单元格包含多个属性的数据结构,每个属性都是大小为2、j = 1 .. m的矩阵,属性数量不固定。

我需要将这个数据结构转换成Python格式,但我对numpy和python列表不熟悉。使用numpy/scipy在Python中组织这个数据的最佳方式是什么?

谢谢。


你需要如何处理这些数据?最简单的方法是将所有内容都倒入一个嵌套列表序列中,但我有一种隐约的感觉,这样做可能不支持你所寻求的功能类型。 - Silas Ray
4个回答

27

我经常看到以下转换方法:

Matlab 数组 -> Python NumPy 数组

Matlab cell 数组 -> Python 列表

Matlab 结构体 -> Python 字典

所以在你的情况下,对应的是一个包含字典的 Python 列表,这些字典本身包含作为条目的 NumPy 数组。

item[i]['attribute1'][2,j]

注意

别忘了在 Python 中从零开始编号!

[更新]

附加:使用类

除了上述简单的转换之外,你还可以定义一个虚拟类,例如

class structtype():
    pass

这允许以下类型的用法:

>> s1 = structtype()
>> print s1.a
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-40-7734865fddd4> in <module>()
----> 1 print s1.a
AttributeError: structtype instance has no attribute 'a'
>> s1.a=10
>> print s1.a
10

在这种情况下,您的示例变为例如:

>> item = [ structtype() for i in range(10)]
>> item[9].a = numpy.array([1,2,3])
>> item[9].a[1]
2

2

@dbouz提供的简单答案,使用了@jmetz的想法

class structtype():
    def __init__(self,**kwargs):
        self.Set(**kwargs)
    def Set(self,**kwargs):
        self.__dict__.update(kwargs)
    def SetAttr(self,lab,val):
        self.__dict__[lab] = val

那么你可以这样做:
myst = structtype(a=1,b=2,c=3)

或者

myst = structtype()
myst.Set(a=1,b=2,c=3)

并且仍然这样做

myst.d = 4 # here, myst.a=1, myst.b=2, myst.c=3, myst.d=4

甚至更多
myst = structtype(a=1,b=2,c=3)
lab = 'a'
myst.SetAttr(lab,10) # a=10,b=2,c=3 ... equivalent to myst.(lab)=10 in MATLAB

对于 myst=struct('a',1,'b',2,'c',3),在Matlab中您将得到预期的结果。

如果要使用结构体单元的等效形式,可以使用 structtypelist

mystarr = [ structtype(a=1,b=2) for n in range(10) ]

这将为您提供

mystarr[0].a # == 1
mystarr[0].b # == 2

1
如果您正在寻找一个好的示例,如何在Python中创建类似MATLAB中所做的结构化数组,您可能需要查看scipy主页(basics.rec)。

示例

x = np.zeros(1, dtype = [('Table', float64, (2, 2)),
                         ('Number', float),
                         ('String', '|S10')])

# Populate the array
x['Table']  = [1, 2]
x['Number'] = 23.5
x['String'] = 'Stringli'

# See what is written to the array
print(x)

打印输出结果如下:
[([[1.0, 2.0], [1.0, 2.0]], 23.5, 'Stringli')]

很不幸,我没有找到如何在不知道结构化数组大小的情况下定义结构化数组的方法。您也可以直接定义包含其内容的数组。
x = np.array(([[1, 2], [1, 2]], 23.5, 'Stringli'),
                dtype = [('Table', float64, (2, 2)),
                         ('Number', float),
                         ('String', '|S10')])

# Same result as above but less code (if you know the contents in advance)
print(x)

我能理解你想要忠实于Matlab格式,但是它的功能不就和字典一样吗? - zwep
1
@zwep 不,结构化数组上有更多的功能。NumPy也可以在这样的结构化数组上执行其优化算法。这就是我使用它的原因。 - strpeter
1
谢谢。看起来这些带有多索引的结构化数组可以像简单的Pandas数据框一样运作。太棒了! :) - zwep
嗯,pandas 依赖于 numpy。它只是在 numpy 数组上包了一点额外的东西。因此,我从未开始使用 pandas。我希望你现在理解了这种相似性的起源。 - strpeter

0
对于一些应用程序来说,一个`dict`或者字典列表就足够了。但是,如果你真的想在Python中模拟一个MATLAB的`struct`,你必须利用它的面向对象编程特性,创建一个类似于结构体的类。
这是一个简单的示例,允许你将任意数量的变量存储为属性,并且可以以空值初始化(仅适用于Python 3.x)。`i`是索引器,用于显示对象内部存储的属性数量。
class Struct:
    def __init__(self, *args, prefix='arg'): # constructor
        self.prefix = prefix
        if len(args) == 0:
            self.i = 0
        else:
            i=0
            for arg in args:
                i+=1
                arg_str = prefix + str(i)
                # store arguments as attributes
                setattr(self, arg_str, arg) #self.arg1 = <value>
            self.i = i
    def add(self, arg):
        self.i += 1
        arg_str = self.prefix + str(self.i)
        setattr(self, arg_str, arg)

你可以将它初始化为空(i=0),或者使用初始属性填充它。然后你可以随意添加属性。尝试以下操作:

b = Struct(5, -99.99, [1,5,15,20], 'sample', {'key1':5, 'key2':-100})
b.add(150.0001)
print(b.__dict__)
print(type(b.arg3))
print(b.arg3[0:2])
print(b.arg5['key1'])

c = Struct(prefix='foo')
print(c.i) # empty Struct
c.add(500) # add a value as foo1
print(c.__dict__)

将为对象 b 返回以下结果:

{'prefix': 'arg', 'arg1': 5, 'arg2': -99.99, 'arg3': [1, 5, 15, 20], 'arg4': 'sample', 'arg5': {'key1': 5, 'key2': -100}, 'i': 6, 'arg6': 150.0001}
<class 'list'>
[1, 5]
5

而对于Objective-C:

0
{'prefix': 'foo', 'i': 1, 'foo1': 500}

请注意,将属性分配给对象是通用的 - 不仅限于scipy/numpy对象,而且适用于所有数据类型和自定义对象(数组、数据框等)。当然,这只是一个玩具模型 - 您可以进一步开发它,使其能够被索引、漂亮地打印、删除元素、可调用等,根据您的项目需求。只需在开头定义类,然后将其用于存储-检索即可。这就是Python的美妙之处 - 它并没有完全满足您的需求,特别是如果您来自MATLAB,但它可以做更多的事情!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接