懶人秘籍:教你如何避免編寫pandas代碼

2021-01-12 讀芯術

全文共4781字,預計學習時長14分鐘

來源:Pexels

Pandas在數據科學領域無需介紹,它提供高性能,易於使用的數據結構和數據分析工具。但是,在處理過多的數據時,單核上的Pandas就顯得心有餘而力不足了,大家不得不求助於不同的分布式系統來提高性能。然而,提高性能的權衡常常伴隨著陡峭的學習曲線。

而大家都在儘可能地避免這種懸崖峭壁,結果可想而知,都轉向了如何避免編寫pandas代碼。

在過去4年裡,筆者一直使用pandas作為數據分析的主要工具。必須承認,「如何避免編寫pandas代碼」的大部分內容來自於使用pandas編程的起步階段。在進行代碼審閱時,筆者仍然看到許多經驗豐富的程式設計師在看一些熱門「如何避免使用」的帖子。

在本文中,筆者首先展示了一個「如何避免」的例子,然後展示了一個正確的「如何使用」pandas來計算統計數據的方法。改進後,代碼更簡潔、易讀,執行更快。報告時間的格式為: 831 ms ± 25.7 ms per loop,即平均831毫秒,標準偏差為25.7毫秒。每個代碼示例執行多次,以計算準確的執行時間。

和往常一樣,可以下載 JupyterNotebook並在電腦上試運行。

開始pandas遊戲之旅,請閱讀如下資源:

5個鮮為人知的pandas技巧使用pandas進行探索性數據分析

來源:Pexels

設置

from platform importpython_versionimport numpy as npimport pandas as pdnp.random.seed(42) # set the seed tomake examples repeatable

樣本數據集

樣本數據集包含各個城市的預訂信息,是隨機的,唯一目的是展示樣本。

數據集有三列:

id表示唯一的標識city表示預定的城市信息booked perc表示特定時間預定的百分比

數據集有一萬條,這使速度改進更加明顯。注意,如果代碼以正確的pandas方式編寫,pandas可以利用DataFrames計算數百萬(甚至數十億)行的統計數據。

size = 10000cities =["paris", "barcelona", "berlin", "newyork"]df = pd.DataFrame( {"city": np.random.choice(cities,size=size), "booked_perc": np.random.rand(size)})df["id"] = df.index.map(str) +"-" + df.citydf = df[["id", "city", "booked_perc"]]df.head()

1.如何避免對數據求和

翻滾的熊貓/Reddit

來自Java世界的靈感,把「多行for循環」應用到了Python。

計算booked perc列的總和,把百分比加起來毫無意義,但無論如何,一起來試試吧,實踐出真知。

%%timeitsuma = 0for _, row in df.iterrows(): suma += row.booked_perc766ms ± 20.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

更符合Python風格的方式來對列求和如下:

%%timeitsum(booked_perc forbooked_perc in df.booked_perc)989 s ± 18.5 s per loop (mean ±std. dev. of 7 runs, 1000 loops each)%%timeitdf.booked_perc.sum()92s ± 2.21 s per loop (mean ± std. dev. of 7 runs, 10000 loops each)

正如預期的那樣,第一個示例是最慢的——對一萬項求和幾乎需要1秒。第二個例子的速度之快令人驚訝。

正確的方法是使用pandas對數據進行求和(或對列使用任何其他操作),這是第三個示例——也是最快的!

2.如何避免過濾數據

玩耍的熊貓/Giphy

儘管在使用pandas之前,筆者已經很熟悉numpy,並使用for循環來過濾數據。求和時,還是可以觀察到性能上的差異。

%%timeitsuma = 0for _, row in df.iterrows(): if row.booked_perc <=0.5: suma += row.booked_perc831ms ± 25.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)%%timeitdf[df.booked_perc<= 0.5].booked_perc.sum()724 s ± 18.8 s per loop(mean ± std. dev. of 7 runs, 1000 loops each)

正如預期的一樣,第二個例子比第一個例子快很多

如果加入更多的過濾器呢?只需把它們添加到括號裡

%%timeitdf[(df.booked_perc <=0.5) & (df.city == 'new york')].booked_perc.sum()1.55ms ± 10.7 s per loop (mean ± std. dev. of 7 runs, 1000 loops each)

3.如何避免訪問以前的值

翻滾的熊貓/Giphy

你可能會說:好吧,但是如果需要訪問先前某一列的值呢,還是需要一個for循環。你錯了!

分別使用和不使用for循環來計算一行到另一行百分數的改變

%%timeitfor i inrange(1, len(df)): df.loc[i,"perc_change"] = (df.loc[i].booked_perc- df.loc[i - 1].booked_perc) / df.loc[i- 1].booked_perc7.02 s ± 24.4 ms per loop (mean ± std. dev. of 7runs, 1 loop each)%%timeitdf["perc_change"] = df.booked_perc.pct_change()586s ± 17.3 s per loop (mean ± std. dev. of 7 runs, 1000 loops each)

同樣,第二個例子比第一個使用for循環的例子快得多

pandas有許多函數可以根據以前的值計算統計數據(例如shift函數對值進行移位)。這些函數接受periods參數,可以在計算中包含以前值的數量。

4.如何避免使用複雜的函數

來源:墜落的熊貓(國家地理)Giphy

有時需要在DataFrame中使用複雜函數(有多個變量的函數)。讓我們將從紐約的booking_perc兩兩相乘,其他設置為0並且把這列命名為sales_factor。

筆者首先想到的是使用iterrows的for循環

%%timeitfor i, row in df.iterrows(): if row.city =='new york': df.loc[i, 'sales_factor'] =row.booked_perc * 2 else: df.loc[i, 'sales_factor'] =03.58 s ± 48.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

一個更好的辦法是直接在DataFrame上使用函數

%%timeitdef calculate_sales_factor(row): if row.city =='new york': return row.booked_perc* 2 return 0df['sales_factor'] =df.apply(calculate_sales_factor, axis=1)165 ms ± 2.48 ms per loop(mean ± std. dev. of 7 runs, 10 loops each)

最快的方法是使用pandas過濾器直接計算函數值

%%timeit df.loc[df.city== 'new york', 'sales_factor'] = df[df.city == 'newyork'].booked_perc * 2df.sales_factor.fillna(0, inplace=True)3.03 ms ± 85.5 sper loop (mean ± std. dev. of 7 runs, 100 loops each)

可以看到從第一個例子到最後一個的加速過程。

當解決有3個及3個以上變量的函數時,可以把它分解為多個pandas表達式。這比運用函數更快。

Eg: f(x, a, b) = (a + b) * xdf['a_plus_b'] = df['a'] +df['b']df['f'] = df['a_plus_b'] * df['x']

5.如何避免對數據進行分組

蹭癢熊貓/Giphy

現在可以看到,在開始使用pandas之前,筆者更多依賴於for循環。至於對數據進行分組,如果充分發揮pandas的優勢,可以減少代碼行數。

要計算如下數據:

一個城市的平均sales factor一個城市的首次預定id

%%timeit avg_by_city = {}count_by_city = {}first_booking_by_city = {}for i, row in df.iterrows(): city = row.city if city in avg_by_city: avg_by_city[city] += row.sales_factor count_by_city[city] += 1 else: avg_by_city[city] = row.sales_factor count_by_city[city] = 1 first_booking_by_city[city] =row['id']for city, _ in avg_by_city.items(): avg_by_city[city] /=count_by_city[city]878 ms ± 21.4 ms per loop (mean ± std. dev. of 7 runs, 1 loopeach)

Pandas有分組操作所以不必在DataFrame上進行迭代,pandas的分組操作和SQL的GROUP BY語句一樣的。

%%timeitdf.groupby('city').sales_factor.mean()df.groupby('city').sales_factor.count()df.groupby('city').id.first()3.05 ms ± 65.3 s per loop(mean ± std. dev. of 7 runs, 100 loops each)%%timeitdf.groupby("city").agg({"sales_factor":["mean", "count"], "id": "first"})4.5ms ± 131 s per loop (mean ± std. dev. of 7 runs, 100 loops each)

驚奇的是,第三個例子不是最快的,但比第二個例子更簡潔。筆者建議,如果需要加速的代碼,請用第二種方法。

快樂的熊貓/Giphy

最後,小芯的建議是:如果需要使用pandas編寫for循環,那一定存在一種更好的編寫方式。

會存在一些計算量很大的函數,即使上述的優化方法也會無效。那麼我們就需要使用最後手段:Cython和Numba。

大家一起來試試這些方法吧,一定會有意想不到的收穫~

留言點讚關注

我們一起分享AI學習與發展的乾貨

如轉載,請後臺留言,遵守轉載規範

相關焦點

  • 如何在Python中編寫簡單代碼,並且速度超越Spark?
    數據科學家們用pandas進行探索。然後,其他的數據工程師團隊重新編寫相同的邏輯代碼並使其大規模工作,或者使用Spark令其與實時流一同工作。當數據科學家需要更改邏輯或將一個不同的數據集用於他/她的模型時,則會進行一次次地迭代。除了注意業務邏輯之外,還要分別或同時在Hadoop和Kubernetes構建集群,並應用整個CI / CD過程手動進行管理。
  • 嫌pandas慢又不想改代碼怎麼辦?來試試Modin
    最近看到了一篇也是關於對pandas提速的文章,但是從另一個角度,工具。使用它可以很好的突破操作優化上的瓶頸,而這個工具就是Modin。Modin存在的意義就是:更改一行代碼來提速pandas工作流程。Pandas在數據科學領域就無需介紹了,它提供高性能,易於使用的數據結構和數據分析工具。
  • 在pandas中使用pipe()提升代碼可讀性
    簡介我們在利用pandas開展數據分析時,應儘量避免過於「碎片化」的組織代碼,尤其是創建出過多不必要的「中間變量」,既浪費了「內存」,又帶來了關於變量命名的麻煩,更不利於整體分析過程代碼的可讀性,因此以流水線方式組織代碼非常有必要。
  • PandaSQL:一個讓你能夠通過SQL語句進行pandas的操作的python包
    如果你熟練的使用SQL,那麼這篇文章將介紹一種更直接、簡單的使用Pandas處理大多數數據操作案例。假設你對SQL非常的熟悉,或者你想有更可讀的代碼。或者您只是想在dataframe上運行一個特殊的SQL查詢。或者,也許你來自R,想要一個sqldf的替代品。
  • pandas指南:做更高效的數據科學家
    如果你是Python新手,很難知道針對特定任務的包哪個是最好的。你需要有經驗的人來告訴你。今天我要告訴你們的是:在數據科學中,有一個軟體包是你們絕對需要學習的,那就是pandas。而pandas真正有趣的地方是,很多其他的包也在裡面。pandas是一個核心包,因此它具有來自其他各種包的特性。
  • 如何用pandas更快地進行數據可視化?
    作者:劉早起來源:早起Python(公眾號)如果你經常使用Python進行數據分析,那麼對於pandas一定不會陌生,但是Pandas除了在數據處理上大放異彩,隨著版本的不斷更新,Pandas的繪圖功能在某些情況下甚至要比matplotlib更加適用,本文就將介紹如何用
  • Python數據分析利器,Pandas入門介紹,幫你便捷高效處理複雜數據
    pandas(pannel data analysis,面板數據分析),我個人覺得pandas用於數據分析處理有別於Python字典和列表的主要在於以下三點。運算效率提升,pandas是基於numpy寫的,換句話說也是c語言進行編寫並編譯成本地庫的,在運算效率會高很多。消耗資源少,因為pandas採用矩陣運算,在算法結構上比列表和字典組合數據消耗更少資源。
  • PANDAS: 新手教程 一
    它可以幫助你對數據進行各種操作,並生成有關它的不同報告。我將把這篇文章分成兩篇基本知識-我將在這個故事中介紹。我將介紹Pandas的基本功能,這些功能將使你大致了解如何開始使用Pandas,以及它如何幫助你節省大量時間。高級-將通過高級的功能,使它更容易解決複雜的分析問題。它將涵蓋的主題,如風格,繪圖,讀取多個文件等。第二部分仍在進行中,敬請期待。
  • 用Pandas演示tips的小技巧,學到了嗎?
    無論是學生、數據科學家還是博士研究人員,這些技巧都一定能幫到你。下載Jupyter notebook,一起動動小手來試試吧!設置創建一個10行3列的數據幀,數值隨機。df_list =pd.read_html('analysis.html')df_list編寫文件在代碼中編寫注釋時,將數據幀轉換為字符串會非常有用。print(df.to_string())Excel電子表格Excel的大佬地位毋庸置疑,而Pandas能夠將數據幀轉化為Excel電子表格。
  • 如何通過一頓飯來說明NumPy與pandas的功用
    而在這股勢力中,其主角及成員便是NumPy、pandas、matplotlib以及scipy。本文要簡單介紹的則是主力中的主力:NumPy與pandas。誠然,R語言幾乎專注於統計分析,其第三方包無數,有著統計學的深度以及各學科統計分析應用的廣度,並且也在與Python的較量中不甘示弱。
  • 如何使用Pandas-Profiling進行探索性數據分析
    Pandas-profiling是一個開源Python庫,它只需一行代碼即可為任何機器學習數據集生成漂亮的交互式報告。pandas_profiling使用df.profile_report()擴展了DataFrame,以便進行快速數據分析。
  • 如何用Pandas庫實現MySQL資料庫的讀寫?
    本次分享將介紹如何在Python中使用Pandas庫實現MySQL資料庫的讀寫。首先我們需要了解點ORM方面的知識。pymysql  其中,pandas模塊提供了read_sql_query()函數實現了對資料庫的查詢,to_sql()函數實現了對資料庫的寫入,並不需要實現新建MySQL數據表。
  • 代碼跑得慢甩鍋Python?手把手教你如何給代碼提速30%
    其實某個特定程序(無論使用何種程式語言)的運行速度是快還是慢,在很大程度上取決於編寫該程序的開發人員自身素質,以及他們編寫優化而高效代碼的能力。Medium上一位小哥就詳細講了講如何讓python提速30%,以此證明代碼跑得慢不是python的問題,而是代碼本身的問題。
  • 懂Excel輕鬆入門Python數據分析包pandas(二十一):透視表
    後來才發現,原來不是 Python 數據處理厲害,而是他有數據分析神器—— pandas前言本系列上一節文章最後我隨手使用了 pandas 中的透視表操作,之後有些小夥伴詢問我相關的問題。正好 pandas 的 pivot_table 也是與 Excel 透視表對應。本文簡單教你入門使用 pandas 完成透視表功能。
  • PANDAS: 新手教程 一 - 人工智慧遇見磐創
    它可以幫助你對數據進行各種操作,並生成有關它的不同報告。我將把這篇文章分成兩篇基本知識-我將在這個故事中介紹。我將介紹Pandas的基本功能,這些功能將使你大致了解如何開始使用Pandas,以及它如何幫助你節省大量時間。高級-將通過高級的功能,使它更容易解決複雜的分析問題。它將涵蓋的主題,如風格,繪圖,讀取多個文件等。第二部分仍在進行中,敬請期待。
  • Python學習120課 pandas簡介kaggle下載數據及pandas讀取外部數據
    推薦一個數據平臺:www.kaggle.com數據科學的很多數據是來源於kaggle,這個平臺上有很多公開的數據,而且這些數據都是真實的數據,因此我們後面通過pandas去處理的數據都是從kaggle上下載的數據。●註冊並激活kaggle帳號首先你需要在kaggle註冊一個帳號,才能下載它的數據。
  • 想讓pandas運行更快嗎?那就用Modin吧
    「通過更改一行代碼擴展你的 pandas 工作流。」Pandas 是數據科學領域的工作者都熟知的程序庫。它提供高性能、易於使用的數據結構和數據分析工具。但是,當處理過於龐大的數據時,單個內核上運行的 Pandas 就會變得力不從心,人們不得不求助於不同的分布式系統來提高性能。然而,為了提高性能而做的這種權衡會帶來陡峭的學習曲線。
  • 提高數據處理效率,一行代碼開啟Pandas四倍速!
    如何讓Pandas更快更省心呢?快來了解新庫Modin,可以分割pandas的計算量,提高數據處理效率,一行代碼即刻開啟Pandas四倍速。首先了解一些基礎知識:Pandas作為Python中用於處理數據的庫,能簡單且靈活地處理不同種類、大小的數據。除此之外,Pandas還有許多函數有助於輕鬆處理不同數據。
  • Pandas閃回咒!如何在Python中重寫SQL查詢?
    本文就教你一種方法,使用Pandas在Python中輕鬆重現SQL結果。入門指南如果電腦中沒有pandas包,則需要先安裝一下:Conda install pandas在這個階段,我們將使用著名的Kaggle泰坦尼克數據集:https://www.kaggle.com/c/titanic/data?
  • pandas使用的25個技巧
    查詢pandas版本  如果你還想知道pandas所依賴的模塊的版本,你可以使用show_versions()函數:pandas依賴模塊的版本號你可以查看到Python,pandas, Numpy, matplotlib等的版本信息。2. 創建示例DataFrame   假設你需要創建一個示例DataFrame。