首页>>python >> Python调用matlab函数:数据传递效率低下原因

Python调用matlab函数:数据传递效率低下原因

时间:2023-10-27 19:06:49 网络整理 点击:198

Python调用matlab函数

本文章主要描述两个Python调用matlab函数的方法,代码都是作者学习过程自己编写的,因为没有什么难度,所以直接贴出来,让大家能够快速上手。

MatlabEngine实现原理

import matlab.engine
import sys
eng = matlab.engine.start_matlab()
a = matlab.double([1,4,9,16,25])
b = eng.sqrt(a)
b=np.array(b)

上面几行代码示例了python调用matlab的方式,需要注意的是matlabengine实现的交互效率非常低,主要原因在于数据传递。

import numpy as np
from scipy.sparse import csc_matrix
from scipy.sparse import csr_matrix
from scipy.linalg import solve
from scipy import io
import scipy.io as scio
import scipy
import time
import random
import matlab.engine
import sys
eng = matlab.engine.start_matlab()
n=300
ns=30
lie=np.zeros((0,))
hang=np.zeros((n*n,ns))
for i in range(0,n*n):
 lie_temp=np.array(random.sample(range(0,n*n), ns))
 
 lie_temp=np.array(lie_temp)
 lie = np.hstack((lie,lie_temp))  # 沿着矩阵列拼接
 hang[i] = np.array([i] * ns)
hang = hang.reshape(hang.shape[0]*hang.shape[1], )
hang=hang+1
lie=lie+1
value= np.random.rand(n*n*ns,)
f= np.random.rand(n*n,1)
value = value.tolist()
hang = hang.tolist()
lie = lie.tolist()
f = f.tolist()
matlab_i = matlab.double(hang)
matlab_j = matlab.double(lie)
matlab_v = matlab.double(value)
matlab_f = matlab.double(f)
time_start = time.time() #开始计时
x=eng.sparse_matlab(matlab_i,matlab_j,matlab_v,matlab_f)
x=np.array(x)
time_end = time.time()#结束计时
time_c= time_end - time_start   #运行所花时间
print( 'cpu matlab csc solve',time_c, 's\n')

上面代码示例的在python中创建一个稀疏矩阵的三元组输入参数,然后传递给matlab,通过matlab来求解稀疏线性方程组,然而数据传递的过程非常耗时,而且运算效率远低于纯matlab的计算效率

matlabengine实现的python调用matlab会在cpu线程中创建一个matlab进程,因此可以认为matlabengine是通过python开启了matlab,让python和matlab同时工作。

经过上面两个代码的分析,matlabengine的效率低下原因可以总结为两个:1、数据传递效率低2、matlab和python同时运行,cpu资源占用过大

python调用matlab生成的dll文件

高版本的matlab支持将函数文件输出为dll文件,dll又根据和不同编程语言的交互分为多个类型。

如上图所示library compiler中有多个打包的选择,最后一个即为python。

选择好需要打包的matlab函数文件,点击package,将会生成三个文件夹。这里我们只关注for_redistribution_files_only这个文件夹,cmd进入该文件夹路径,输入python.exe .\setup.py install安装库文件。

此刻就完成了库文件安装。

如上图,打包了一个名为New_sin的函数脚本,cmd安装完成后,直接在python内import New_sin即可。有些小白可能会遇到库导入不成功的问题,请自行百度查找,一般都采用pycharm编程,设置好路径就可以调用到。

到这一步已经完成了dll文件的import,现在需要进行函数调用和数据传递。

import numpy as np
import matlab
import New_sin
matlab_funtion = New_sin.initialize()
a=np.array([1,2,3]).tolist()
a=matlab.double(a)
b = matlab_funtion.New_sin(a,a,a)
matlab_funtion.terminate()

如上代码示例了dll文件的调用和数据传递,然而这种方式效率极低,本质上和matlabengine的数据传递实现相同,不同的是dll方法实现的调用线程中不再存在matlab,cpu占用相对会小一些。

为了解决数据传递问题,题主推荐采用mat格式进行读写,python将numpy数据存储为mat数据,matlab直接读取mat数据进行运算,注意matlab读取mat数据必须指定详细路径,不申明路径情况下mat文件很可能读取错误或者异步。

import numpy as np
import sparse_solver
import time
from scipy import io
import scipy.io as scio
import time
spsolver = sparse_solver.initialize()
time_start = time.time() #开始计时
mat = io.loadmat('value_mat.mat')
value = mat.get('value_combine')
mat = io.loadmat('hang_mat.mat')
hang = mat.get('hang_combine')
mat = io.loadmat('lie_mat.mat')
lie = mat.get('lie_combine')
mat = io.loadmat('f_mat.mat')
f = mat.get('f')
mat = io.loadmat('ff_mat.mat')
ff = mat.get('ff')
time_end = time.time()#结束计时
time_c= time_end - time_start   #运行所花时间
print( 'read took ',time_c, 's\n')
print("这里读取更新mat是没有问题的")
print(hang.shape)
print("new hang shape is ",hang.shape)
time_start = time.time() #开始计时
py_hang_mat = 'hang_py.mat'
scio.savemat(py_hang_mat, {'hang_py':hang})
py_lie_mat = 'lie_py.mat'
scio.savemat(py_lie_mat, {'lie_py':lie})
py_value_mat = 'value_py.mat'
scio.savemat(py_value_mat, {'value_py':value})
py_f_mat = 'f_py.mat'
scio.savemat(py_f_mat, {'f_py':f})
time_end = time.time()#结束计时
time_c= time_end - time_start   #运行所花时间
print( 'write took ',time_c, 's\n')
mat = io.loadmat('hang_py.mat')
hang=mat.get('hang_py')
print("测试python保存的mat文件",hang.shape)
time_start = time.time() #开始计时
spsolver.sparse_solver(nargout=0)
time_end = time.time()#结束计时
time_c= time_end - time_start   #运行所花时间
print( 'matlab sparse solve',time_c, 's\n')
print("这里读取更新mat有问题的")
mat = io.loadmat('x_mat.mat')
x=mat.get('x_mat')
print(x.shape)
print(ff.shape)
error=(np.max(abs(x-ff)))
print(error)

上面代码示例了稀疏矩阵的三元组参数的存取过程,mat读取和创建采用scipy 库实现。采用mat实现数据交互意味这matlab的函数中不需要再设定输入参数

function sparse_solver()
clear;
load C:\Users\86183\Desktop\pybind11_test\pycharm_test\hang_py.mat hang_py;
load C:\Users\86183\Desktop\pybind11_test\pycharm_test\lie_py.mat lie_py;
load C:\Users\86183\Desktop\pybind11_test\pycharm_test\value_py.mat value_py;
load C:\Users\86183\Desktop\pybind11_test\pycharm_test\f_py.mat f_py;
i_m=max(hang_py);
j_m=max(lie_py);
hang_py=double(hang_py);
lie_py=double(lie_py);
if(max(lie_py)~=max(size(f_py)))
 error('input parameter error');
end
sparse_c=sparse(hang_py,lie_py,value_py,i_m,j_m);
x_mat=sparse_c\f_py;
save x_mat x_mat;
clear;
end

如上即为matlab的函数代码,要注意matlab加载mat文件时候要指定详细的路径,或则会出错。

题主测试发现,通过mat交互数据,dll处理运算的方法效率和matlab本身的运算效率相差无几,然而通过matlab库进行数据转换的运算效率却比matlab本身低非常多。因此题主推荐通过dll调用matlab函数,mat实现数据交互,其他的交互方法都存在效率问题,在这里不做推荐。

本文示例的代码是python读取matlab生成的稀疏矩阵三元组参数,然后python将mat数据存为numpy,再将numpy存为mat数据,matlab的函数直接读取mat文件,完成稀疏线性方程组求解,并将结果存储为mat文件。有好奇的小伙伴会问题主为什么要用matlab的稀疏矩阵求解函数,因为python的太慢了,说白了这就是收费软件和开源编程语言的差距,不过在这里不多纠结,反正这两个编程语言在C/C++面前都是工具罢了。

这里稍微提几句,matlab的运算效率虽然不及C/C++,但是在矩阵运算上比python的numpy+mkl还是要快很多,即便是大家诟病的for循环,matlab还是优于python,虽然python有numba,但是numba限制过多,matlab本身的编程难度比python还低,但是国内很多matlab都是破解版的,所以有利有弊吧。工科学生不应该去纠结学python还是matlab,matlab和python都只能称为工具,如果想做算法底层,仅仅掌握这两个语言完全不够。

补充:

关于输出参数

由于采用mat交互矩阵数据,因此matlab的函数不输出参数,所以nargout=0

关于import matlab报错

先确认自己安装了matlab库(pip install matlab),如果还是报错则进入

D:\matlab2020b\extern\engines\python

cmd切到这个文件夹,然后输入python.exe .\setup.py install

《Python调用matlab函数:数据传递效率低下原因》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
下载文档

文档为doc格式