pandas 中這 3 個函數,沒想到竟成了我數據處理的主力!

2021-02-21 Python數據科學

學Pandas有一年多了,用Pandas做數據分析也快一年了,常常在總結梳理一些Pandas中好用的方法。今天,延承這一系列,再分享三個函數,堪稱是個人日常在數據處理環節中應用頻率較高的3個函數:apply、map和applymap,其中apply是主角,map和applymap為贈送。

數據處理環節無非就是各種數據清洗,除了常規的缺失值和重複值處理邏輯相對較為簡單,更為複雜的其實當屬異常值處理以及各種數據變換:例如類型轉換、簡單數值計算等等。在這一過程中,如何既能保證數據處理效率而又不失優雅,Pandas中的這幾個函數堪稱理想的解決方案。
為展示應用這3個函數完成數據處理過程中的一些demo,這裡以經典的鐵達尼號數據集為例。需要下載該數據集和文中示例源碼的可後臺回復關鍵字apply獲取下載方式。

在學習apply具體應用之前,有必要首先闡釋apply函數的方法論。apply英文原義是"應用"的意思,作為程式語言中的函數名,似乎在很多種語言都有體現,比如近日個人在學習Scala語言中apply被用作是伴生對象中自動創建對象的預設實現,如此重要的角色也可見apply這個函數的重要性。那麼apply應用在Pandas中,其核心功能其實可以概括為一句話:

apply:我本身不處理數據,我們只是數據的搬運工。

說人話就是,apply自身是不帶有任何數據處理功能的,但可以用作是對其他數據處理方法的調度器,至於調度什麼又為誰而調度呢?這是理解apply的兩個核心環節:

調度什麼?調度的是apply函數接收的參數,即apply接收一個數據處理函數為主要參數,並將其應用到相應的數據上。所以調度什麼取決於接收了什麼樣的數據處理函數;

為誰調度?也就是apply接收的數據處理函數,其作用對象是誰?或者說數據處理的粒度是什麼?答案是數據處理的粒度包括了點線面三個層面:即可以是單個元素(標量,scalar),也可以是一行或一列(series),還可以是一個dataframe。

當然,這些文字描述肯定還比較抽象,那麼不妨直接進入正題:talk is cheap,show me the code!

前面提到,理解apply核心在於明確兩個環節:調度函數和作用對象。調度函數就是apply接收的參數,既可以是Python內置的函數,也支持自定義函數,只要符合指定的作用對象(即是標量還是series亦或一個dataframe)即可。而作用對象則取決於調用apply的對象類型,具體來說:

一個Series對象調用apply時,數據處理函數作用於該Series的每個元素上,即作用對象是一個標量,實現從一個Series轉換到另一個Series;

一個DataFrame對象調用apply時,數據處理函數作用於該DataFrame的每一行或者每一列上,即作用對象是一個Series,實現從一個DataFrame轉換到一個Series上;

一個DataFrame對象經過groupby分組後調用apply時,數據處理函數作用於groupby後的每個子dataframe上,即作用對象還是一個DataFrame(行是每個分組對應的行;列欄位少了groupby的相應列),實現從一個DataFrame轉換到一個Series上。

以鐵達尼號數據集為例,這裡分別舉幾個小例子。原始數據集如下:

①將性別sex列轉化為0和1數值,其中female對應0,male對應1。應用apply函數實現這一功能非常簡單:

其中,這裡apply接收了一個lambda匿名函數,通過一個簡單的if-else邏輯實現數據映射。該功能十分簡單,接收的函數也不帶任何其他參數。

②下面再來一個稍微複雜一點的案例,注意到年齡age列當前數據類型是小數,需要將其轉換為整數,同時還有0.9167這種過小的年齡,所以要求接受一個函數,支持接受指定的最大和最小年齡限制,當數據中超出此年齡範圍的統一用截斷填充,同時由於原數據集中age列存在缺失值,還需首先進行缺失值填充。這裡首先實現一個自定義函數用於實現指定的年齡處理功能:

def get_age(age, max_age, min_age):    age = int(age)  # 轉換為整數    if age > max_age:        age = max_age    if age < min_age:        age = min_age    return age

然後,直接對age列調用該函數即可,其中除了第一個參數age由調用該函數的series進行向量化填充外,另兩個參數需要指定,在apply中即通過args傳入。具體而言,實現如下:

DataFrame是pandas中的核心數據結構,其每一行和每一列都是一個Series數據類型。那麼應用apply到一個DataFrame的每個Series,自然存在一個問題是應用到行還是列的問題,所以一個DataFrame調用apply函數時需要指定一個axis參數,其中axis=0對應行方向的處理,即對每列應用apply接收函數;axis=1對應列方向處理,即對每行應用接收函數。默認為axis=0。這裡仍然舉兩個小例子:

①取所有數值列的數據最大值。當然,這個處理其實可以直接調用max函數,但這裡為了演示apply應用,所以不妨照此嘗試:

上述apply函數完成了對四個數值列求取最大值,其中預設axis參數為0,對應行方向處理,即對每一列數據求最大值。
②然後來一個按行方向處理的例子,例如根據性別和年齡,區分4類人群:即女孩、成年女子、男孩、成年男子,其中年齡以18歲為界值進行區分。首先給出人群劃分的函數實現:
def cat_person(sr):    if sr['sex_num'] == 0:        if sr['age_num'] < 18:            return '女孩'        else:            return '成年女子'    else:        if sr['age_num'] < 18:            return '男孩'        else:            return '成年男子'

基於此,用apply簡單調用即可,其中axis=1設置apply的作用方向為按列方向,即對每行進行處理。其中每行都相當於一個帶有age和sex等信息的Series,通過cat_person函數進行提取判斷,即實現了人群的劃分:

3. 應用到DataFrame groupby後的每個分組DataFrame

實際上,個人一直覺得這是一個非常有效的用法,相較於原生的groupby,通過配套使用goupby+apply兩個函數,實現更為個性化的聚合統計功能。例如,這裡我們希望統計不同艙位等級內的"生存年齡比"(僅為配合舉例而隨意定義的指標,無實際含義),定義為各艙位等級內生存人員的年齡之和與所有人員年齡之和的比值。為實現這一數據統計,則首先應以艙位等級作為分組欄位進行分組,而後對每個分組內的數據進行聚合統計,示例代碼如下:

其中apply接收一個lambda匿名函數,該匿名函數接收一個dataframe為參數(該dataframe中不含pclass列),並提取survived列和age_num列參與計算。最後得到每個艙位等級的一個統計指標結果,返回類型是一個Series對象。

以上,可以梳理apply函數的執行流程:首先明確調用apply的數據結構類型,是Series還是DataFrame,如果是DataFrame還需進一步確定是直接調用apply還是經過groupby分組之後調用,其中前者對應apply的接收函數處理一行或一列,後者對應接收函數處理每個分組對應的子DataFrame,最後根據作用對象類型設計相應的接收函數,從而完成個性化的數據處理。

前面介紹了apply的三種應用場景,作用對象分別對應元素、Series以及DataFrame,可以說功能已經非常強大了。除了apply之外,pandas其實還提供了兩個功能極為相近的函數:map和applymap,不過相較於功能強大的apply來說,二者功能則相對局限。具體而言,二者分別實現功能如下:

1.map 在Python中提到map關鍵詞,個人首先聯想到的是兩個場景:①一種數據結構,即字典或者叫映射,通過鍵值對的方式組織數據,在Python中叫dict;②Python的一個內置函數叫map,實現數據按照一定規則完成映射的過程。而在Pandas框架中,這兩種含義都有所體現:對一個Series對象的每個元素實現字典映射或者函數變換,其中後者與apply應用於Series的用法完全一致,而前者則僅僅是簡單將函數參數替換為字典變量即可。仍以替換性別一列為0/1數值為例,應用map函數的實現方式為:

雖然map對於Series元素級的變換提供了兩種數據轉換方式,但卻僅能用於Series,而無法應用到DataFrame上。但與此同時,map相較於apply又在另一個方面具有獨特應用,即對於索引列這種特殊的Series只能應用map,而無法應用apply。

2.applymap 從名字上可以看出,這好像是個apply函數與map函數的混合體,實際上也確實有這方面的味道:即applymap綜合了apply可以應用到DataFrame和map僅能應用到元素級進行變換的雙重特性,所以applymap是將接收函數應用於DataFrame的每個元素,以實現相應的變換。

從某種角度來講,這種變換得以實施的前提是該DataFrame的各列元素具有相同的數據類型和相近的業務含義,否則運用相同的數據變換很難保證實際效果。

假設需要獲取DataFrame中各個元素的數據類型,則應用applymap實現如下:

apply、map和applymap常用於實現Pandas中的數據變換,通過接收一個函數實現特定的變換規則;apply功能最為強大,可應用於Series、DataFrame以及DataFrame分組後的group DataFrame,分別實現元素級、Series級以及DataFrame級別的數據變換;map僅可作用於Series實現元素級的變換,既可以接收一個字典完成變化也可接收特定的函數,而且不僅可作用於普通的Series類型,也可用於索引列的變換,而索引列的變換是apply所不能應用的;applymap僅可用於DataFrame,接收一個函數實現對所有數據實現元素級的變換

愛點讚的人,運氣都不會太差

相關焦點

  • 100 個 pandas 數據分析函數總結
    (點擊上方快速關注並設置為星標,一起學Python)來源:數據分析1480
  • 盤點Pandas 的100個常用函數
    作者 | 劉順祥 來源 | 數據分析1480 這一期將分享我認為比較常規的100個實用函數,這些函數大致可以分為六類,分別是統計匯總函數、數據清洗函數、數據篩選、繪圖與元素級運算函數、時間序列函數和其他函數。
  • Python 數據處理庫 pandas 入門教程
    這兩種類型的數據結構對比如下:名稱維度說明Series1維帶有標籤的同構類型數組DataFrame2維表格結構,帶有標籤,大小可變,且可以包含異構的數據列DataFrame可以看做是Series的容器,即:一個DataFrame中可以包含若干個Series。註:在0.20.0版本之前,還有一個三維的數據結構,名稱為Panel。
  • Pandas 數據處理|Datetime 時間模塊在 Pandas 中的使用
    Datatime 作為 Python 中的時間模塊類型,處理時間有關數據是非常方便的, Pandas 作為數據分析程序包同樣也支持 DataTime 數據機制,例如1,函數 to_datetime() 將數據列表中的 Series 列轉化為 datetime 類型,#Convert the type to datetimeapple.Date =
  • Python 數據處理庫 pandas 進階教程
    0, 1000)之間的隨機數,然後組裝成3行12列的矩陣(如果你對NumPy不熟悉可以訪問NumPy官網學習,或者看一下我之前寫過的:Python 機器學習庫 NumPy 教程)。例如,某個多條數據分散在3個地方記錄,最後我們將三個數據添加到一起。
  • Pandas 數據處理 | Datetime 時間模塊在 Pandas 中的使用
    Datatime 作為 Python 中的時間模塊類型,處理時間有關數據是非常方便的, Pandas 作為數據分析程序包同樣也支持 DataTime 數據機制,例如1,函數 to_datetime() 將數據列表中的 Series 列轉化為 datetime 類型,#Convert the type to datetimeapple.Date
  • 通過 SQL 查詢學習 Pandas 數據處理
    ://shzhangji.com/cnblogs/2017/07/23/learn-pandas-from-a-sql-perspective/Pandas 是一款廣泛使用的數據處理工具。本文提供了一系列的示例,如何將常見的 SQL 查詢語句使用 Pandas 來實現。Pandas 的安裝和基本概念並不在本文講述範圍內,請讀者到官網上閱讀相關文檔,或者閱讀《利用 Python 進行數據分析》一書。我推薦大家使用 Anaconda Python 套件,其中集成了 Spyder 集成開發環境。
  • Pandas 3個不為人知卻好用的函數
    中不得不知的4個重要函數中,我們分享過Numpy中幾個特別實用的功能,今天再和大家分享Pandas中的幾個重要函數。idxmin() 和 idxmax()Pandas 裡面的 idxmin 、idxmax函數與Numpy中 argmax、argmin 用法大致相同,這些函數將返回第一次出現的最小/最大值的索引。在下面代碼中,我們構建了一個DataFrame,通過idxmin() 函數幫助我們找到了每列的最小值所對應的索引。
  • 數據處理必看:如何讓你的 pandas 循環加快 71803 倍
    雷鋒網 AI 開發者按,如果你使用 python 和 pandas 進行數據分析,那麼不久你就會第一次使用循環了。然而,即使是對小型數據集,使用標準循環也很費時,你很快就會意識到大型數據幀可能需要很長的時間。當我第一次等了半個多小時來執行代碼時,我找到了接下來想與你共享的替代方案。標準循環數據幀是具有行和列的 pandas 對象。
  • 這是 Pandas 最詳細教程了
    有一個用於數據科學的包絕對是必需的,它就是 pandas。pandas 最有趣的地方在於裡面隱藏了很多包。它是一個核心包,裡面有很多其他包的功能。這點很棒,因為你只需要使用 pandas 就可以完成工作。
  • 數據分析利器 pandas 系列教程(二):強大的 DataFrame
    在上一篇文章 數據分析利器 pandas 系列教程(一):從 Series 說起  中:詳細介紹了 pandas 基礎數據結構 Series,今天說說另一種數據結構 DataFrame。創建 dataframe 其實有 N 種方法,沒必要一一掌握,畢竟常用的不過兩三種,我也不打算把所有的創建方式都說一遍,那樣有炫技的嫌疑,按照自己的理解,我把這些創建方式統一分為兩大類:按列的方式創建、按行的方式創建,只講這兩大類下各自最具代表性的創建方式。
  • Python 數據分析:Pandas 進階
    概述我們在上一篇文章初識 Pandas中已經對 Pandas 作了一些基本介紹,本文我們進一步來學習 Pandas 的一些使用。2. 缺失項在現實中我們獲取到的數據有時會存在缺失項問題,對於這樣的數據,我們通常需要做一些基本處理,下面我們通過示例來看一下。
  • 別找了,這是 Pandas 最詳細教程了
    有一個用於數據科學的包絕對是必需的,它就是 pandas。pandas 最有趣的地方在於裡面隱藏了很多包。它是一個核心包,裡面有很多其他包的功能。這點很棒,因為你只需要使用 pandas 就可以完成工作。pandas 相當於 python 中 excel:它使用表(也就是 dataframe),能在數據上做各種變換,但還有其他很多功能。如果你早已熟知 python 的使用,可以直接跳到第三段。
  • Python 數據處理(六)—— panda 基礎介紹
    Python 數據處理(六)前言在這裡,我們將會討論很多 pandas 數據結構所共有的基本功能函數先讓我們來創建一個示例對象In [1]: index = pd.date_range("1/1/2000", periods
  • 用 Pandas 讀寫網頁中的 HTML 表格數據
    我們可以使用HTML的<table>標籤來呈現表格數據。Pandas 數據分析庫提供了read_html()和to_html()之類的功能,因此我們可以將數據導入和導出到DataFrames。在本文中,我們將學習如何從HTML文件讀取表格數據並將其加載到Pandas DataFrame中。我們還將學習如何將數據從Pandas DataFrame寫入HTML文件。
  • 數據科學 | 從 Pandas 小白到 Pandas 能手
    在本文中,作者從 Pandas 的簡介開始,一步一步講解了 Pandas 的發展現狀、內存優化等問題。這是一篇最佳實踐教程,既適合用過 Pandas 的讀者,也適合沒用過但想要上手的小白。通過本文,你將有望發現一到多種用 pandas 編碼的新方法。Pandas 發展現狀;內存優化;索引;方法鏈;隨機提示。
  • 數據預處理的 10 個小技能,附 Pandas 實現
    數據預處理常用的處理步驟,包括找出異常值、處理缺失值、過濾不合適值、去掉重複行、分箱、分組、排名、category轉數值等,下面使用 pandas 解決這些最常見的預處理任務。import pandas as pddf = pd.DataFrame({'a':[1,3,np.nan],'b':[4,np.nan,np.nan]})# 異常值平均值上下1.96個標準差區間以外的值meangrade = df['a'].mean()stdgrade = df['a'].std()toprange = meangrade
  • 史上最全Pandas 教程!
    有一個用於數據科學的包絕對是必需的,它就是 pandas。pandas 最有趣的地方在於裡面隱藏了很多包。它是一個核心包,裡面有很多其他包的功能。這點很棒,因為你只需要使用 pandas 就可以完成工作。pandas 相當於 python 中 excel:它使用表(也就是 dataframe),能在數據上做各種變換,但還有其他很多功能。如果你早已熟知 python 的使用,可以直接跳到第三段。
  • 30 個函數,加速你的數據分析處理速度!
    為了更好的學習 Python,我將以客戶流失數據集為例,分享 「30」 個在數據分析過程中最常使用的函數和方法,數據「文末」可以下載。我們減了 4 列,因此列數從 14 個減少到 10 列。2.選擇特定列我們從 csv 文件中讀取部分列數據。可以使用 usecols 參數。
  • Pandas transform函數
    Pandas是一個很有用的庫,它包含了大量用於操作數據的內置函數。其中,transform()在處理行或列時非常有用。在本文中,我們將介紹以下最常用的Pandas transform()用途:轉換值組合groupby()過濾數據在組級別處理缺失值請查看我的Github repo以獲取原始碼;https://github.com