Python與Matlab混合編程的實現案例
前言
因為項目需要,需要批處理很多Matlab的.m文件,從每個文件中提取結果合并到一個文件中。 很明顯,如果手工統(tǒng)計,幾百個文件會累死的。 因此立即想到了Python在批處理方面的優(yōu)勢,因此就在網上找了相關資料,實現了想要的功能,這里簡單記錄一下。
一、環(huán)境準備
首先電腦上要有Matlab,而且不能太老,比如Matlab 7.0可能就不行。 在電腦Matlab的安裝目錄下,依次找到MATLAB\R2015b\extern\engines\python,例如我電腦上的路徑是D:\Program Files\MATLAB\R2015b\extern\engines\python。 在這個目錄下有個setup.py。在命令行中安裝這個腳本,正常就可以成功了。
然后就可以在Python中import了,這個包的名字就叫”matlab”。
二、簡單示例
下面的代碼簡單演示了在Python中調用了Matlab的sqrt()函數并返回結果。說明了調用的主要步驟,同時加入了計時的代碼,記錄每個過程的耗時。
# coding=utf-8 import matlab.engine import time # 第一步,初始化Matlab的Runtime t1 = time.time() eng = matlab.engine.start_matlab() t2 = time.time() # 第二步,調用Matlab函數 res1 = eng.sqrt(16.0) t3 = time.time() res2 = eng.abs(-8.6) t4 = time.time() # 第三步,退出Runtime eng.quit() t5 = time.time() print type(res1), res1 print type(res2), res2 print "Initial time", t2 - t1 print "Running time1", t3 - t2 print "Running time2", t4 - t3 print "Quit time", t5 - t4
可以看到,程序輸出了和在Matlab中調用函數一樣的格式ans=…。同時可以發(fā)現,與C# & Matlab混合編程類似,程序運行最耗時的就是Runtime的初始化。 不同的運算耗時的差別與初始化耗時相比可以忽略不計。同時Runtime只要初始化一次,第二次調用函數時就不需要再初始化了。這些都和C#的接口是一樣的。
三、更復雜的示例
很明顯,我們好不容易用Python調Matlab肯定不是想簡單做個開方、取絕對值的運算的,要不然直接Python就可以實現,何必殺雞焉用牛刀。 比如調用我們自己編寫的.m文件中的函數等等。下
1.調用.m文件
首先新建一個m文件,并起名為triangle.m,用于計算三角形面積。如下。
并且將這個m文件放在py文件同一路徑下,然后在Python中可以這樣調用。
# coding=utf-8 import matlab.engine eng = matlab.engine.start_matlab() eng.triangle(nargout=0) eng.quit()
結果如下。
控制臺中像Matlab一樣輸出了結果。 但有幾點需要注意。首先nargout=0的含義是表示返回值為空。盡管控制臺打印出了結果,但并不會返回給Python。 如果沒有這個參數,程序會報錯。同時m文件必須和腳本文件在同一目錄下才能運行。而eng后面的內容就是m文件的名字。
2.調用自定義函數
把之前的m文件少做修改,編程Matlab函數,如下。
Python調用代碼如下:
# coding=utf-8 import matlab.engine eng = matlab.engine.start_matlab() ans = eng.triangle(2.3, 9.1) print ans eng.quit()
這里用變量ans接收了返回值,下一步就可以繼續(xù)用于其它操作了。 這里也有需要注意的地方。需要記住的是eng后面的依然是m文件的名字而不是函數的名字。 這里就涉及到Matlab中函數的命名規(guī)范問題了。一般情況下函數名與m文件名保持一致。 但如果不一致,在Python中經過測試也可以,但最好保持一致。
對于多返回值函數,可以在Matlab中組成一個矩陣,直接返回這個矩陣,然后在Python中再解析。 或者指定返回值個數。
不過需要注意的是,例如Matlab返回了一個a = [[1 2 3]]的矩陣,但直接獲取a[0]是錯的。因為Matlab返回的是一個二維矩陣,所以矩陣其實是1×3。 所以應該按照行列的方式讀取,寫成a[0][0]。
在Python中創(chuàng)建Matlab矩陣也很簡單。代碼如下:
# coding=utf-8 import matlab.engine A = matlab.int8([1, 2, 3, 4, 5]) print type(A), A.size, A
輸出結果如下:
3.繪圖測試
代碼如下。
#coding=utf-8 import matlab.engine def plot_test(eng): eng.workspace['data'] = \ eng.randi(matlab.double([1, 100]), matlab.double([30, 2])) eng.eval("plot(data(:,1),'ro-')") eng.hold('on', nargout=0) eng.eval("plot(data(:,2),'bx--')") eng = matlab.engine.start_matlab() plot_test(eng) # 需要讓程序在這暫停,類似于C++里的system('pause'),不然Figure一閃而過 # 按任意鍵退出 raw_input() eng.quit()
運行結果如下。
首先,對于一些簡單的命令,如max、min、power、sqrt等,我們直接可以eng.xxx()來完成。 但對于如繪圖等稍微復雜的命令,我們就可以使用eng.eval()函數來完成。 其中參數是我們拼接的需要執(zhí)行的字符串,如“plot(data(:,1),’ro-‘)”等。這樣程序在運行時就會調用Matlab執(zhí)行這一行語句。 所以其實同理,我們完全可以把之前的例子寫成eng.eval("sqrt(16.0)",nargout=0),控制臺會輸出結果4。 或者全部用eval()函數來寫Matlab命令,不與Python進行數據交互,只是調用Matlab。 在使用eval()時需要注意返回值的問題。如果沒有返回值,別忘了加上一句nargout=0。
以上只是很少一部分混合編程的相關知識,只是項目中用到的部分。其實還有很多東西可以學習,更多有關Python Matlab混合編程的說明可以參考官方文檔。 看到網上還有一種Matlab的調用方式,直接pip install mlab,然后直接import mlab就可以了,但是沒有嘗試,因此這里不多介紹了。
四、項目相關
最后簡單說一下項目相關的東西。項目中的需求是,有很多.m文件分布在許多文件夾中,需要獲取到某一路徑下的全部m文件。 然后獲取m文件中矩陣的相關統(tǒng)計值。最后再將各個m文件的統(tǒng)計結果匯總在一個m文件中。 因此使用了Python的os模塊遍歷文件夾,獲取所有m文件的路徑,然后根據指定的規(guī)則對m文件進行重寫,并輸出成新的m文件放在腳本目錄下。 最后通過Python調用Matlab運行m腳本,輸出結果到Python中,Python集中匯總輸出。
這里的關鍵點之一是由于各個m文件的文件名是不同的,因此eng.xxx()是沒有辦法在運行前寫死的。 必須根據讀取的文件名動態(tài)生成Python語句然后運行。這對于傳統(tǒng)編譯型語言可能很難實現,但對Python解釋型語言很容易實現。 在Python中有exec()函數可以實現這個需求,其中參數是需要執(zhí)行的代碼字符串。 項目部分代碼如下:
def joinCode(new_names): codes = [] for item in new_names: codes.append("res = eng." + item + "()") return codes def execMatlab(codes, exs, ex2s, eys, ey2s): eng = matlab.engine.start_matlab() for code in codes: exec code exs.append(res[0][0]) ex2s.append(res[0][1]) eys.append(res[0][2]) ey2s.append(res[0][3]) eng.quit()
項目中首先調用joinCode()函數根據new_names列表動態(tài)生成代碼字符串存放在codes中。 然后調用execMatlab()函數依次執(zhí)行每條語句。這里的res看似并沒有在代碼中定義,而且在IDE中確實也會報錯,說未定義。 但是其實它是在動態(tài)執(zhí)行的代碼中定義的,因此執(zhí)行時是不會報錯的。
順帶提一下,在Python中,執(zhí)行系統(tǒng)命令調用的是os.system()函數。參數就是需要執(zhí)行的代碼。 而且這個函數對于Windows和Linux都適用,是跨平臺的。類似于os.walk()等內置函數,都是抽象后的與系統(tǒng)無關的函數。 下面的代碼是用于執(zhí)行動態(tài)系統(tǒng)代碼的例子:
def exeCMD(cmds): for i in range(cmds.__len__()): print "\n---------------------------------------------------------------------" print "Executing:", cmds[i] os.system(cmds[i]) print "---------------------------------------------------------------------\n" print "**********", ((i + 1) * 1.0 / len(cmds)) * 100, "% finished.**********" print "**********100 % finished.**********"
最后,可以import platform包,可以獲取系統(tǒng)類型。如下函數是判斷當前是什么系統(tǒng),從而自動決定是使用哪種路徑分隔符。
def getOSType(): sysstr = platform.system() if (sysstr == "Windows"): separator = "\\" elif (sysstr == "Linux"): separator = "/" return separator
到此這篇關于Python與Matlab混合編程的實現案例的文章就介紹到這了,更多相關Python與Matlab混合編程內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Windows下Pycharm遠程連接虛擬機中Centos下的Python環(huán)境(圖文教程詳解)
由于最近學習tensorflow的需要,tensorflow是在Linux環(huán)境下,使用的是Python。為了方便程序的調試,嘗試在Windows下的Pycharm遠程連接到虛擬機中Centos下的Python環(huán)境,感興趣的朋友跟隨小編看看吧2020-03-03簡介Python的collections模塊中defaultdict類型的用法
這里我們來簡介Python的collections模塊中defaultdict類型的用法,與內置的字典類最大的不同在于初始化上,一起來看一下:2016-07-07