改进numpy数组到matlabdoub的转换性能

2024-06-06 14:32:34 发布

您现在位置:Python中文网/ 问答频道 /正文

从Python调用MATLAB必然会导致一些性能降低,我可以通过重写Python中的(大量)代码来避免这些性能降低。然而,这对我来说并不是一个现实的选择,但是让我恼火的是效率的巨大损失在于从numpy数组到matlabdouble的简单转换。在

我说的是从data1到data1m的以下转换,其中

data1 = np.random.uniform(low = 0.0, high = 30000.0, size = (1000000,))
data1m = matlab.double(list(data1))

这里matlab.double来自Mathworks自己的MATLAB包/引擎。第二行代码在我的系统上花费了20秒,这对于一个除了让数字在MATLAB中“可食用”之外什么都不做的转换来说似乎太多了。在

所以基本上我在寻找一个与给定的here相反的技巧,它可以将MATLAB输出转换回Python。在


Tags: 代码numpynprandom数组性能效率double
3条回答

我的情况有点不同(python脚本从matlab调用),但是对于我来说,将ndarray转换为数组.array大大加快了进程。基本上它与Alexandre Chabot解决方案非常相似,但不需要更改任何文件:

#untested i.e. only deducted from my "matlab calls python" situation
import numpy
import array

data1 = numpy.random.uniform(low = 0.0, high = 30000.0, size = (1000000,))
ar = array.array('d',data1.flatten('F').tolist())
p = matlab.double(ar)
C = matlab.reshape(p,data1.shape) #this part I am definitely not sure about if it will work like that

至少如果从Matlab中完成数组.array“双”和“快”。用matlab2016b+python 3.5.4 64位进行测试。在

在等待更好的建议的同时,我将发布迄今为止我想出的最好的技巧。归根结底就是用`scipy.io.savemat,然后在MATLAB中加载此文件。在

这不是最漂亮的黑客,它需要一些小心,以确保依赖同一脚本的不同进程不会最终写入和加载彼此的.mat文件,但性能提高对我来说是值得的。在

作为一个测试用例,我编写了两个简单的、几乎完全相同的MATLAB函数,它们需要2个numpy数组(我测试的长度为1000000)和一个int作为输入。在

function d = test(x, y, fs_signal)
d = sum((x + y))./double(fs_signal);

function d = test2(path)
load(path)
d = sum((x + y))./double(fs_signal);

函数test需要转换,而test2需要保存。在

测试test:转换两个numpy数组需要cirka40s。准备和运行测试的总时间为170 s

测试test2:保存数组和int在我的系统上需要cirka 0.35秒。令人惊讶的是,在MATLAB中加载.mat文件是非常有效的(或者更令人惊讶的是,它在处理它的双精度函数时非常不熟练)。。。准备和运行test2的总时间为0.38 s

性能提高了近450倍。。。在

高效传递numpy数组

查看文件夹PYTHONPATH\Lib\site-packages\matlab\_internal中的文件mlarray_sequence.py。在这里您将找到MATLAB数组对象的构造。性能问题来自于在generic_flattening函数中使用循环复制数据。在

为了避免这种行为,我们将对文件进行一点编辑。此修复程序应该适用于复杂和非复杂的数据类型。在

  1. 备份原始文件以防出错。在
  2. import numpy as np添加到文件开头的其他导入中
  3. 在第38行中,您可以找到:

    init_dims = _get_size(initializer)  # replace this with 
         try:
             init_dims=initializer.shape
         except:
             init_dims = _get_size(initializer)
    
  4. 在第48行中,您可以找到:

    if is_complex:
        complex_array = flat(self, initializer,
                             init_dims, typecode)
        self._real = complex_array['real']
        self._imag = complex_array['imag']
    else:
        self._data = flat(self, initializer, init_dims, typecode)
    
    #Replace this with:
    
    if is_complex:
        try:
            self._real = array.array(typecode,np.ravel(initializer, order='F').real)
            self._imag = array.array(typecode,np.ravel(initializer, order='F').imag)
        except:
            complex_array = flat(self, initializer,init_dims, typecode)
            self._real = complex_array['real']
            self._imag = complex_array['imag']
    else:
        try:
            self._data = array.array(typecode,np.ravel(initializer, order='F'))
        except:
            self._data = flat(self, initializer, init_dims, typecode)
    

现在可以将numpy数组直接传递给MATLAB数组创建方法。在

data1 = np.random.uniform(low = 0.0, high = 30000.0, size = (1000000,))
#faster
data1m = matlab.double(data1)
#or slower method
data1m = matlab.double(data1.tolist())

data2 = np.random.uniform(low = 0.0, high = 30000.0, size = (1000000,)).astype(np.complex128)
#faster
data1m = matlab.double(data2,is_complex=True)
#or slower method
data1m = matlab.double(data2.tolist(),is_complex=True)

MATLAB数组创建的性能提高了15倍,而且接口现在更易于使用。在

相关问题 更多 >