Pandas程式設計庫對資料科學界來說是一份天賜的禮物。無論你問哪一個資料科學家,他們是怎樣使用Python處理他們的資料集,他們無疑都會談到Pandas。
Pandas是一個偉大的程式設計庫的縮影:簡單、直觀、功能廣泛。
然而,對資料科學家的Pandas資料框進行數千甚至數百萬次的計算,卻仍然是一項挑戰。你不能只是將資料放入編寫Python for迴圈語句中,並期望在合理的時間內處理你的資料。
pandas是為一次性處理整個行或列的向量化操作而設計的,迴圈在每個單元格、行或列中,但並不是設計使用庫的方式。因此,在使用Pandas時,你應該考慮高度可並行化的矩陣運演算法。
本指南將教你如何使用Pandas,它是被設計來使用和思考的矩陣運算。在此過程中,我將向你展示一些實用的且節省時間的技巧和竅門,這些技巧和竅門將使你的Pandas程式碼比那些可怕的Python for迴圈更快地執行!
我們的設定
在本教程中,我們將使用經典的Iris Flowers資料集。 讓我們透過用seaborn載入的資料集並輸入前5行來開始滾動。
現在讓我們構建一個基線,用Python for迴圈來測量我們的速度。我們將透過迴圈每一行來設定要在資料集上執行的計算,然後測量整個操作的速度。這將為我們提供一個基線,看看我們的新最佳化能在多大程度上幫助我們擺脫困境。
在上面的程式碼中,我們建立了一個基本函式,它使用的是If-Else語句。我們編寫了一個for迴圈,透過迴圈dataframe對每一行應用函式,然後測量迴圈的總執行時間。
在我的i7-8700k計算機上,迴圈執行5次平均需要0.01345秒。
迴圈語句.iterrows()
這是最簡單但非常有價值的,可以加速使用Pandas內建的.iterrows()函式。
當我們在上一節中編寫for迴圈時,我們使用了range()函式。 然而,當我們在Python中迴圈大量值時,生成器往往要快得多。在本文中,你可以閱讀更多關於生成器是如何工作的資訊,並還會使其執行得更快。
Pandas的.iterrows()函式在內部實現了一個生成器函式,它將在每次迭代時產生一行Dataframe。更確切地說,.iterrows()為DataFrame中的每一行產生(index, Series)元組。 這實際上與在原始Python中使用enumerate()之類的東西相同,但執行速度要快得多。
下面我們修改了程式碼,使用.iterrows()而不是常規的for迴圈。 在我上一節用於測試的完全相同的機器上,平均執行時間為0.005892秒 - 加速2.28倍!
.iterrows()函式給我們帶來了很大的提升速度,但是我們還遠遠沒有完成。請始終記住,當使用專為向量操作設計的庫時,可能有一種方法可以在沒有for迴圈的情況下最有效地完成任務。
為我們提供此功能的Pandas功能是.apply()函式。我們的function.apply()接受另一個函式作為其輸入,並沿著DataFrame的軸(行、列等)應用它。 在我們傳遞函式的情況下,lambda通常可以方便地將所有內容打包在一起。
在下面的程式碼中,我們已經完全用.apply()和lambda函式替換了我們的for迴圈來打包我們想要的計算。在我的機器上,此程式碼的平均執行時間為0.0020897秒 ,比我們原來的for迴圈速度快了6.44倍。
apply()之所以這麼快,是因為它在內部嘗試了Cython迭代器。如果你的函式恰好針對Cython進行了最佳化,那麼.apply()將為您帶來更大的速度。還有額外的一點好處是,使用內建函式可以生成更乾淨、更易讀的程式碼。
最後
前面我提到過,如果你正在使用一個為向量化操作設計的庫,那麼你應該始終尋找一種不使用for迴圈去進行計算的方法。
同樣,有許多以這種方式設計的庫,包括pandas,將具有方便的內建函式,可以執行你正在尋找的精確計算,並且速度更快。
來自Pandas的.cut()函式將一組bin定義為輸入,這些bin定義了If-Else的每個範圍和每一組標籤,這些標籤定義了每個範圍返回的值。 然後它執行我們使用compute_class()函式,且手動編寫的完全相同的操作。
檢視下面的程式碼,瞭解.cut()的工作原理。 我們再次獲得了更清晰、更易讀的程式碼所帶來的好處。 最後,.cut()函式平均執行0.001423秒 , 比原來的for迴圈快了9.39倍!
Pandas程式設計庫對資料科學界來說是一份天賜的禮物。無論你問哪一個資料科學家,他們是怎樣使用Python處理他們的資料集,他們無疑都會談到Pandas。
Pandas是一個偉大的程式設計庫的縮影:簡單、直觀、功能廣泛。
然而,對資料科學家的Pandas資料框進行數千甚至數百萬次的計算,卻仍然是一項挑戰。你不能只是將資料放入編寫Python for迴圈語句中,並期望在合理的時間內處理你的資料。
pandas是為一次性處理整個行或列的向量化操作而設計的,迴圈在每個單元格、行或列中,但並不是設計使用庫的方式。因此,在使用Pandas時,你應該考慮高度可並行化的矩陣運演算法。
本指南將教你如何使用Pandas,它是被設計來使用和思考的矩陣運算。在此過程中,我將向你展示一些實用的且節省時間的技巧和竅門,這些技巧和竅門將使你的Pandas程式碼比那些可怕的Python for迴圈更快地執行!
我們的設定
在本教程中,我們將使用經典的Iris Flowers資料集。 讓我們透過用seaborn載入的資料集並輸入前5行來開始滾動。
現在讓我們構建一個基線,用Python for迴圈來測量我們的速度。我們將透過迴圈每一行來設定要在資料集上執行的計算,然後測量整個操作的速度。這將為我們提供一個基線,看看我們的新最佳化能在多大程度上幫助我們擺脫困境。
在上面的程式碼中,我們建立了一個基本函式,它使用的是If-Else語句。我們編寫了一個for迴圈,透過迴圈dataframe對每一行應用函式,然後測量迴圈的總執行時間。
在我的i7-8700k計算機上,迴圈執行5次平均需要0.01345秒。
迴圈語句.iterrows()
這是最簡單但非常有價值的,可以加速使用Pandas內建的.iterrows()函式。
當我們在上一節中編寫for迴圈時,我們使用了range()函式。 然而,當我們在Python中迴圈大量值時,生成器往往要快得多。在本文中,你可以閱讀更多關於生成器是如何工作的資訊,並還會使其執行得更快。
Pandas的.iterrows()函式在內部實現了一個生成器函式,它將在每次迭代時產生一行Dataframe。更確切地說,.iterrows()為DataFrame中的每一行產生(index, Series)元組。 這實際上與在原始Python中使用enumerate()之類的東西相同,但執行速度要快得多。
下面我們修改了程式碼,使用.iterrows()而不是常規的for迴圈。 在我上一節用於測試的完全相同的機器上,平均執行時間為0.005892秒 - 加速2.28倍!
.iterrows()函式給我們帶來了很大的提升速度,但是我們還遠遠沒有完成。請始終記住,當使用專為向量操作設計的庫時,可能有一種方法可以在沒有for迴圈的情況下最有效地完成任務。
為我們提供此功能的Pandas功能是.apply()函式。我們的function.apply()接受另一個函式作為其輸入,並沿著DataFrame的軸(行、列等)應用它。 在我們傳遞函式的情況下,lambda通常可以方便地將所有內容打包在一起。
在下面的程式碼中,我們已經完全用.apply()和lambda函式替換了我們的for迴圈來打包我們想要的計算。在我的機器上,此程式碼的平均執行時間為0.0020897秒 ,比我們原來的for迴圈速度快了6.44倍。
apply()之所以這麼快,是因為它在內部嘗試了Cython迭代器。如果你的函式恰好針對Cython進行了最佳化,那麼.apply()將為您帶來更大的速度。還有額外的一點好處是,使用內建函式可以生成更乾淨、更易讀的程式碼。
最後
前面我提到過,如果你正在使用一個為向量化操作設計的庫,那麼你應該始終尋找一種不使用for迴圈去進行計算的方法。
同樣,有許多以這種方式設計的庫,包括pandas,將具有方便的內建函式,可以執行你正在尋找的精確計算,並且速度更快。
來自Pandas的.cut()函式將一組bin定義為輸入,這些bin定義了If-Else的每個範圍和每一組標籤,這些標籤定義了每個範圍返回的值。 然後它執行我們使用compute_class()函式,且手動編寫的完全相同的操作。
檢視下面的程式碼,瞭解.cut()的工作原理。 我們再次獲得了更清晰、更易讀的程式碼所帶來的好處。 最後,.cut()函式平均執行0.001423秒 , 比原來的for迴圈快了9.39倍!