SciPy, ввод и вывод в MATLAB

jpp1bh3q5qfkjunosratzx9ytpw.jpeg

SciPy (произносится как сай пай) — это пакет прикладных математических процедур, основанный на расширении Numpy Python. С SciPy интерактивный сеанс Python превращается в такую же полноценную среду обработки данных и прототипирования сложных систем, как MATLAB, IDL, Octave, R-Lab и SciLab. В этом посте я хотел бы рассказать о возможностях пакета ввода/вывода scipy.io, который позволяет работать с файлами данных Octave и MATLAB.


Введение

Для начала импортируем пакет scipy.io следующим образом:

import scipy.io as sio

Основные процедуры пакета scipy.io, которые позволяют работать с файлами MATLAB:

sio.loadmat
sio.savemat
sio.whosmat

Чтобы не нарушать лицензионного соглашения MATLAB, работать будем в среде GNU Octave, которая имеет совместимые с MATLAB функции сохранения и загрузки. Введем в командной строке Octave:

octave:1> a = 1:12
a =
   1   2   3   4   5   6   7   8   9  10  11  12

octave:2> a = reshape(a, [1 3 4])
a =
ans(:,:,1) =
   1   2   3
ans(:,:,2) =
   4   5   6
ans(:,:,3) =
   7   8   9
ans(:,:,4) =
   10   11   12

octave:3> save -6 octave_a.mat a % MATLAB 6 compatible
octave:4> ls octave_a.mat
octave_a.mat

Код для импорта MATLAB файла в Python:

mat_contents = sio.loadmat('octave_a.mat')
mat_contents
    {'__header__': b'MATLAB 5.0 MAT-file, written by Octave 4.2.2, 2019-02-02 20:26:43 UTC',
     '__version__': '1.0',
     '__globals__': [],
     'a': array([[[ 1.,  4.,  7., 10.],
             [ 2.,  5.,  8., 11.],
             [ 3.,  6.,  9., 12.]]])}
oct_a = mat_contents['a']
oct_a
    array([[[ 1.,  4.,  7., 10.],
            [ 2.,  5.,  8., 11.],
            [ 3.,  6.,  9., 12.]]])
oct_a.shape
(1, 3, 4)

Как видим, файл прочитан верно. Теперь рассмотрим экспорт из SciPy в MATLAB:

import numpy as np
vect = np.arange (10)
vect.shape
(10,)
sio.savemat ('np_vector.mat', {'vect': vect})

Импортируем Python файл в Octave:

octave:8> load np_vector.mat
octave:9> vect
vect =

  0  1  2  3  4  5  6  7  8  9

octave:10> size(vect)
ans =
    1   10

Чтобы проверить содержимое файла MATLAB без чтения данных в памяти, используем команду whosmat:

sio.whosmat ('octave_a.mat')
[('a', (1, 3, 4), 'double')]

Функция whosmat возвращает список кортежей, по одному для каждого массива (или другого объекта), который содержится в файле MATLAB. Каждый кортеж содержит имя, содержимое файла и тип данных.


Структуры MATLAB

Структуры MATLAB похожи на словари Python dicts. Отличие заключается в том, что именем поля обязательно должна быть строка. Значением поля может быть любой объект.
Вспомним, что MATLAB — акроним MATrix LABoratory. Т.к. основное назначение MATLAB — работа с матрицами, поэтому все объекты в ней — это матрицы. Даже одно число представляется в виде матрицы размера (1, 1).

octave:11> my_struct = struct('field1', 1, 'field2', 2)
my_struct =
{
  field1 =  1
  field2 =  2
}

octave:12> save -6 octave_struct.mat my_struct

Загрузим MATLAB структуру в Python:

mat_contents = sio.loadmat('octave_struct.mat')
mat_contents
{'__header__': b'MATLAB 5.0 MAT-file, written by Octave 4.2.2, 2019-02-02 20:34:26 UTC',
 '__version__': '1.0',
 '__globals__': [],
 'my_struct': array([[(array([[1.]]), array([[2.]]))]],
       dtype=[('field1', 'O'), ('field2', 'O')])}
oct_struct = mat_contents['my_struct']
oct_struct.shape
(1, 1)
val = oct_struct[0,0]
val
(array([[1.]]), array([[2.]]))
val['field1']
array([[1.]])
val['field2']
array([[2.]])
val.dtype
dtype([('field1', 'O'), ('field2', 'O')])

В версиях SciPy от 0.12.0 структуры MATLAB возвращаются как структурированные массивы numpy. Названия полей массива numpy являются названием полей структуры MATLAB. Имена полей можно прочитать с помощью команды dtype, как в примере выше. Подробнее про типы данных structed arrays .

Таким образом, в MATLAB массив структур имеет размер как минимум 2D, что повторяется при чтении в SciPy. Чтобы сократить размерность до 1, используем параметр squeeze_me:

mat_contents = sio.loadmat ('octave_struct.mat', squeeze_me = True)
oct_struct = mat_contents ['my_struct']
oct_struct.shape
()

Иногда удобнее загружать структуры MATLAB как объекты python, а не numpy массивы. Чтобы это сделать, используйте параметр struct_as_record = False для загрузки.

mat_contents = sio.loadmat ('octave_struct.mat', struct_as_record = False)
oct_struct = mat_contents ['my_struct']
oct_struct[0,0].field1
array([[1.]])

Параметр struct_as_record = False прекрасно работает совместно с параметром squeeze_me:

mat_contents = sio.loadmat('octave_struct.mat', struct_as_record=False, squeeze_me=True)
oct_struct = mat_contents['my_struct']
oct_struct.shape # выдаст ошибку, т.к. у скаляра нет аттрибута shape
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

 in 
      1 mat_contents = sio.loadmat('octave_struct.mat', struct_as_record=False, squeeze_me=True)
      2 oct_struct = mat_contents['my_struct']
----> 3 oct_struct.shape # выдаст ошибку, т.к. это скаляр

AttributeError: 'mat_struct' object has no attribute 'shape'
type(oct_struct)
scipy.io.matlab.mio5_params.mat_struct
oct_struct.field1
1.0

Самый простой способ экспорта структур из python в MATLAB — с помощью словарей dicts:

a_dict = {'field1': 0.5, 'field2': 'a string'}
sio.savemat ('saved_struct.mat', {'a_dict': a_dict})

В MATLAB загружается как:

octave:21> load saved_struct
octave:22> a_dict
a_dict =

  scalar structure containing the fields:

    field1 =  0.50000
    field2 = a string

Также можно экспортировать структуры из python в MATLAB с помощью массивов numpy:

dt = [('f1', 'f8'), ('f2', 'S10')]
arr = np.zeros ((2,), dtype = dt)
arr
array([(0., b''), (0., b'')], dtype=[('f1', '
arr [0] ['f1'] = 0.5
arr [0] ['f2'] = 'python'
arr [1] ['f1'] = 99
arr [1] ['f2'] = 'not perl'
sio.savemat ('np_struct_arr.mat', {'arr': arr})


Массивы ячеек (cell) MATLAB

Массивы ячеек (cell) в MATLAB похожи на списки python. Элементы в массивах ячеек могут содержать любой тип объекта MATLAB. Также cell очень похожи на массивы объектов numpy. Рассмотрим пример экспорта cell из MATLAB в numpy.

octave:14> my_cells = {1, [2, 3]}
my_cells =
{
  [1,1] =  1
  [1,2] =

     2   3

}

octave:15> save -6 octave_cells.mat my_cells

Вернемся к Python:

mat_contents = sio.loadmat ('octave_cells.mat')
oct_cells = mat_contents ['my_cells']
print (oct_cells.dtype)
object
val = oct_cells [0,0]
val
array([[1.]])
print (val.dtype)
float64

Экспорт из numpy в массив cell MATLAB сделаем c помощью numpy-массива объектов:

obj_arr = np.zeros ((2,), dtype = np.object)
obj_arr [0] = 1
obj_arr [1] = 'a string'
obj_arr
array([1, 'a string'], dtype=object)
sio.savemat ('np_cells.mat', {'obj_arr': obj_arr})

Проверим правильность экспорта cell из numpy в Octave:

octave:16> load np_cells.mat
octave:17> obj_arr
obj_arr =
{
  [1,1] = 1
  [2,1] = a string
}

На этом, пожалуй, закончим. Надеюсь для кого-то эта статья послужит поводом для интеграции исследований в MATLAB со свободным программным обеспечением.
Источник: Документация scipy

© Habrahabr.ru