Python作為一個(gè)設(shè)計(jì)優(yōu)秀的程序語言,現(xiàn)在已廣泛應(yīng)用于各種領(lǐng)域,依靠其強(qiáng)大的第三方類庫,Python在各個(gè)領(lǐng)域都能發(fā)揮巨大的作用。
江城網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,江城網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為江城上千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站制作要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的江城做網(wǎng)站的公司定做!
下面我們就來看一下python中常用到的庫:
數(shù)值計(jì)算庫:
1. NumPy
支持多維數(shù)組與矩陣運(yùn)算,也針對(duì)數(shù)組運(yùn)算提供大量的數(shù)學(xué)函數(shù)庫。通常與SciPy和Matplotlib一起使用,支持比Python更多種類的數(shù)值類型,其中定義的最重要的對(duì)象是稱為ndarray的n維數(shù)組類型,用于描述相同類型的元素集合,可以使用基于0的索引訪問集合中元素。
2. SciPy
在NumPy庫的基礎(chǔ)上增加了眾多的數(shù)學(xué)、科學(xué)及工程計(jì)算中常用的庫函數(shù),如線性代數(shù)、常微分方程數(shù)值求解、信號(hào)處理、圖像處理、稀疏矩陣等,可進(jìn)行插值處理、信號(hào)濾波,以及使用C語言加速計(jì)算。
3. Pandas
基于NumPy的一種工具,為解決數(shù)據(jù)分析任務(wù)而生。納入大量庫和一些標(biāo)準(zhǔn)的數(shù)據(jù)模型,提供高效地操作大型數(shù)據(jù)集所需的工具及大量的能快速便捷處理數(shù)據(jù)的函數(shù)和方法,為時(shí)間序列分析提供很好的支持,提供多種數(shù)據(jù)結(jié)構(gòu),如Series、Time-Series、DataFrame和Panel。
數(shù)據(jù)可視化庫:
4. Matplotlib
第一個(gè)Python可視化庫,有許多別的程序庫都是建立在其基礎(chǔ)上或者直接調(diào)用該庫,可以很方便地得到數(shù)據(jù)的大致信息,功能非常強(qiáng)大,但也非常復(fù)雜。
5. Seaborn
利用了Matplotlib,用簡潔的代碼來制作好看的圖表。與Matplotlib最大的區(qū)別為默認(rèn)繪圖風(fēng)格和色彩搭配都具有現(xiàn)代美感。
6. ggplot
基于R的一個(gè)作圖庫ggplot2,同時(shí)利用了源于《圖像語法》(The Grammar of Graphics)中的概念,允許疊加不同的圖層來完成一幅圖,并不適用于制作非常個(gè)性化的圖像,為操作的簡潔度而犧牲了圖像的復(fù)雜度。
7. Bokeh
跟ggplot一樣,Bokeh也基于《圖形語法》的概念。與ggplot不同之處為它完全基于Python而不是從R處引用。長處在于能用于制作可交互、可直接用于網(wǎng)絡(luò)的圖表。圖表可以輸出為JSON對(duì)象、HTML文檔或者可交互的網(wǎng)絡(luò)應(yīng)用。
8. Plotly
可以通過Python notebook使用,與Bokeh一樣致力于交互圖表的制作,但提供在別的庫中幾乎沒有的幾種圖表類型,如等值線圖、樹形圖和三維圖表。
9. pygal
與Bokeh和Plotly一樣,提供可直接嵌入網(wǎng)絡(luò)瀏覽器的可交互圖像。與其他兩者的主要區(qū)別在于可將圖表輸出為SVG格式,所有的圖表都被封裝成方法,且默認(rèn)的風(fēng)格也很漂亮,用幾行代碼就可以很容易地制作出漂亮的圖表。
10. geoplotlib
用于制作地圖和地理相關(guān)數(shù)據(jù)的工具箱??捎脕碇谱鞫喾N地圖,比如等值區(qū)域圖、熱度圖、點(diǎn)密度圖。必須安裝Pyglet(一個(gè)面向?qū)ο缶幊探涌冢┓娇墒褂谩?/p>
11. missingno
用圖像的方式快速評(píng)估數(shù)據(jù)缺失的情況,可根據(jù)數(shù)據(jù)的完整度對(duì)數(shù)據(jù)進(jìn)行排序或過濾,或者根據(jù)熱度圖或樹狀圖對(duì)數(shù)據(jù)進(jìn)行修正。
web開發(fā)庫:
12. Django
一個(gè)高級(jí)的Python Web框架,支持快速開發(fā),提供從模板引擎到ORM所需的一切東西,使用該庫構(gòu)建App時(shí),必須遵循Django的方式。
13. Socket
一個(gè)套接字通訊底層庫,用于在服務(wù)器和客戶端間建立TCP或UDP連接,通過連接發(fā)送請(qǐng)求與響應(yīng)。
14. Flask
一個(gè)基于Werkzeug、Jinja 2的Python輕量級(jí)框架(microframework),默認(rèn)配備Jinja模板引擎,也包含其他模板引擎或ORM供選擇,適合用來編寫API服務(wù)(RESTful rervices)。
15. Twisted
一個(gè)使用Python實(shí)現(xiàn)的基于事件驅(qū)動(dòng)的網(wǎng)絡(luò)引擎框架,建立在deferred object之上,一個(gè)通過異步架構(gòu)實(shí)現(xiàn)的高性能的引擎,不適用于編寫常規(guī)的Web Apps,更適用于底層網(wǎng)絡(luò)。
數(shù)據(jù)庫管理:
16. MySQL-python
又稱MySQLdb,是Python連接MySQL最流行的一個(gè)驅(qū)動(dòng),很多框架也基于此庫進(jìn)行開發(fā)。只支持Python 2.x,且安裝時(shí)有許多前置條件。由于該庫基于C語言開發(fā),在Windows平臺(tái)上的安裝非常不友好,經(jīng)常出現(xiàn)失敗的情況,現(xiàn)在基本不推薦使用,取代品為衍生版本。
17. mysqlclient
完全兼容MySQLdb,同時(shí)支持Python 3.x,是Django ORM的依賴工具,可使用原生SQL來操作數(shù)據(jù)庫,安裝方式與MySQLdb一致。
18. PyMySQL
純Python實(shí)現(xiàn)的驅(qū)動(dòng),速度比MySQLdb慢,最大的特點(diǎn)為安裝方式簡潔,同時(shí)也兼容MySQL-python。
19. SQLAlchemy
一種既支持原生SQL,又支持ORM的工具。ORM是Python對(duì)象與數(shù)據(jù)庫關(guān)系表的一種映射關(guān)系,可有效提高寫代碼的速度,同時(shí)兼容多種數(shù)據(jù)庫系統(tǒng),如SQLite、MySQL、PostgreSQL,代價(jià)為性能上的一些損失。
自動(dòng)化運(yùn)維:
20. jumpsever跳板機(jī)
一種由Python編寫的開源跳板機(jī)(堡壘機(jī))系統(tǒng),實(shí)現(xiàn)了跳板機(jī)的基本功能,包含認(rèn)證、授權(quán)和審計(jì),集成了Ansible、批量命令等。
支持WebTerminal Bootstrap編寫,界面美觀,自動(dòng)收集硬件信息,支持錄像回放、命令搜索、實(shí)時(shí)監(jiān)控、批量上傳下載等功能,基于SSH協(xié)議進(jìn)行管理,客戶端無須安裝agent。主要用于解決可視化安全管理,因完全開源,容易再次開發(fā)。
21. Magedu分布式監(jiān)控系統(tǒng)
一種用Python開發(fā)的自動(dòng)化監(jiān)控系統(tǒng),可監(jiān)控常用系統(tǒng)服務(wù)、應(yīng)用、網(wǎng)絡(luò)設(shè)備,可在一臺(tái)主機(jī)上監(jiān)控多個(gè)不同服務(wù),不同服務(wù)的監(jiān)控間隔可以不同,同一個(gè)服務(wù)在不同主機(jī)上的監(jiān)控間隔、報(bào)警閾值可以不同,并提供數(shù)據(jù)可視化界面。
22. Magedu的CMDB
一種用Python開發(fā)的硬件管理系統(tǒng),包含采集硬件數(shù)據(jù)、API、頁面管理3部分功能,主要用于自動(dòng)化管理筆記本、路由器等常見設(shè)備的日常使用。由服務(wù)器的客戶端采集硬件數(shù)據(jù),將硬件信息發(fā)送至API,API負(fù)責(zé)將獲取的數(shù)據(jù)保存至數(shù)據(jù)庫中,后臺(tái)管理程序負(fù)責(zé)對(duì)服務(wù)器信息進(jìn)行配置和展示。
23. 任務(wù)調(diào)度系統(tǒng)
一種由Python開發(fā)的任務(wù)調(diào)度系統(tǒng),主要用于自動(dòng)化地將一個(gè)服務(wù)進(jìn)程分布到其他多個(gè)機(jī)器的多個(gè)進(jìn)程中,一個(gè)服務(wù)進(jìn)程可作為調(diào)度者依靠網(wǎng)絡(luò)通信完成這一工作。
24. Python運(yùn)維流程系統(tǒng)
一種使用Python語言編寫的調(diào)度和監(jiān)控工作流的平臺(tái),內(nèi)部用于創(chuàng)建、監(jiān)控和調(diào)整數(shù)據(jù)管道。允許工作流開發(fā)人員輕松創(chuàng)建、維護(hù)和周期性地調(diào)度運(yùn)行工作流,包括了如數(shù)據(jù)存儲(chǔ)、增長分析、Email發(fā)送、A/B測試等諸多跨多部門的用例。
GUI編程:
25. Tkinter
一個(gè)Python的標(biāo)準(zhǔn)GUI庫,可以快速地創(chuàng)建GUI應(yīng)用程序,可以在大多數(shù)的UNIX平臺(tái)下使用,同樣可以應(yīng)用在Windows和Macintosh系統(tǒng)中,Tkinter 8.0的后續(xù)版本可以實(shí)現(xiàn)本地窗口風(fēng)格,并良好地運(yùn)行在絕大多數(shù)平臺(tái)中。
26. wxPython
一款開源軟件跨平臺(tái)GUI庫wxWidgets的Python封裝和Python模塊,是Python語言的一套優(yōu)秀的GUI圖形庫,允許程序員很方便地創(chuàng)建完整的、功能健全的GUI用戶界面。
27. PyQt
一個(gè)創(chuàng)建GUI應(yīng)用程序的工具庫,是Python編程語言和Qt的成功融合,可以運(yùn)行在所有主要操作系統(tǒng)上,包括UNIX、Windows和Mac。PyQt采用雙許可證,開發(fā)人員可以選擇GPL和商業(yè)許可,從PyQt的版本4開始,GPL許可證可用于所有支持的平臺(tái)。
28. PySide
一個(gè)跨平臺(tái)的應(yīng)用程式框架Qt的Python綁定版本,提供與PyQt類似的功能,并相容API,但與PyQt不同處為其使用LGPL授權(quán)。
更多Python知識(shí)請(qǐng)關(guān)注Python自學(xué)網(wǎng)。
竅門一:關(guān)鍵代碼使用外部功能包
Python簡化了許多編程任務(wù),但是對(duì)于一些時(shí)間敏感的任務(wù),它的表現(xiàn)經(jīng)常不盡人意。使用C/C++或機(jī)器語言的外部功能包處理時(shí)間敏感任務(wù),可以有效提高應(yīng)用的運(yùn)行效率。這些功能包往往依附于特定的平臺(tái),因此你要根據(jù)自己所用的平臺(tái)選擇合適的功能包。簡而言之,這個(gè)竅門要你犧牲應(yīng)用的可移植性以換取只有通過對(duì)底層主機(jī)的直接編程才能獲得的運(yùn)行效率。以下是一些你可以選擇用來提升效率的功能包:
Cython
Pylnlne
PyPy
Pyrex
這些功能包的用處各有不同。比如說,使用C語言的數(shù)據(jù)類型,可以使涉及內(nèi)存操作的任務(wù)更高效或者更直觀。Pyrex就能幫助Python延展出這樣的功能。Pylnline能使你在Python應(yīng)用中直接使用C代碼。內(nèi)聯(lián)代碼是獨(dú)立編譯的,但是它把所有編譯文件都保存在某處,并能充分利用C語言提供的高效率。
竅門二:在排序時(shí)使用鍵
Python含有許多古老的排序規(guī)則,這些規(guī)則在你創(chuàng)建定制的排序方法時(shí)會(huì)占用很多時(shí)間,而這些排序方法運(yùn)行時(shí)也會(huì)拖延程序?qū)嶋H的運(yùn)行速度。最佳的排序方法其實(shí)是盡可能多地使用鍵和內(nèi)置的sort()方法。譬如,拿下面的代碼來說:
import operator
somelist = [(1, 5,?, (6, 2, 4), (9, 7, 5)]
somelist.sort(key=operator.itemgetter(0))
somelist
#Output = [(1, 5,?, (6, 2, 4), (9, 7, 5)]
somelist.sort(key=operator.itemgetter(1))
somelist
#Output = [(6, 2, 4), (1, 5,?, (9, 7, 5)]
somelist.sort(key=operator.itemgetter(2))
somelist
#Output = [(6, 2, 4), (9, 7, 5), (1, 5,?]
在每段例子里,list都是根據(jù)你選擇的用作關(guān)鍵參數(shù)的索引進(jìn)行排序的。這個(gè)方法不僅對(duì)數(shù)值類型有效,還同樣適用于字符串類型。
竅門三:針對(duì)循環(huán)的優(yōu)化
每一種編程語言都強(qiáng)調(diào)最優(yōu)化的循環(huán)方案。當(dāng)使用Python時(shí),你可以借助豐富的技巧讓循環(huán)程序跑得更快。然而,開發(fā)者們經(jīng)常遺忘的一個(gè)技巧是:盡量避免在循環(huán)中訪問變量的屬性。譬如,拿下面的代碼來說:
lowerlist = ['this', 'is', 'lowercase']
upper = str.upper
upperlist = []
append = upperlist.append
for word in lowerlist:
append(upper(word))
print(upperlist)
#Output = ['THIS', 'IS', 'LOWERCASE']
每次你調(diào)用str.upper, Python都會(huì)計(jì)算這個(gè)式子的值。然而,如果你把這個(gè)求值賦值給一個(gè)變量,那么求值的結(jié)果就能提前知道,Python程序就能運(yùn)行得更快。因此,關(guān)鍵就是盡可能減小Python在循環(huán)中的工作量。因?yàn)镻ython解釋執(zhí)行的特性,在上面的例子中會(huì)大大減慢它的速度。
(注意:優(yōu)化循環(huán)的方法還有很多,這只是其中之一。比如,很多程序員會(huì)認(rèn)為,列表推導(dǎo)式是提高循環(huán)速度的最佳方法。關(guān)鍵在于,優(yōu)化循環(huán)方案是提高應(yīng)用程序運(yùn)行速度的上佳選擇。)
竅門四:使用較新的Python版本
如果你在網(wǎng)上搜索Python,你會(huì)發(fā)現(xiàn)數(shù)不盡的信息都是關(guān)于如何升級(jí)Python版本。通常,每個(gè)版本的Python都會(huì)包含優(yōu)化內(nèi)容,使其運(yùn)行速度優(yōu)于之前的版本。但是,限制因素在于,你最喜歡的函數(shù)庫有沒有同步更新支持新的Python版本。與其爭論函數(shù)庫是否應(yīng)該更新,關(guān)鍵在于新的Python版本是否足夠高效來支持這一更新。
你要保證自己的代碼在新版本里還能運(yùn)行。你需要使用新的函數(shù)庫才能體驗(yàn)新的Python版本,然后你需要在做出關(guān)鍵性的改動(dòng)時(shí)檢查自己的應(yīng)用。只有當(dāng)你完成必要的修正之后,你才能體會(huì)新版本的不同。
然而,如果你只是確保自己的應(yīng)用在新版本中可以運(yùn)行,你很可能會(huì)錯(cuò)過新版本提供的新特性。一旦你決定更新,請(qǐng)分析你的應(yīng)用在新版本下的表現(xiàn),并檢查可能出問題的部分,然后優(yōu)先針對(duì)這些部分應(yīng)用新版本的特性。只有這樣,用戶才能在更新之初就覺察到應(yīng)用性能的改觀。
竅門五:嘗試多種編碼方法
每次創(chuàng)建應(yīng)用時(shí)都使用同一種編碼方法幾乎無一例外會(huì)導(dǎo)致應(yīng)用的運(yùn)行效率不盡人意??梢栽诔绦蚍治鰰r(shí)嘗試一些試驗(yàn)性的辦法。譬如說,在處理字典中的數(shù)據(jù)項(xiàng)時(shí),你既可以使用安全的方法,先確保數(shù)據(jù)項(xiàng)已經(jīng)存在再進(jìn)行更新,也可以直接對(duì)數(shù)據(jù)項(xiàng)進(jìn)行更新,把不存在的數(shù)據(jù)項(xiàng)作為特例分開處理。請(qǐng)看下面第一段代碼:
n = 16
myDict = {}
for i in range(0, n):
char = 'abcd'[i%4]
if char not in myDict:
myDict[char] = 0
myDict[char] += 1
print(myDict)
當(dāng)一開始myDict為空時(shí),這段代碼會(huì)跑得比較快。然而,通常情況下,myDict填滿了數(shù)據(jù),至少填有大部分?jǐn)?shù)據(jù),這時(shí)換另一種方法會(huì)更有效率。
n = 16
myDict = {}
for i in range(0, n):
char = 'abcd'[i%4]
try:
myDict[char] += 1
except KeyError:
myDict[char] = 1
print(myDict)
在兩種方法中輸出結(jié)果都是一樣的。區(qū)別在于輸出是如何獲得的。跳出常規(guī)的思維模式,創(chuàng)建新的編程技巧能使你的應(yīng)用更有效率。
竅門六:交叉編譯你的應(yīng)用
開發(fā)者有時(shí)會(huì)忘記計(jì)算機(jī)其實(shí)并不理解用來創(chuàng)建現(xiàn)代應(yīng)用程序的編程語言。計(jì)算機(jī)理解的是機(jī)器語言。為了運(yùn)行你的應(yīng)用,你借助一個(gè)應(yīng)用將你所編的人類可讀的代碼轉(zhuǎn)換成機(jī)器可讀的代碼。有時(shí),你用一種諸如Python這樣的語言編寫應(yīng)用,再以C++這樣的語言運(yùn)行你的應(yīng)用,這在運(yùn)行的角度來說,是可行的。關(guān)鍵在于,你想你的應(yīng)用完成什么事情,而你的主機(jī)系統(tǒng)能提供什么樣的資源。
Nuitka是一款有趣的交叉編譯器,能將你的Python代碼轉(zhuǎn)化成C++代碼。這樣,你就可以在native模式下執(zhí)行自己的應(yīng)用,而無需依賴于解釋器程序。你會(huì)發(fā)現(xiàn)自己的應(yīng)用運(yùn)行效率有了較大的提高,但是這會(huì)因平臺(tái)和任務(wù)的差異而有所不同。
(注意:Nuitka現(xiàn)在還處在測試階段,所以在實(shí)際應(yīng)用中請(qǐng)多加注意。實(shí)際上,當(dāng)下最好還是把它用于實(shí)驗(yàn)。此外,關(guān)于交叉編譯是否為提高運(yùn)行效率的最佳方法還存在討論的空間。開發(fā)者已經(jīng)使用交叉編譯多年,用來提高應(yīng)用的速度。記住,每一種解決辦法都有利有弊,在把它用于生產(chǎn)環(huán)境之前請(qǐng)仔細(xì)權(quán)衡。)
在使用交叉編譯器時(shí),記得確保它支持你所用的Python版本。Nuitka支持Python2.6, 2.7, 3.2和3.3。為了讓解決方案生效,你需要一個(gè)Python解釋器和一個(gè)C++編譯器。Nuitka支持許多C++編譯器,其中包括Microsoft Visual Studio,MinGW 和 Clang/LLVM。
交叉編譯可能造成一些嚴(yán)重問題。比如,在使用Nuitka時(shí),你會(huì)發(fā)現(xiàn)即便是一個(gè)小程序也會(huì)消耗巨大的驅(qū)動(dòng)空間。因?yàn)镹uitka借助一系列的動(dòng)態(tài)鏈接庫(DDLs)來執(zhí)行Python的功能。因此,如果你用的是一個(gè)資源很有限的系統(tǒng),這種方法或許不太可行。
最優(yōu)化
為什么要做最優(yōu)化呢?因?yàn)樵谏钪校藗兛偸窍M腋V祷蚱渌_(dá)到一個(gè)極值,比如做生意時(shí)希望成本最小,收入最大,所以在很多商業(yè)情境中,都會(huì)遇到求極值的情況。
函數(shù)求根
這里「函數(shù)的根」也稱「方程的根」,或「函數(shù)的零點(diǎn)」。
先把我們需要的包加載進(jìn)來。import numpy as npimport scipy as spimport scipy.optimize as optimport matplotlib.pyplot as plt%matplotlib inline
函數(shù)求根和最優(yōu)化的關(guān)系?什么時(shí)候函數(shù)是最小值或最大值?
兩個(gè)問題一起回答:最優(yōu)化就是求函數(shù)的最小值或最大值,同時(shí)也是極值,在求一個(gè)函數(shù)最小值或最大值時(shí),它所在的位置肯定是導(dǎo)數(shù)為 0 的位置,所以要求一個(gè)函數(shù)的極值,必然要先求導(dǎo),使其為 0,所以函數(shù)求根就是為了得到最大值最小值。
scipy.optimize 有什么方法可以求根?
可以用 scipy.optimize 中的 bisect 或 brentq 求根。f = lambda x: np.cos(x) - x # 定義一個(gè)匿名函數(shù)x = np.linspace(-5, 5, 1000) # 先生成 1000 個(gè) xy = f(x) # 對(duì)應(yīng)生成 1000 個(gè) f(x)plt.plot(x, y); # 看一下這個(gè)函數(shù)長什么樣子plt.axhline(0, color='k'); # 畫一根橫線,位置在 y=0
opt.bisect(f, -5, 5) # 求取函數(shù)的根0.7390851332155535plt.plot(x, y)plt.axhline(0, color='k')plt.scatter([_], [0], c='r', s=100); # 這里的 [_] 表示上一個(gè) Cell 中的結(jié)果,這里是 x 軸上的位置,0 是 y 上的位置
求根有兩種方法,除了上面介紹的 bisect,還有 brentq,后者比前者快很多。%timeit opt.bisect(f, -5, 5)%timeit opt.brentq(f, -5, 5)10000 loops, best of 3: 157 s per loopThe slowest run took 11.65 times longer than the fastest. This could mean that an intermediate result is being cached.10000 loops, best of 3: 35.9 s per loop
函數(shù)求最小化
求最小值就是一個(gè)最優(yōu)化問題。求最大值時(shí)只需對(duì)函數(shù)做一個(gè)轉(zhuǎn)換,比如加一個(gè)負(fù)號(hào),或者取倒數(shù),就可轉(zhuǎn)成求最小值問題。所以兩者是同一問題。
初始值對(duì)最優(yōu)化的影響是什么?
舉例來說,先定義個(gè)函數(shù)。f = lambda x: 1-np.sin(x)/xx = np.linspace(-20., 20., 1000)y = f(x)
當(dāng)初始值為 3 值,使用 minimize 函數(shù)找到最小值。minimize 函數(shù)是在新版的 scipy 里,取代了以前的很多最優(yōu)化函數(shù),是個(gè)通用的接口,背后是很多方法在支撐。x0 = 3xmin = opt.minimize(f, x0).x # x0 是起始點(diǎn),起始點(diǎn)最好離真正的最小值點(diǎn)不要太遠(yuǎn)plt.plot(x, y)plt.scatter(x0, f(x0), marker='o', s=300); # 起始點(diǎn)畫出來,用圓圈表示plt.scatter(xmin, f(xmin), marker='v', s=300); # 最小值點(diǎn)畫出來,用三角表示plt.xlim(-20, 20);
初始值為 3 時(shí),成功找到最小值。
現(xiàn)在來看看初始值為 10 時(shí),找到的最小值點(diǎn)。x0 = 10xmin = opt.minimize(f, x0).xplt.plot(x, y)plt.scatter(x0, f(x0), marker='o', s=300)plt.scatter(xmin, f(xmin), marker='v', s=300)plt.xlim(-20, 20);
由上圖可見,當(dāng)初始值為 10 時(shí),函數(shù)找到的是局部最小值點(diǎn),可見 minimize 的默認(rèn)算法對(duì)起始點(diǎn)的依賴性。
那么怎么才能不管初始值在哪個(gè)位置,都能找到全局最小值點(diǎn)呢?
如何找到全局最優(yōu)點(diǎn)?
可以使用 basinhopping 函數(shù)找到全局最優(yōu)點(diǎn),相關(guān)背后算法,可以看幫助文件,有提供論文的索引和出處。
我們?cè)O(shè)初始值為 10 看是否能找到全局最小值點(diǎn)。x0 = 10from scipy.optimize import basinhoppingxmin = basinhopping(f,x0,stepsize = 5).xplt.plot(x, y);plt.scatter(x0, f(x0), marker='o', s=300);plt.scatter(xmin, f(xmin), marker='v', s=300);plt.xlim(-20, 20);
當(dāng)起始點(diǎn)在比較遠(yuǎn)的位置,依然成功找到了全局最小值點(diǎn)。
如何求多元函數(shù)最小值?
以二元函數(shù)為例,使用 minimize 求對(duì)應(yīng)的最小值。def g(X): x,y = X return (x-1)**4 + 5 * (y-1)**2 - 2*x*yX_opt = opt.minimize(g, (8, 3)).x # (8,3) 是起始點(diǎn)print X_opt[ 1.88292611 1.37658521]fig, ax = plt.subplots(figsize=(6, 4)) # 定義畫布和圖形x_ = y_ = np.linspace(-1, 4, 100)X, Y = np.meshgrid(x_, y_)c = ax.contour(X, Y, g((X, Y)), 50) # 等高線圖ax.plot(X_opt[0], X_opt[1], 'r*', markersize=15) # 最小點(diǎn)的位置是個(gè)元組ax.set_xlabel(r"$x_1$", fontsize=18)ax.set_ylabel(r"$x_2$", fontsize=18)plt.colorbar(c, ax=ax) # colorbar 表示顏色越深,高度越高fig.tight_layout()
畫3D 圖。from mpl_toolkits.mplot3d import Axes3Dfrom matplotlib import cmfig = plt.figure()ax = fig.gca(projection='3d')x_ = y_ = np.linspace(-1, 4, 100)X, Y = np.meshgrid(x_, y_)surf = ax.plot_surface(X, Y, g((X,Y)), rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)cset = ax.contour(X, Y, g((X,Y)), zdir='z',offset=-5, cmap=cm.coolwarm)fig.colorbar(surf, shrink=0.5, aspect=5);
曲線擬合
曲線擬合和最優(yōu)化有什么關(guān)系?
曲線擬合的問題是,給定一組數(shù)據(jù),它可能是沿著一條線散布的,這時(shí)要找到一條最優(yōu)的曲線來擬合這些數(shù)據(jù),也就是要找到最好的線來代表這些點(diǎn),這里的最優(yōu)是指這些點(diǎn)和線之間的距離是最小的,這就是為什么要用最優(yōu)化問題來解決曲線擬合問題。
舉例說明,給一些點(diǎn),找到一條線,來擬合這些點(diǎn)。
先給定一些點(diǎn):N = 50 # 點(diǎn)的個(gè)數(shù)m_true = 2 # 斜率b_true = -1 # 截距dy = 2.0 # 誤差np.random.seed(0)xdata = 10 * np.random.random(N) # 50 個(gè) x,服從均勻分布ydata = np.random.normal(b_true + m_true * xdata, dy) # dy 是標(biāo)準(zhǔn)差plt.errorbar(xdata, ydata, dy, fmt='.k', ecolor='lightgray');
上面的點(diǎn)整體上呈現(xiàn)一個(gè)線性關(guān)系,要找到一條斜線來代表這些點(diǎn),這就是經(jīng)典的一元線性回歸。目標(biāo)就是找到最好的線,使點(diǎn)和線的距離最短。要優(yōu)化的函數(shù)是點(diǎn)和線之間的距離,使其最小。點(diǎn)是確定的,而線是可變的,線是由參數(shù)值,斜率和截距決定的,這里就是要通過優(yōu)化距離找到最優(yōu)的斜率和截距。
點(diǎn)和線的距離定義如下:def chi2(theta, x, y): return np.sum(((y - theta[0] - theta[1] * x)) ** 2)
上式就是誤差平方和。
誤差平方和是什么?有什么作用?
誤差平方和公式為:
誤差平方和大,表示真實(shí)的點(diǎn)和預(yù)測的線之間距離太遠(yuǎn),說明擬合得不好,最好的線,應(yīng)該是使誤差平方和最小,即最優(yōu)的擬合線,這里是條直線。
誤差平方和就是要最小化的目標(biāo)函數(shù)。
找到最優(yōu)的函數(shù),即斜率和截距。theta_guess = [0, 1] # 初始值theta_best = opt.minimize(chi2, theta_guess, args=(xdata, ydata)).xprint(theta_best)[-1.01442005 1.93854656]
上面兩個(gè)輸出即是預(yù)測的直線斜率和截距,我們是根據(jù)點(diǎn)來反推直線的斜率和截距,那么真實(shí)的斜率和截距是多少呢?-1 和 2,很接近了,差的一點(diǎn)是因?yàn)橛性胍舻囊?。xfit = np.linspace(0, 10)yfit = theta_best[0] + theta_best[1] * xfitplt.errorbar(xdata, ydata, dy, fmt='.k', ecolor='lightgray');plt.plot(xfit, yfit, '-k');
最小二乘(Least Square)是什么?
上面用的是 minimize 方法,這個(gè)問題的目標(biāo)函數(shù)是誤差平方和,這就又有一個(gè)特定的解法,即最小二乘。
最小二乘的思想就是要使得觀測點(diǎn)和估計(jì)點(diǎn)的距離的平方和達(dá)到最小,這里的“二乘”指的是用平方來度量觀測點(diǎn)與估計(jì)點(diǎn)的遠(yuǎn)近(在古漢語中“平方”稱為“二乘”),“最小”指的是參數(shù)的估計(jì)值要保證各個(gè)觀測點(diǎn)與估計(jì)點(diǎn)的距離的平方和達(dá)到最小。
關(guān)于最小二乘估計(jì)的計(jì)算,涉及更多的數(shù)學(xué)知識(shí),這里不想詳述,其一般的過程是用目標(biāo)函數(shù)對(duì)各參數(shù)求偏導(dǎo)數(shù),并令其等于 0,得到一個(gè)線性方程組。具體推導(dǎo)過程可參考斯坦福機(jī)器學(xué)習(xí)講義 第 7 頁。def deviations(theta, x, y): return (y - theta[0] - theta[1] * x)theta_best, ier = opt.leastsq(deviations, theta_guess, args=(xdata, ydata))print(theta_best)[-1.01442016 1.93854659]
最小二乘 leastsq 的結(jié)果跟 minimize 結(jié)果一樣。注意 leastsq 的第一個(gè)參數(shù)不再是誤差平方和 chi2,而是誤差本身 deviations,即沒有平方,也沒有和。yfit = theta_best[0] + theta_best[1] * xfitplt.errorbar(xdata, ydata, dy, fmt='.k', ecolor='lightgray');plt.plot(xfit, yfit, '-k');
非線性最小二乘
上面是給一些點(diǎn),擬合一條直線,擬合一條曲線也是一樣的。def f(x, beta0, beta1, beta2): # 首先定義一個(gè)非線性函數(shù),有 3 個(gè)參數(shù) return beta0 + beta1 * np.exp(-beta2 * x**2)beta = (0.25, 0.75, 0.5) # 先猜 3 個(gè) betaxdata = np.linspace(0, 5, 50)y = f(xdata, *beta)ydata = y + 0.05 * np.random.randn(len(xdata)) # 給 y 加噪音def g(beta): return ydata - f(xdata, *beta) # 真實(shí) y 和 預(yù)測值的差,求最優(yōu)曲線時(shí)要用到beta_start = (1, 1, 1)beta_opt, beta_cov = opt.leastsq(g, beta_start)print beta_opt # 求到的 3 個(gè)最優(yōu)的 beta 值[ 0.25525709 0.74270226 0.54966466]
拿估計(jì)的 beta_opt 值跟真實(shí)的 beta = (0.25, 0.75, 0.5) 值比較,差不多。fig, ax = plt.subplots()ax.scatter(xdata, ydata) # 畫點(diǎn)ax.plot(xdata, y, 'r', lw=2) # 真實(shí)值的線ax.plot(xdata, f(xdata, *beta_opt), 'b', lw=2) # 擬合的線ax.set_xlim(0, 5)ax.set_xlabel(r"$x$", fontsize=18)ax.set_ylabel(r"$f(x, \beta)$", fontsize=18)fig.tight_layout()
除了使用最小二乘,還可以使用曲線擬合的方法,得到的結(jié)果是一樣的。beta_opt, beta_cov = opt.curve_fit(f, xdata, ydata)print beta_opt[ 0.25525709 0.74270226 0.54966466]
有約束的最小化
有約束的最小化是指,要求函數(shù)最小化之外,還要滿足約束條件,舉例說明。
邊界約束def f(X): x, y = X return (x-1)**2 + (y-1)**2 # 這是一個(gè)碗狀的函數(shù)x_opt = opt.minimize(f, (0, 0), method='BFGS').x # 無約束最優(yōu)化
假設(shè)有約束條件,x 和 y 要在一定的范圍內(nèi),如 x 在 2 到 3 之間,y 在 0 和 2 之間。bnd_x1, bnd_x2 = (2, 3), (0, 2) # 對(duì)自變量的約束x_cons_opt = opt.minimize(f, np.array([0, 0]), method='L-BFGS-B', bounds=[bnd_x1, bnd_x2]).x # bounds 矩形約束fig, ax = plt.subplots(figsize=(6, 4))x_ = y_ = np.linspace(-1, 3, 100)X, Y = np.meshgrid(x_, y_)c = ax.contour(X, Y, f((X,Y)), 50)ax.plot(x_opt[0], x_opt[1], 'b*', markersize=15) # 沒有約束下的最小值,藍(lán)色五角星ax.plot(x_cons_opt[0], x_cons_opt[1], 'r*', markersize=15) # 有約束下的最小值,紅色星星bound_rect = plt.Rectangle((bnd_x1[0], bnd_x2[0]), bnd_x1[1] - bnd_x1[0], bnd_x2[1] - bnd_x2[0], facecolor="grey")ax.add_patch(bound_rect)ax.set_xlabel(r"$x_1$", fontsize=18)ax.set_ylabel(r"$x_2$", fontsize=18)plt.colorbar(c, ax=ax)fig.tight_layout()
不等式約束
介紹下相關(guān)理論,先來看下存在等式約束的極值問題求法,比如下面的優(yōu)化問題。
目標(biāo)函數(shù)是 f(w),下面是等式約束,通常解法是引入拉格朗日算子,這里使用 ββ 來表示算子,得到拉格朗日公式為
l 是等式約束的個(gè)數(shù)。
然后分別對(duì) w 和ββ 求偏導(dǎo),使得偏導(dǎo)數(shù)等于 0,然后解出 w 和βiβi,至于為什么引入拉格朗日算子可以求出極值,原因是 f(w) 的 dw 變化方向受其他不等式的約束,dw的變化方向與f(w)的梯度垂直時(shí)才能獲得極值,而且在極值處,f(w) 的梯度與其他等式梯度的線性組合平行,因此他們之間存在線性關(guān)系。(參考《最優(yōu)化與KKT條件》)
對(duì)于不等式約束的極值問題
常常利用拉格朗日對(duì)偶性將原始問題轉(zhuǎn)換為對(duì)偶問題,通過解對(duì)偶問題而得到原始問題的解。該方法應(yīng)用在許多統(tǒng)計(jì)學(xué)習(xí)方法中。有興趣的可以參閱相關(guān)資料,這里不再贅述。def f(X): return (X[0] - 1)**2 + (X[1] - 1)**2def g(X): return X[1] - 1.75 - (X[0] - 0.75)**4x_opt = opt.minimize(f, (0, 0), method='BFGS').xconstraints = [dict(type='ineq', fun=g)] # 約束采用字典定義,約束方式為不等式約束,邊界用 g 表示x_cons_opt = opt.minimize(f, (0, 0), method='SLSQP', constraints=constraints).xfig, ax = plt.subplots(figsize=(6, 4))x_ = y_ = np.linspace(-1, 3, 100)X, Y = np.meshgrid(x_, y_)c = ax.contour(X, Y, f((X, Y)), 50)ax.plot(x_opt[0], x_opt[1], 'b*', markersize=15) # 藍(lán)色星星,沒有約束下的最小值ax.plot(x_, 1.75 + (x_-0.75)**4, '', markersize=15)ax.fill_between(x_, 1.75 + (x_-0.75)**4, 3, color="grey")ax.plot(x_cons_opt[0], x_cons_opt[1], 'r*', markersize=15) # 在區(qū)域約束下的最小值ax.set_ylim(-1, 3)ax.set_xlabel(r"$x_0$", fontsize=18)ax.set_ylabel(r"$x_1$", fontsize=18)plt.colorbar(c, ax=ax)fig.tight_layout()
scipy.optimize.minimize 中包括了多種最優(yōu)化算法,每種算法使用范圍不同,詳細(xì)參考官方文檔。
第一、NumPy
NumPy是Numerical
Python的簡寫,是Python數(shù)值計(jì)算的基石。它提供多種數(shù)據(jù)結(jié)構(gòu)、算法以及大部分涉及Python數(shù)值計(jì)算所需的接口。NumPy還包括其他內(nèi)容:
①快速、高效的多維數(shù)組對(duì)象ndarray
②基于元素的數(shù)組計(jì)算或數(shù)組間數(shù)學(xué)操作函數(shù)
③用于讀寫硬盤中基于數(shù)組的數(shù)據(jù)集的工具
④線性代數(shù)操作、傅里葉變換以及隨機(jī)數(shù)生成
除了NumPy賦予Python的快速數(shù)組處理能力之外,NumPy的另一個(gè)主要用途是在算法和庫之間作為數(shù)據(jù)傳遞的數(shù)據(jù)容器。對(duì)于數(shù)值數(shù)據(jù),NumPy數(shù)組能夠比Python內(nèi)建數(shù)據(jù)結(jié)構(gòu)更為高效地存儲(chǔ)和操作數(shù)據(jù)。
第二、pandas
pandas提供了高級(jí)數(shù)據(jù)結(jié)構(gòu)和函數(shù),這些數(shù)據(jù)結(jié)構(gòu)和函數(shù)的設(shè)計(jì)使得利用結(jié)構(gòu)化、表格化數(shù)據(jù)的工作快速、簡單、有表現(xiàn)力。它出現(xiàn)于2010年,幫助Python成為強(qiáng)大、高效的數(shù)據(jù)分析環(huán)境。常用的pandas對(duì)象是DataFrame,它是用于實(shí)現(xiàn)表格化、面向列、使用行列標(biāo)簽的數(shù)據(jù)結(jié)構(gòu);以及Series,一種一維標(biāo)簽數(shù)組對(duì)象。
pandas將表格和關(guān)系型數(shù)據(jù)庫的靈活數(shù)據(jù)操作能力與Numpy的高性能數(shù)組計(jì)算的理念相結(jié)合。它提供復(fù)雜的索引函數(shù),使得數(shù)據(jù)的重組、切塊、切片、聚合、子集選擇更為簡單。由于數(shù)據(jù)操作、預(yù)處理、清洗在數(shù)據(jù)分析中是重要的技能,pandas將是重要主題。
第三、matplotlib
matplotlib是最流行的用于制圖及其他二維數(shù)據(jù)可視化的Python庫,它由John D.
Hunter創(chuàng)建,目前由一個(gè)大型開發(fā)者團(tuán)隊(duì)維護(hù)。matplotlib被設(shè)計(jì)為適合出版的制圖工具。
對(duì)于Python編程者來說也有其他可視化庫,但matplotlib依然使用最為廣泛,并且與生態(tài)系統(tǒng)的其他庫良好整合。
第四、IPython
IPython項(xiàng)目開始于2001年,由Fernando
Pérez發(fā)起,旨在開發(fā)一個(gè)更具交互性的Python解釋器。在過去的16年中,它成為Python數(shù)據(jù)技術(shù)棧中最重要的工具之一。
盡管它本身并不提供任何計(jì)算或數(shù)據(jù)分析工具,它的設(shè)計(jì)側(cè)重于在交互計(jì)算和軟件開發(fā)兩方面將生產(chǎn)力最大化。它使用了一種執(zhí)行-探索工作流來替代其他語言中典型的編輯-編譯-運(yùn)行工作流。它還提供了針對(duì)操作系統(tǒng)命令行和文件系統(tǒng)的易用接口。由于數(shù)據(jù)分析編碼工作包含大量的探索、試驗(yàn)、試錯(cuò)和遍歷,IPython可以使你更快速地完成工作。
第五、SciPy
SciPy是科學(xué)計(jì)算領(lǐng)域針對(duì)不同標(biāo)準(zhǔn)問題域的包集合。以下是SciPy中包含的一些包:
①scipy.integrate數(shù)值積分例程和微分方程求解器
②scipy.linalg線性代數(shù)例程和基于numpy.linalg的矩陣分解
③scipy.optimize函數(shù)優(yōu)化器和求根算法
④scipy.signal信號(hào)處理工具
⑤scipy.sparse稀疏矩陣與稀疏線性系統(tǒng)求解器
SciPy與Numpy一起為很多傳統(tǒng)科學(xué)計(jì)算應(yīng)用提供了一個(gè)合理、完整、成熟的計(jì)算基礎(chǔ)。
第六、scikit-learn
scikit-learn項(xiàng)目誕生于2010年,目前已成為Python編程者首選的機(jī)器學(xué)習(xí)工具包。僅僅七年,scikit-learn就擁有了全世界1500位代碼貢獻(xiàn)者。其中包含以下子模塊:
①分類:SVM、最近鄰、隨機(jī)森林、邏輯回歸等
②回歸:Lasso、嶺回歸等
③聚類:K-means、譜聚類等
④降維:PCA、特征選擇、矩陣分解等
⑤模型選擇:網(wǎng)格搜索、交叉驗(yàn)證、指標(biāo)矩陣
⑥預(yù)處理:特征提取、正態(tài)化
scikit-learn與pandas、statsmodels、IPython一起使Python成為高效的數(shù)據(jù)科學(xué)編程語言。
1. Pandas.apply() – 特征工程瑰寶
Pandas 庫已經(jīng)非常優(yōu)化了,但是大部分人都沒有發(fā)揮它的最大作用。想想它一般會(huì)用于數(shù)據(jù)科學(xué)項(xiàng)目中的哪些地方。一般首先能想到的就是特征工程,即用已有特征創(chuàng)造新特征。其中最高效的方法之一就是Pandas.apply(),即Pandas中的apply函數(shù)。
在Pandas.apply()中,可以傳遞用戶定義功能并將其應(yīng)用到Pandas Series的所有數(shù)據(jù)點(diǎn)中。這個(gè)函數(shù)是Pandas庫最好的擴(kuò)展功能之一,它能根據(jù)所需條件分隔數(shù)據(jù)。之后便能將其有效應(yīng)用到數(shù)據(jù)處理任務(wù)中。
2. Pandas.DataFrame.loc – Python數(shù)據(jù)操作絕妙技巧
所有和數(shù)據(jù)處理打交道的數(shù)據(jù)科學(xué)家(差不多所有人了!)都應(yīng)該學(xué)會(huì)這個(gè)方法。
很多時(shí)候,數(shù)據(jù)科學(xué)家需要根據(jù)一些條件更新數(shù)據(jù)集中某列的某些值。Pandas.DataFrame.loc就是此類問題最優(yōu)的解決方法。
3. Python函數(shù)向量化
另一種解決緩慢循環(huán)的方法就是將函數(shù)向量化。這意味著新建函數(shù)會(huì)應(yīng)用于輸入列表,并返回結(jié)果數(shù)組。在Python中使用向量化能至少迭代兩次,從而加速計(jì)算。
事實(shí)上,這樣不僅能加速代碼運(yùn)算,還能讓代碼更加簡潔清晰。
4. Python多重處理
多重處理能使系統(tǒng)同時(shí)支持一個(gè)以上的處理器。
此處將數(shù)據(jù)處理分成多個(gè)任務(wù),讓它們各自獨(dú)立運(yùn)行。處理龐大的數(shù)據(jù)集時(shí),即使是apply函數(shù)也顯得有些遲緩。
關(guān)于優(yōu)化Python編程的4個(gè)妙招,青藤小編就和您分享到這里了。如果您對(duì)python編程有濃厚的興趣,希望這篇文章可以為您提供幫助。如果您還想了解更多關(guān)于python編程的技巧及素材等內(nèi)容,可以點(diǎn)擊本站的其他文章進(jìn)行學(xué)習(xí)。