博客專欄

EEPW首頁 > 博客 > 干貨!機(jī)器學(xué)習(xí)中,如何優(yōu)化數(shù)據(jù)性能

干貨!機(jī)器學(xué)習(xí)中,如何優(yōu)化數(shù)據(jù)性能

發(fā)布人:AI科技大本營 時(shí)間:2021-06-14 來源:工程師 發(fā)布文章

得益于覆蓋各種需求的第三方庫,Python在今天已經(jīng)成為了研究機(jī)器學(xué)習(xí)的主流工具。不過由于其解釋型語言的特性,在運(yùn)行速度上往往和傳統(tǒng)編譯型語言有較大差距。特別是當(dāng)訓(xùn)練數(shù)據(jù)集非常龐大時(shí),很多時(shí)候處理數(shù)據(jù)本身就會(huì)占用大量的時(shí)間。

Python中自身提供了非常強(qiáng)大的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu):numpy庫下的ndarry和pandas庫下的DataFrame。前者提供了很多l(xiāng)ist沒有實(shí)現(xiàn)的便利功能,而后者是最方便的column-row型數(shù)據(jù)的存儲(chǔ)方式,同樣提供了大量方便的隨機(jī)訪問函數(shù)。

然而不正確的使用很多時(shí)候反而會(huì)適得其反,給人一種如此高級(jí)的三方庫性能還不如list手動(dòng)造輪子的錯(cuò)覺。

本文主要通過優(yōu)化數(shù)據(jù)結(jié)構(gòu)以及一些使用中的注意點(diǎn)來提高在大數(shù)據(jù)量下數(shù)據(jù)的處理速度。

避免使用append來逐行添加結(jié)果

很多人在逐行處理數(shù)據(jù)的時(shí)候,喜歡使用append來逐行將結(jié)果寫入DataFrame或ndarry。類似下面的寫法: 

1.png

這是非常不好的習(xí)慣,numpy或pandas在實(shí)現(xiàn)append的時(shí)候,實(shí)際上對(duì)內(nèi)存塊進(jìn)行了拷貝——當(dāng)數(shù)據(jù)塊逐漸變大的時(shí)候,這一操作的開銷會(huì)非常大。

下面是官方文檔對(duì)此的描述:

Numpy: 2.png

Pandas.DataFrame: 3.png

實(shí)際上,受list的append操作的影響,開發(fā)者會(huì)不假思索的認(rèn)為numpy和pandas中的append也是簡單的數(shù)組尾部拼接。這實(shí)際上是一個(gè)很嚴(yán)重的誤解,會(huì)產(chǎn)生很多不必要的拷貝開銷。筆者沒有深入研究它們這么設(shè)計(jì)原因,猜測(cè)可能是為了保證拼接后的數(shù)組在內(nèi)存中依然是連續(xù)區(qū)塊——這對(duì)于高性能的隨機(jī)查找和隨機(jī)訪問是很有必要的。

解決辦法:

除非必須,在使用DataFrame的部分函數(shù)時(shí),考慮將inplace=True。出于保證原始數(shù)據(jù)的一致性,DataFrame的大部分方法都會(huì)返回一個(gè)原始數(shù)據(jù)的拷貝,如果要將返回結(jié)果寫回,用這種方式效率更高。

除非必須,避免使用逐行處理。Numpy和pandas都提供了很多非常方便的區(qū)塊選取及區(qū)塊處理的辦法。這些功能非常強(qiáng)大,支持按條件的選取,能滿足大部分的需求。同時(shí)因?yàn)閚darry和DataFrame都具有良好的隨機(jī)訪問的性能,使用條件選取執(zhí)行的效率往往是高于條件判斷再執(zhí)行的。

4.png

特殊情況下,使用預(yù)先聲明的數(shù)據(jù)塊而避免append。如果在某些特殊需求下(例如當(dāng)前行的處理邏輯依賴于上一行的處理結(jié)果)并且需要構(gòu)造新的數(shù)組,不能直接寫入源數(shù)據(jù)時(shí)。這種情況下,建議提前聲明一個(gè)足夠大的數(shù)據(jù)塊,將自增的逐行添加改為逐行賦值。 

5.png

這種寫法本質(zhì)上是通過空間換取時(shí)間,即便數(shù)據(jù)量非常巨大,無法一次性寫入內(nèi)存,也可以通過數(shù)據(jù)塊的方式,減少不必要的拼接操作。需要注意的是,數(shù)據(jù)塊的邊界處理?xiàng)l件,以避免漏行。

避免鏈?zhǔn)劫x值

鏈?zhǔn)劫x值是幾乎所有pandas的新人都會(huì)在不知不覺中犯的錯(cuò)誤,并且產(chǎn)生惱人而又意義不明的SettingWithCopyWarning警告。實(shí)際上這個(gè)警告是在提醒開發(fā)者,你的代碼可能沒按你的預(yù)期運(yùn)行,需要檢查——很多時(shí)候可能產(chǎn)生難以調(diào)試發(fā)現(xiàn)的錯(cuò)誤。當(dāng)使用DataFrame作為輸入的第三方庫時(shí),非常容易產(chǎn)生這類錯(cuò)誤,且難以判斷問題到底出現(xiàn)在哪兒。

在繼續(xù)講解鏈?zhǔn)綇?fù)制前,需要先了解pandas的方法有一部分是返回的是輸入數(shù)據(jù)的視圖(view)一部分返回的是輸入數(shù)據(jù)的拷貝(copy),還有少部分是直接修改源數(shù)據(jù)。

6.png

上圖很好的解釋了視圖與拷貝的關(guān)系。當(dāng)需要對(duì)df2進(jìn)行修改時(shí),有時(shí)候我們希望df1也能被修改,有時(shí)候則不希望。而當(dāng)使用鏈?zhǔn)劫x值時(shí),則有可能產(chǎn)生歧義。這里的歧義指的是面向開發(fā)人員的,代碼執(zhí)行是不會(huì)有歧義的。 

鏈?zhǔn)剿饕?,就是?duì)同一個(gè)數(shù)據(jù)連續(xù)的使用索引,形如data[1:5][2:3]這樣。而鏈?zhǔn)劫x值,就是使用鏈?zhǔn)剿饕M(jìn)行賦值操作。下圖是一個(gè)鏈?zhǔn)劫x值的例子,解釋器給出了SettingWithCopyWarning警告,同時(shí)對(duì)data的賦值操作也沒有成功。 

7.png

解決辦法:上圖中的警告建議,當(dāng)你想修改原始數(shù)據(jù)時(shí),使用loc來確保賦值操作被在原始數(shù)據(jù)上執(zhí)行,這種寫法對(duì)開發(fā)人員是無歧義的(開發(fā)人員往往會(huì)誤認(rèn)為鏈?zhǔn)劫x值修改的依然是源數(shù)據(jù))。

反過來的情況并不會(huì)發(fā)生這種歧義。如果開發(fā)人員想選取源數(shù)據(jù)的一部分,修改其中某列的值并賦給新的變量而不修改源數(shù)據(jù),那么正常的寫法就是無歧義的。 

8.png

然而有些隱蔽的鏈?zhǔn)剿饕⒉皇呛唵蔚南裆鲜銮闆r那樣,有可能跨越多行代碼,甚至函數(shù)。下圖的例子中,data_part是對(duì)data的選取,而賦值操作又對(duì)data_part進(jìn)行了選取,此時(shí)構(gòu)成了鏈?zhǔn)剿饕?nbsp;

9.png

解決辦法:當(dāng)你確定是要構(gòu)造拷貝時(shí),明確指明構(gòu)造拷貝。避免對(duì)有可能是視圖的中間變量進(jìn)行修改。 

10.png

需要注意的是:DataFrame的索引操作到底是返回視圖還是返回拷貝,取決于數(shù)據(jù)本身。對(duì)于單類型數(shù)據(jù)(全是某一類型的DataFrame)出于效率的考慮,索引操作總是返回視圖,而對(duì)于多類型數(shù)據(jù)(列與列的數(shù)據(jù)類型不一樣)則總是返回拷貝。但也請(qǐng)不要依賴這一特性,因?yàn)楦鶕?jù)內(nèi)存布局,其行為未必總是一致。最好的方法還是明確指定——如果想要寫入副本數(shù)據(jù),就在索引時(shí)明確拷貝;如果想要修改源數(shù)據(jù),就使用loc嚴(yán)格賦值。 

總結(jié)

1.可以直接修改源數(shù)據(jù)就修改源數(shù)據(jù),避免不必要的拷貝

2.使用條件索引替代逐行遍歷

3.構(gòu)造數(shù)據(jù)塊替代逐行添加

4.想修改源數(shù)據(jù)時(shí)使用data.loc[row_index, col_index]替代鏈?zhǔn)劫x值

5.想構(gòu)造副本時(shí)嚴(yán)格使用copy消除****鏈?zhǔn)劫x值

參考資料:

https://numpy.org/doc/stable/reference/generated/numpy.append.html

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.append.html

https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#indexing-label

https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#indexing-view-versus-copy

https://zhuanlan.zhihu.com/p/41202576 

*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。



關(guān)鍵詞: AI

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉