将Numpy数组"转换"为Matlab,反之亦然

34 python matlab numpy

我正在寻找一种方法将NumPy数组传递给Matlab.

我已经设法通过使用数组将数组存储到图像中scipy.misc.imsave然后使用它来加载它imread,但这当然会导致矩阵包含0到256之间的值而不是"实际"值.

将此矩阵的乘积除以256,并且原始NumPy数组中的最大值给出了正确的矩阵,但我觉得这有点单调乏味.

有更简单的方法吗?

Joe*_*ton 46

当然,只需使用 scipy.io.savemat

举个例子:

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))
Run Code Online (Sandbox Code Playgroud)

同样,有scipy.io.loadmat.

然后在matlab中加载它load test.

另外,正如@JAB建议的那样,您可以将内容保存到ascii制表符分隔文件(例如numpy.savetxt).但是,如果你走这条路,你将被限制在2个维度.另一方面,ascii是普遍的交换格式.几乎任何东西都会处理分隔的文本文件.

  • 谢谢你,正是我正在寻找的。 (2认同)

Jul*_*ENS 9

一个简单的解决方案,无需通过文件或外部库传递数据.

Numpy有一种方法可以将ndarrays转换为list,并且可以从列表中定义matlab数据类型.所以,什么时候可以改造:

np_a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
mat_a = matlab.double(np_a.tolist())
Run Code Online (Sandbox Code Playgroud)

从matlab到python需要更多的关注.没有内置函数可以将类型直接转换为列表.但我们可以访问原始数据,这些数据不是形状,而是简单的.所以,我们使用reshape(格式正确)和transpose(因为MATLAB和numpy存储数据的方式不同).压力非常重要:在项目中测试它,主要是在使用超过2维的矩阵时.它适用于MATLAB 2015a和2 dims.

np_a = np.array(mat_a._data.tolist())
np_a = np_a.reshape(mat_a.size).transpose()
Run Code Online (Sandbox Code Playgroud)

  • 请注意,“mat_a = matlab.double(np_a.tolist())”可能非常低效/缓慢。除了 np 数组之外,请遵循 Joe Kington 的答案。请参阅/sf/answers/3169888781/ (3认同)

Eri*_*ric 6

这是一个避免在 python 中迭代或使用文件 IO 的解决方案 - 以依赖(丑陋的)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)
Run Code Online (Sandbox Code Playgroud)

到达这里所需的观察是:

  • Matlab 似乎只看type(x).__name__type(x).__module__确定它是否理解类型
  • 似乎任何可索引的对象都可以放在._data属性中

不幸的是,matlab 并没有在_data内部有效地使用属性,而是一次迭代一个项目,而不是使用 pythonmemoryview协议:(。所以这种方法的速度增益是微不足道的。

  • 速度提升应该是相当显着的。我用这个方法得到了大约 15 倍的结果。/sf/answers/3170369821/ (2认同)