Solución:
Claro, solo usa scipy.io.savemat
Como ejemplo:
import numpy as np
import scipy.io
x = np.linspace(0, 2 * np.pi, 100)
y = np.cos(x)
scipy.io.savemat('test.mat', dict(x=x, y=y))
Del mismo modo, hay scipy.io.loadmat
.
Luego carga esto en matlab con load test
.
Alternativamente, como sugirió @JAB, podría simplemente guardar cosas en un archivo delimitado por tabulaciones ascii (p. Ej. numpy.savetxt
). Sin embargo, estará limitado a 2 dimensiones si sigue esta ruta. Por otro lado, ascii es el formato de intercambio universal. Prácticamente cualquier cosa manejará un archivo de texto delimitado.
Una solución simple, sin pasar datos por archivo o librerías externas.
Numpy tiene un método para transformar ndarrays en listas y los tipos de datos de matlab se pueden definir a partir de listas. Entonces, ¿cuándo se puede transformar como:
np_a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
mat_a = matlab.double(np_a.tolist())
De matlab a python requiere más atención. No hay una función incorporada para convertir el tipo directamente en listas. Pero podemos acceder a los datos sin procesar, que no tienen forma, sino que son simples. Entonces, usamos reshape
(formatear correctamente) y transpose
(debido a la forma diferente en que MATLAB y numpy almacenan datos). Es muy importante enfatizar eso: Pruébelo en su proyecto, principalmente si está utilizando matrices con más de 2 dimensiones. Funciona para MATLAB 2015a y 2 dim.
np_a = np.array(mat_a._data.tolist())
np_a = np_a.reshape(mat_a.size).transpose()
Aquí hay una solución que evita iterar en python, o usar el archivo IO, a expensas de depender de los componentes internos (feos) de matlab:
import matlab
# This is actually `matlab._internal`, but matlab/__init__.py
# mangles the path making it appear as `_internal`.
# Importing it under a different name would be a bad idea.
from _internal.mlarray_utils import _get_strides, _get_mlsize
def _wrapper__init__(self, arr):
assert arr.dtype == type(self)._numpy_type
self._python_type = type(arr.dtype.type().item())
self._is_complex = np.issubdtype(arr.dtype, np.complexfloating)
self._size = _get_mlsize(arr.shape)
self._strides = _get_strides(self._size)[:-1]
self._start = 0
if self._is_complex:
self._real = arr.real.ravel(order="F")
self._imag = arr.imag.ravel(order="F")
else:
self._data = arr.ravel(order="F")
_wrappers = {}
def _define_wrapper(matlab_type, numpy_type):
t = type(matlab_type.__name__, (matlab_type,), dict(
__init__=_wrapper__init__,
_numpy_type=numpy_type
))
# this tricks matlab into accepting our new type
t.__module__ = matlab_type.__module__
_wrappers[numpy_type] = t
_define_wrapper(matlab.double, np.double)
_define_wrapper(matlab.single, np.single)
_define_wrapper(matlab.uint8, np.uint8)
_define_wrapper(matlab.int8, np.int8)
_define_wrapper(matlab.uint16, np.uint16)
_define_wrapper(matlab.int16, np.int16)
_define_wrapper(matlab.uint32, np.uint32)
_define_wrapper(matlab.int32, np.int32)
_define_wrapper(matlab.uint64, np.uint64)
_define_wrapper(matlab.int64, np.int64)
_define_wrapper(matlab.logical, np.bool_)
def as_matlab(arr):
try:
cls = _wrappers[arr.dtype.type]
except KeyError:
raise TypeError("Unsupported data type")
return cls(arr)
Las observaciones necesarias para llegar hasta aquí fueron:
- Matlab parece solo mirar
type(x).__name__
ytype(x).__module__
para determinar si entiende el tipo - Parece que cualquier objeto indexable se puede colocar en el
._data
atributo
Desafortunadamente, matlab no está usando el _data
atributo de manera eficiente internamente, y está iterando sobre él un elemento a la vez en lugar de usar el Python memoryview
protocolo :(. Entonces, la ganancia de velocidad es marginal con este enfoque.