MATLAB是学术界最常用的编程工具,虽然MATLAB的功能已经很强大了,但是相对于开源的python来说,python丰富的开源工具和框架也是MATLAB所望尘莫及的。在编程实现任务所需的功能时,可能你对MATLAB相当熟悉,但是MATLAB里面却没有现成的代码供你使用,而恰好python却有开源的代码实现(比如当今正火的sklearn,比如pytorch等等等等),这时很头疼的情况就出现了----你对python不熟悉!!!
就问你难不难受?
别慌,你看----他来了,他带着混合编程走来了,他就是MATLAB与python混合编程!
下面,我们直奔主题————>怎么编程?
首先,你需要知道,MATLAB想要与python实现混合编程是有条件滴,条件就是MATLAB版本至少在2016版本以上(当然这只是As I all know,其实不太准确,因为我也是从网上看到的,反正2017版本是可以的)。
然后我们正式开始。
首先甩条官方链接:https://ww2.mathworks.cn/help/matlab/getting-started-with-python.html
作为一名程序猿,你得知道,新东西搞不懂?---->看文档
没错,我就是因为网上啥都找不到,最后实在无奈才去看的文档。(虽然官网文档能打开,但响应速度实在感人,所以下面我会直接将部分文档内容复制下来,省去你等待的时间,如果还是看不懂,你可以选择自己去官网看)
想要实现MATLAB和python的混合编程,那MATLAB和python你必须得有,环境变量配置好,这时前提,然后在MATLAB的命令行窗口输入:
pyversion
然后会显示当前的python信息。
如果没有显示,就手动指定。
使用下面命令,后面的是你电脑python.exe所在的绝对路径,如果你的电脑上有不止一个python环境(比如用anaconda创建了多个虚拟环境),也可以使用下面的命令来切换到不同的python环境
pyversion D:\Anaconda3\envs\OLSF\python.exe
不过执行之后什么输出都没有,如下:
有一点很必要知道的是,前面的命令(包括后面的命令,比如导包)执行完之后,MATLAB会将python的信息什么的加载到内存中去,我看网上说此时如果修改了代码什么的以后,重新执行,你会发现MATLAB调用的仍然是没修改之前的代码,修改没起到作用,此时你需要重启MATLAB,或者执行重新加载命令,看完文档之后我发现,还有一种方法可以不用重启MATLAB,那就是清除缓存!
下面先说怎么清除缓存,重新加载后面会说到。
#清楚缓存,包括工作区变量和已经加载的类和python模块缓存
clear classes
下面的内容来自官方文档:
------------------------------------------------------------------------我是一条分割线------------------------------------------------------------------------
有助于您快速开始在 MATLAB® 中使用 Python® 的示例和概念
要从 MATLAB 中调用 Python 库,请安装受支持的 Python 参考实现 (CPython) 版本。MATLAB 支持版本 2.7、3.5、3.6 和 3.7。您需要安装的版本取决于需要使用的库。有关信息,请参阅安装支持的 Python 实现。
要调用 Python 函数,请在模块名称和函数名称前键入 py.
。将 MATLAB 数据作为参数传递给 Python 函数;MATLAB 会将数据转换为最适合在 Python 语言中表达该数据的类型。例如,py.os.listdir('.')
列出当前文件夹的内容。
如需关于 Python 语言的帮助,请参阅 www.python.org/doc
。如需关于第三方模块或用户定义模块的帮助,请参考产品文档。
要从 Python 应用程序调用 MATLAB 函数,请参阅从 Python 调用 MATLAB。
pyversion |
更改 Python 解释器的默认版本 |
matlab.exception.PyException |
捕获 Python 异常的错误信息 |
系统和配置要求
如何验证您已安装受支持的 Python 版本。
创建一个 Python 对象。
MATLAB 变量和 Python 对象的行为有所不同。
Help for Python Functions
How to find help for Python functions.
了解 Python 和 MATLAB import 命令
如何使用 Python import
语句和 MATLAB import
命令。
调用用户定义的 Python 模块
创建本文档中的示例使用的一个 Python 模块。
重新加载经过修改的用户定义的 Python 模块
此示例说明如何重新加载经过修改的 Python 模块。
安装支持的 Python 实现
如何从 www.python.org
网站安装支持的 Python 版本。
------------------------------------------------------------------------我也是一条分割线------------------------------------------------------------------------
这部分直接看官方文档就行,说白了创建对象就等于python中 的实例化一个类,不过如果你想修改类的属性默认值的话,只能用创建的对象点儿(.)属性名=value的方式来修改。
------------------------------------------------------------------------我还是一条分割线------------------------------------------------------------------------
创建 Python® 对象 pyObj
的语法如下:
pyObj = py.modulename.ClassName(varargin)
其中 varargin
是由 ClassName
中的 __init__
方法指定的构造函数参数列表。
在 MATLAB® 中,Python 对象是引用类型(句柄对象),并且不遵从 MATLAB 的“赋值时复制”和“传值”规则。当您复制句柄对象时,只会复制句柄并且旧句柄和新句柄都引用相同的数据。当您复制 MATLAB 变量(值对象)时,变量数据也会复制。更改原始变量并不会影响新变量。
以下示例在 Python 标准库 textwrap
模块中创建 TextWrapper
类的一个对象。
读取构造函数签名 __init__
。
py.help('textwrap.TextWrapper.__init__')
Help on method __init__ in textwrap.TextWrapper:
textwrap.TextWrapper.__init__ = __init__(self, width=70, initial_indent='', subsequent_indent='', expand_tabs=True, replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, drop_whitespace=True, break_on_hyphens=True) unbound textwrap.TextWrapper method
创建一个默认 TextWrapper
对象。您不需要传递任何输入参数,因为每个参数都有由等号 (=
) 字符标识的默认值。
tw = py.textwrap.TextWrapper;
tw =
Python TextWrapper with properties:
width: 70
subsequent_indent: [1x1 py.str]
wordsep_simple_re_uni: [1x1 py._sre.SRE_Pattern]
fix_sentence_endings: 0
break_on_hyphens: 1
break_long_words: 1
wordsep_re_uni: [1x1 py._sre.SRE_Pattern]
initial_indent: [1x1 py.str]
expand_tabs: 1
replace_whitespace: 1
drop_whitespace: 1
要更改某个逻辑值,例如 break_long_words
属性,请键入:
tw.break_long_words = 0;
要更改某个数值,例如 width
属性,请先确定数值类型。
class(tw.width)
ans =
int64
默认情况下,当您将 MATLAB 数字传递给 Python 函数时,Python 将其作为浮点数读取。如果函数需要的是整数,Python 可能会引发错误或产生意外的结果。将 MATLAB 数字显式转换为整数。例如,键入:
tw.width = int64(3);
阅读 wrap
方法的帮助。
py.help('textwrap.TextWrapper.wrap')
Help on method wrap in textwrap.TextWrapper:
textwrap.TextWrapper.wrap = wrap(self, text) unbound textwrap.TextWrapper method
wrap(text : string) -> [string]
Reformat the single paragraph in 'text' so it fits in lines of
no more than 'self.width' columns, and return a list of wrapped
lines. Tabs in 'text' are expanded with string.expandtabs(),
and all other whitespace characters (including newline) are
converted to space.
从输入 T
创建换行的列表 w
。
T = 'MATLAB® is a high-level language and interactive environment for numerical computation, visualization, and programming.';
w = wrap(tw,T);
whos w
Name Size Bytes Class Attributes
w 1x1 112 py.list
将 py.list
转换为元胞数组并显示结果。
wrapped = cellfun(@char, cell(w), 'UniformOutput', false);
fprintf('%s\n', wrapped{:})
MATLAB®
is
a
high-
level
language
and
interactive
environment
for
numerical
computation,
visualization,
and
programming.
尽管 width
为 3,但将 break_long_words
属性设置为 false 会覆盖显示中的 width
值。
------------------------------------------------------------------------我又是一条分割线------------------------------------------------------------------------
MATLAB想要导入python的包很简单,python里导包是这么导:
import numpy as np
from sklearn.metrics import f1_score
而用MATLAB调用python包时只需要在前面加个py.就行,比如:
import py.numpy
import py.torch.*
如果要导入自己写的模块,就这么写:
# mymodule是你写的模块的文件名比如:mymodule.py
# myfunc是mymodlue.py里面的函数
py.mymodule.myfunc(参数1,参数2,...)
这里要注意的是:你自己写的模块必须放在python的搜索路径下,让python可以找到他,或者直接放在你MATLAB代码的目录下。当放在MATLAB代码目录下时,需要将当前文件夹添加到 Python 搜索路径,执行如下命令:
if count(py.sys.path,'') == 0
insert(py.sys.path,int32(0),'');
end
然后看官方文档:
------------------------------------------------------------------------我又是一条分割线------------------------------------------------------------------------
import
命令import
语句在 MATLAB® 中的功能与在 Python® 中的功能不同。Python 使用 import
语句加载代码并使代码可供访问。MATLAB 使用 import
函数来引用类或函数,而不必使用包名称。
切勿调用:
import py.*
如果执行了此调用,则 MATLAB 会调用 Python 函数,而不是同名的 MATLAB 函数。这可能会导致意外的行为。
如果您调用此命令,则必须调用 MATLAB 命令:
clear import
import pythonmodule
当您键入以下内容时,MATLAB 会自动加载 Python:
py.command
请勿在 MATLAB 中键入:
import pythonmodule
import
缩短类或函数名称借助 Python from...import
语句,您可以在不使用完全限定名称的情况下引用模块。假设您有以下 Python 代码,其中 y
是您要使用的类或函数名称。
from x import y
将此语句替换为以下 MATLAB 代码:
import x.y
例如,Python textwrap
模块会格式化文本块。
S = py.textwrap.wrap('This is a string');
由于 wrap
不是 MATLAB 函数,您可以使用 import
函数缩短调用语法。调用此命令后,您不需要键入包 (py
) 和模块 (textwrap
) 名称。
import py.textwrap.wrap
S = wrap('This is a string');
将当前文件夹更改为可写文件夹。在 MATLAB 编辑器中打开一个新文件。
复制下列用于定义 myfunc
函数的语句并将文件另存为 mymod.py
。
def myfunc():
"""Display message."""
return 'version 1'
调用 myfunc
。
py.mymod.myfunc
ans =
Python str with no properties.
version 1
修改该函数,用以下代码替换 return
语句:
return 'version 2'
保存文件。
clear classes
MATLAB 删除工作区中的所有变量、脚本和类。
mod = py.importlib.import_module('mymod');
py.reload(mod);
py.importlib.reload(mod);
调用更新后的 myfunc
函数。
py.mymod.myfunc
ans =
Python str with no properties.
version 2
此示例说明如何从以下 Python® 模块调用方法。本文档中的示例会使用此模块。
此示例说明如何在 MATLAB® 中创建该模块。如果您在 Python 编辑器中创建 mymod.py
,请确保该模块位于 Python 搜索路径上。此示例还可指导经验不丰富的 Python 用户如何获得调用该函数的帮助。
将当前文件夹更改为可写文件夹。
在 MATLAB 编辑器中打开一个新文件。
复制下列命令并将该文件另存为 mymod.py
。
# mymod.py
"""Python module demonstrates passing MATLAB types to Python functions"""
def search(words):
"""Return list of words containing 'son'"""
newlist = [w for w in words if 'son' in w]
return newlist
def theend(words):
"""Append 'The End' to list of words"""
words.append('The End')
return words
从 MATLAB 命令提示符下,将当前文件夹添加到 Python 搜索路径。
if count(py.sys.path,'') == 0
insert(py.sys.path,int32(0),'');
end
要了解如何调用函数,请阅读 mymod.py
源文件中 search
函数的函数签名。该函数接受一个输入参数 words
。
def search(words):
阅读 mymod.py
源文件中的函数帮助。根据 Python 网站文档,帮助位于“作为模块、函数、类或方法定义中的第一条语句出现的字符串文字”中。search
的帮助是:
"""Return list of words containing 'son'"""
该函数返回一个列表。
在 MATLAB 中创建一个输入参数,即名称列表。
N = py.list({'Jones','Johnson','James'})
N =
Python list with no properties.
['Jones', 'Johnson', 'James']
调用 search
函数。在模块名称和函数名称前键入 py.
。
names = py.mymod.search(N)
names =
Python list with no properties.
['Johnson']
该函数返回 py.list
值。
原始输入 N
未更改。
N
N =
Python list with no properties.
['Jones', 'Johnson', 'James']
------------------------------------------------------------------------我又是一条分割线------------------------------------------------------------------------
------------------------------------------------------------------------我又是一条分割线------------------------------------------------------------------------
下表显示用于创建 list
、tuple
和 dict
类型的命令。左侧的命令从 Python® 解释器运行。右侧的命令是 MATLAB® 命令。
Python |
MATLAB |
---|---|
['Robert', 'Mary', 'Joseph'] |
py.list({'Robert','Mary','Joseph'}) |
[[1,2],[3,4]] |
py.list({py.list([1,2]),py.list([3,4])}) |
Python |
MATLAB |
---|---|
('Robert', 19, 'Biology') |
py.tuple({'Robert',19,'Biology'}) |
Python |
MATLAB |
---|---|
{'Robert': 357, 'Joe': 391, 'Mary': 229} |
py.dict(pyargs(... |
------------------------------------------------------------------------我又是一条分割线------------------------------------------------------------------------
先看下官方文档:
------------------------------------------------------------------------我又是一条分割线------------------------------------------------------------------------
要调用 Python 方法或函数,请键入 py.
,然后键入模块名、函数名和参数。
在大多数情况下,MATLAB 自动将输入参数转换为 Python 类型。有一个例外情况是用关键字参数调用 Python 函数时。这种情况下需要使用 pyargs
函数将 MATLAB 数据传递给这些函数。
------------------------------------------------------------------------我又是一条分割线------------------------------------------------------------------------
这里有必要说一下,在python中一般使用的内置函数或者框架函数都会有多个可以省略的形参,比如这种形式:
def f1_score(y_true, y_pred, labels=None, pos_label=1, average='binary',
sample_weight=None):
像这种形式的函数在python中是极其常见的,而我们在调用的时候一般会省略其中一些参数,比如这么写:
result = f1_score(y_true, y_pred, average="macro")
这时中间的pos_label等参数会被省略,省略写的时候就需要将后面的参数明确 的标出来比如后面的average= ‘macro’,但是这种调用在MATLAB中使用时非法的,系统会报错。我在网上冲了很久很久的浪也没发现怎么解决这个问题,最后干脆自己想了个办法,自己写个python函数来实现相同的效果。以上面这个函数为例,我新建了一个module.py的文件,然后在里面重写了一下,上代码:
# module.py
from sklearn.metrics import f1_score
def F1_score(y_true, y_pre, average):
return f1_score(y_true, y_pre, average=average)
这样一来,我就可以通过py.module.F1_score()来调用sklearn的f1_score函数了。
在python中是存在异常的,但是当MATLAB调用python代码时,MATLAB并不会自动捕获python的异常,这就需要手动去捕获python代码运行产生的异常。
直接看官方文档:
------------------------------------------------------------------------我又是一条分割线------------------------------------------------------------------------
包: matlab.exception
捕获 Python 异常的错误信息
全页展开
处理 matlab.exception.PyException
对象中的信息,以解决从 MATLAB® 调用的 Python® 方法引发的 Python 错误。此类派生自 MException
。
您不要显式构造 matlab.exception.PyException
对象。在 Python 引发异常时,MATLAB 会自动构造一个 PyException
对象。PyException
对象将包装原始的 Python 异常。
全部折叠
ExceptionObject
- 对象Python sys.exc_info
函数的结果。要了解函数返回的内容信息,请键入:
help('py.sys.exc_info')
exc_info() -> (type, value, traceback)
Return information about the most recent exception caught by an except
clause in the current stack frame or in an older stack frame.
全部折叠
生成一个 Python 异常并显示信息。当 MATLAB 显示包含文本 Python Error
的消息时,请参阅您的 Python 文档以了解详细信息。
try
py.list('x','y',1)
catch e
e.message
if(isa(e,'matlab.exception.PyException'))
e.ExceptionObject
end
end
ans =
Python Error: TypeError: list() takes at most 1 argument (3 given)
ans =
Python tuple with no properties.
(, TypeError('list() takes at most 1 argument (3 given)',), None)
------------------------------------------------------------------------我又是一条分割线------------------------------------------------------------------------
文档写的已经很清楚了,MATLAB也是通过类似python的try-catch机制进行异常的捕获,只不过想要将异常信息抛出,需要添加一个if判断,来判断该异常是否是python的异常。
到这里MATLAB与python的混合编程就结束了,总结一下就是不懂得多看文档,文档说的比别人说的更准确更简洁。
还有就是,多动手,编程不是想想就行,好记性不如烂键盘!
欢迎讨论,欢迎转载!!!
转载请注明出处,谢谢!
欢迎访问我的个人博客:机器学习之路