Сложная структура данных, подобная Matlab, в python (numpy/scipy)

У меня есть данные, которые в настоящее время структурированы следующим образом в Matlab

item{i}.attribute1(2,j)

Где элемент - ячейка из я = 1.. n, каждая из которых содержит структуру данных из нескольких атрибутов, каждая из которых имеет размер матрицы 2, j, где j = 1.. m. Число атрибутов не фиксировано.

Мне нужно перевести эту структуру данных на python, но я новичок в списках numpy и python. Каков наилучший способ структурирования этих данных в python с помощью numpy/scipy?

Спасибо.

Ответ 1

Я часто видел следующие подходы к преобразованию:

массив matlab → массив python numpy

Матовая ячейка ячейки → список python

Структура matlab → python dict

Итак, в вашем случае это будет соответствовать списку python, содержащему dicts, которые сами содержат массивы numpy в качестве записей

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

Примечание

Не забывайте 0-индексацию в 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

Если вы ищете хороший пример создания структурированного массива в Python, как это делается в MATLAB, вам может потребоваться посмотреть скудную домашнюю страницу (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)

Ответ 3

Для некоторых приложений достаточно dict или списка словарей. Однако, если вы действительно хотите эмулировать MATLAB struct в Python, вам нужно воспользоваться преимуществами его ООП и сформировать свой собственный структурный класс.

Это простой пример, например, который позволяет хранить произвольное количество переменных в качестве атрибутов и также может быть инициализирован как пустой (только 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

и для объекта c:

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

Обратите внимание, что назначение атрибутов объектам является общим - оно не только ограничено объектами scipy/numpy, но применимо ко всем типам данных и пользовательским объектам (массивам, фреймам данных и т.д.). Конечно, это игрушечная модель - вы можете ее доработать, чтобы ее можно было индексировать, печатать, печатать, удалять элементы, вызывать и т.д. В зависимости от потребностей вашего проекта. Просто определите класс в начале, а затем используйте его для хранения-поиска. В том, что красота Python - это не совсем то, что вы ищете, особенно если вы приехали из MATLAB, но он может сделать гораздо больше!