Python資料處理:Pandas模組的 12 種實用技巧
簡介
Python 正迅速成為資料科學家們更為鍾愛的程式語言。形成該現狀的理由非常充分:Python 提供了一種覆蓋範圍更為廣闊的程式語言生態系統,以及具有一定計算深度且效能良好的科學計算庫。如果您是 Python 初學者,建議首先看下Python 學習路線。
在 Python 自帶的科學計算庫中,Pandas 模組是最適於資料科學相關操作的工具。它與 Scikit-learn 兩個模組幾乎提供了資料科學家所需的全部工具。本文著重介紹了 Python 中資料處理的 12 種方法。此前的文章裡也分享了一些技巧和經驗,這些將有助於您提高工作效率。
在本文開始前,推薦讀者首先了解一些資料探勘的相關程式碼。為使本文更易於理解,我們事先選定了一個數據集以示範相關操作和處理方法。
資料集來源:本文采用的是貸款預測問題的資料集。請下載該資料集並開始本文內容。
讓我們開始吧
首先匯入相關模組並載入資料集到 Python 環境中:
Python123 | importpandas aspdimportnumpy asnpdata=pd.read_csv |
#1 – 布林索引
如果需要以其它列資料值為條件過濾某一列的資料,您會怎麼處理?例如建立一個列表,列表中全部為未能畢業但曾獲得貸款的女性。這裡可以使用布林索引,程式碼如下:
Python12 | data.loc[(data["Gender"]=="Female")&(data["Education"]=="Not Graduate")&(data["Loan_Status"]=="Y"),["Gender","Education","Loan_Status"]] |
#2 – Apply 函式
Apply 函式是處理資料和建立新變數的常用函式之一。在向資料框的每一行或每一列傳遞指定函式後,Apply 函式會返回相應的值。這個由 Apply 傳入的函式可以是系統預設的或者使用者自定義的。例如,在下面的例子中它可以用於查詢每一行和每一列中的缺失值。
Python1234567891011 | #Create a new function:defnum_missing(x):returnsum(x.isnull())#Applying per column:print"Missing values per column:"printdata.apply(num_missing,axis=0)#axis=0 defines that function is to be applied on each column#Applying per row:print"nMissing values per row:"printdata.apply(num_missing,axis=1).head()#axis=1 defines that function is to be applied on each row |
這樣我們就得到了所需的結果。
注:由於輸出結果包含多行資料,第二個輸出函式使用了 head() 函式以限定輸出資料長度。在不限定輸入引數時 head() 函式預設輸出 5 行資料。
#3 – 填補缺失值
fillna() 函式可一次性完成填補功能。它可以利用所在列的均值/眾數/中位數來替換該列的缺失資料。下面利用“Gender”、“Married”、和“Self_Employed”列中各自的眾數值填補對應列的缺失資料。
Python123 | #First we import a function to determine the modefromscipy.stats importmodemode(data['Gender']) |
輸出結果為:ModeResult(mode=array([‘Male’], dtype=object), count=array([489]))
輸出結果返回了眾數值和對應次數。需要記住的是由於可能存在多個高頻出現的重複資料,因此眾數可以是一個數組。通常預設使用第一個眾數值:
Python1 | mode(data['Gender']).mode[0] |
現在可以進行缺失資料值填補並利用#2方法進行檢查。
Python1234567 | #Impute the values:data['Gender'].fillna(mode(data['Gender']).mode[0],inplace=True)data['Married'].fillna(mode(data['Married']).mode[0],inplace=True)data['Self_Employed'].fillna(mode(data['Self_Employed']).mode[0],inplace=True)#Now check the #missing values again to confirm:printdata.apply(num_missing,axis=0) |
至此,可以確定缺失值已經被填補。請注意,上述方法是最基本的填補方法。包括缺失值建模,用分組平均數(均值/眾數/中位數)填補在內的其他複雜方法將在接下來的文章中進行介紹。
#4 – 資料透視表
Pandas 可建立 MS Excel 型別的資料透視表。例如在下文的程式碼段裡,關鍵列“LoanAmount” 存在缺失值。我們可以根據“Gender”,“Married”和“Self_Employed”分組後的平均金額來替換。 “LoanAmount”的各組均值可由如下方法確定:
Python123 | #Determine pivot tableimpute_grps=data.pivot_table(values=["LoanAmount"],index=["Gender","Married","Self_Employed"],aggfunc=np.mean)printimpute_grps |
#5 – 複合索引
如果您注意觀察#3計算的輸出內容,會發現它有一個奇怪的性質。即每個索引均由三個數值的組合構成,稱為複合索引。它有助於運算操作的快速進行。
從#3的例子繼續開始,已知每個分組資料值但還未進行資料填補。具體的填補方式可結合此前學到的多個技巧來完成。
Python1234567 | #iterate only through rows with missing LoanAmountfori,row indata.loc[data['LoanAmount'].isnull(),:].iterrows():ind=tuple([row['Gender'],row['Married'],row['Self_Employed']])data.loc[i,'LoanAmount']=impute_grps.loc[ind].values[0]#Now check the #missing values again to confirm:printdata.apply(num_missing,axis=0) |
Note:
注:
1. 多值索引需要在 loc 語句中使用用於定義索引分組的元組結構。該元組會在函式中使用。
2. 應使用字尾 .values[0] 以避免潛在的錯誤。因為預設情況下複合索引返回的 Series 元素索引順序與所在的資料框架(dataframe)不一致。在此條件下直接賦值會產生錯誤。
#6 – Crosstab 函式
該函式用於獲取資料的初始印象(直觀檢視),從而驗證一些基本假設。例如在本例中,“Credit_History”被認為會顯著影響貸款狀態。這個假設可以通過如下程式碼生成的交叉表進行驗證:
Python1 | pd.crosstab(data["Credit_History"],data["Loan_Status"],margins=True) |
以上這些都是絕對值。但百分比形式能獲得更為直觀的資料結果。使用 apply 函式可實現該功能:
Python123 | defpercConvert(ser):returnser/float(ser[-1])pd.crosstab(data["Credit_History"],data["Loan_Status"],margins=True).apply(percConvert,axis=1) |
現在可以證明:與僅佔9%的無信用記錄人群相比,佔比為80%的有信用記錄人群獲得貸款的機率會更高。
但這並不是全部的資料結果,其中還包含了一個有趣的內容。既然已知有信用記錄非常重要,如果利用信用記錄情況進行貸款預測會如何?其中,預測有信用記錄的人的獲得貸款狀態為 Y,否則為 N。令人吃驚的是在614次測試中,共正確預測了 82+378=460 次,正確率高達75%!
如果您正好奇為什麼我們需要統計模型,我一點兒也不會責怪您。但是請相信,提高預測精度是一項非常具有挑戰性的任務,哪怕僅僅是在上述預測結果的基礎上提高0.001%的預測精度也是如此。您會接受這個挑戰嗎?
注:75% 是對本文的訓練資料集而言。測試資料集的結果將會有所不同,但也非常接近。同樣地,希望通過這個例子能讓大家明白為什麼僅僅提高0.05%的預測精度就可在Kaggle排行榜中排名躍升500位。
#7 – 合併資料框(DataFrames)
當有來自不同資料來源的資訊需要收集整理時,合併資料框就變成了一項必不可少的基本操作。考慮一個假設的情況,即不同型別的房產有不同的均價(單位:INR / 平方米)。定義資料框如下:
Python12 | prop_rates=pd.DataFrame([1000,5000,12000],index=['Rural','Semiurban','Urban'],columns=['rates'])prop_rates |
現在可將上述資訊與原始資料框合併如下:
Python12 | data_merged=data.merge(right=prop_rates,how='inner',left_on='Property_Area',right_index=True,sort=False)data_merged.pivot_table(values='Credit_History',index=['Property_Area','rates'],aggfunc=len) |
上述透視表驗證了合併操作成功。需要注意的是由於上述程式碼僅對資料值進行簡單計算,因此‘values’引數在本例中是一個獨立內容,與上下文無關。
#8 – 排列資料框架(DataFrames)
Pandas 允許基於多列資料進行簡單排列。具體實現如下:
Python12 | data_sorted=data.sort_values(['ApplicantIncome','CoapplicantIncome'],ascending=False)data_sorted[['ApplicantIncome','CoapplicantIncome']].head(10) |
注:Pandas模組中的“sort”函式現已不再使用,應用“sort_values”函式進行代替。
#9 – 繪圖(Boxplot 和 Histogram 函式)
許多人也許並沒有意識到 Pandas 模組中的 boxplots 和 histograms 函式可以用於直接繪圖,此時沒有必要再單獨呼叫 matplotlib 模組。一行命令即可完成相關功能。例如,如果想通過 Loan_Status 比較 ApplicantIncome 的分佈情況,則實現程式碼如下:
Python1234 | importmatplotlib.pyplot asplt%matplotlibinlinedata.boxplot(column="ApplicantIncome",by="Loan_Status") |
1 | data.hist(column="ApplicantIncome",by="Loan_Status",bins=30) |
上圖的資料結果表明,由於獲得貸款人群和未獲得貸款人群數沒有明顯的收入差距,因此個人收入水平高低並非是否能獲得貸款的主要決定因素。
#10 – 使用 Cut 函式進行分箱
有時將數值資料聚合在一起會更有意義。例如,如果我們要根據一天中的某個時間段(單位:分鐘)建立交通流量模型模型(以路上的汽車為統計目標)。與具體的分鐘數相比,對於交通流量預測而言一天中的具體時間段則更為重要,如“早上”、 “下午”、“傍晚”、“夜晚”、“深夜(Late Night)”。以這種方式建立交通流量模型則更為直觀且避免了過擬合情況的發生。
下面的例子中定義了一個簡單的可重用函式,該函式可以非常輕鬆地實現任意變數的分箱功能。
Python12345678910111213141516< |