數據處理:12個使得效率倍增的pandas技巧

數據處理:12個使得效率倍增的pandas技巧

1. 背景描述

Python正迅速成爲數據科學家偏心的語言,這合情合理。它擁有做爲一種編程語言廣闊的生態環境以及衆多優秀的科學計算庫。若是你剛開始學習Python,能夠先了解一下Python的學習路線。python

python學習路線:https://www.analyticsvidhya.com/learning-paths-data-science-business-analytics-business-intelligence-big-data/learning-path-data-science-python/git

在衆多的科學計算庫中,我認爲Pandas對數據科學運算最有用。Pandas,加上Scikit-learn幾乎能構成了數據科學家所需的所有工具。 本文旨在提供Python數據處理12種方法。文中也分享了一些會讓你的工做更加便捷的小技巧github

在繼續推動以前,我推薦讀者閱覽一些關於數據探索 (data exploration)的代碼。算法

數據探索:https://github.com/typora/typora-issues/issues數據庫

爲了幫助理解,本文用一個具體的數據集進行運算和操做。本文使用了貸款預測(loan prediction) 問題數據集。編程

數據集:http://datahack.analyticsvidhya.com/contest/practice-problem-loan-prediction數組

2. 12個技巧說明

首先我要導入要用的模塊,並把數據集載入Python環境。app

import pandas as pd  
 import numpy as np  
 data = pd.read_csv("train.csv", index_col="Loan_ID")

2.1 布爾索引(Boolean Indexing)

如何你想用基於某些列的條件篩選另外一列的值,你會怎麼作?例如,咱們想要一個所有無大學學歷但有貸款的女性列表。這裏可使用布爾索引。代碼以下:編程語言

能夠篩選出想要的信息ide

data.loc[(data["Gender"]=="Female") & (data["Education"]=="Not Graduate") & (data["Loan_Status"]=="Y"), ["Gender","Education","Loan_Status"]]

想了解更多請閱讀 Pandas Selecting and Indexing

2.2 Apply函數(Apply Function)

Apply是擺弄數據和創造新變量時經常使用的一個函數。Apply把函數應用於數據框的特定行/列以後返回一些值。這裏的函數既能夠是系統自帶的也能夠是用戶定義的。例如,此處能夠用它來尋找每行每列的缺失值個數:

#建立一個新函數:  
 def num_missing(x):    
    return sum(x.isnull())  
    
 #Apply到每一列:  
 print "Missing values per column:"  
 print data.apply(num_missing, axis=0) #axis=0表明函數應用於每一列  
 
 #Apply到每一行:  
 print "nMissing values per row:"  
 print data.apply(num_missing, axis=1).head() #axis=1表明函數應用於每一行

注意:第二個輸出使用了head()函數,由於數據包含太多行。
想了解更多請閱讀 Pandas Reference (apply)

3.替換缺失值

‘fillna()’ 能夠一次解決這個問題。它被用來把缺失值替換爲所在列的平均值/衆數/中位數。

#首先導入一個尋找衆數的函數:  
 from scipy.stats import mode  mode(data['Gender'])

輸出: ModeResult(mode=array([‘Male’], dtype=object), count=array([489]))
返回了衆數及其出現次數。記住,衆數能夠是個數組,由於高頻的值可能不僅一個。咱們一般默認使用第一個:

mode(data['Gender']).mode[0]

如今能夠填補缺失值,並用上一步的技巧來檢驗。

#值替換:  
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)  #再次檢查缺失值以確認:  
print data.apply(num_missing, axis=0)

因而可知,缺失值肯定被替換了。請注意這是最基本的替換方式,其餘更復雜的技術,如爲缺失值建模、用分組平均數(平均值/衆數/中位數)填充,會在從此的文章提到。
想了解更多請閱讀 Pandas Reference (fillna)

2.4 透視表(Pivot Table)

Pandas能夠用來建立 Excel式的透視表。例如,「LoanAmount」這個重要的列有缺失值。咱們能夠用根據 ‘Gender’、‘Married’、‘Self_Employed’分組後的各組的均值來替換缺失值。每一個組的 ‘LoanAmount’能夠用以下方法肯定:

#Determine pivot table  
impute_grps = data.pivot_table(values=["LoanAmount"], index=["Gender","Married","Self_Employed"], aggfunc=np.mean)  
print impute_grps

想了解更多請閱讀 Pandas Reference (Pivot Table)

2.5 多重索引(Multi-Indexing)

你可能注意到上一步驟的輸出有個奇怪的性質。每一個索引都是由三個值組合而成。這叫作多重索引。它能夠幫助運算快速進行。
延續上面的例子,如今咱們有了每一個分組的值,但尚未替換。這個任務能夠用如今學過的多個技巧共同完成。

#只在帶有缺失值的行中迭代:  
for i,row in data.loc[data['LoanAmount'].isnull(),:].iterrows():    
    ind = tuple([row['Gender'],row['Married'],row['Self_Employed']])                    data.loc[i,'LoanAmount'] = impute_grps.loc[ind].values[0]  

#再次檢查缺失值以確認:  
print data.apply(num_missing, axis=0)

注:

多重索引須要在loc中用到定義分組group的元組(tuple)。這個元組會在函數中使用。
須要使用.values[0]後綴。由於默認狀況下元素返回的順序與原數據庫不匹配。在這種狀況下,直接指派會返回錯誤。

2.6 二維表(Crosstab)

這個功能可被用來獲取關於數據的初始「印象」(觀察)。這裏咱們能夠驗證一些基本假設。例如,本例中「Credit_History」 被認爲對欠款狀態有顯著影響。能夠用下面這個二維表進行驗證:

pd.crosstab(data["Credit_History"],data["Loan_Status"],margins=True)

這些數字是絕對數值。不過,百分比數字更有助於快速瞭解數據。咱們能夠用apply函數達到目的:

def percConvert(ser):    
    return ser/float(ser[-1])    pd.crosstab(data["Credit_History"],data["Loan_Status"],margins=True).apply(percConvert, axis=1)

如今能夠很明顯地看出,有信用記錄的人得到貸款的可能性更高:有信用記錄的人有80% 得到了貸款,沒有信用記錄的人只有 9% 得到了貸款。
但不只僅是這樣,其中還包含着更多信息。因爲我如今知道了有信用記錄與否很是重要,若是用信用記錄來預測是否會得到貸款會怎樣?使人驚訝的是,在614次試驗中咱們能預測正確460次,足足有75%!
若是此刻你在納悶,咱們要統計模型有什麼用,我不會怪你。但相信我,在此基礎上提升0.001%的準確率都是充滿挑戰性的。你是否願意接受這個挑戰?
注:對訓練集而言是75% 。在測試集上有些不一樣,但結果相近。同時,我但願這個例子能讓人明白,爲何提升0.05% 的正確率就能在Kaggle排行榜上跳升500個名次。
想了解更多請閱讀Pandas Reference (crosstab)

2.7 數據框合併(Merge DataFrame)

當咱們有收集自不一樣來源的數據時,合併數據框就變得相當重要。假設對於不一樣的房產類型,咱們有不一樣的房屋均價數據。讓咱們定義這樣一個數據框:

prop_rates = pd.DataFrame([1000, 5000, 12000], index=['Rural','Semiurban','Urban'],columns=['rates'])  

prop_rates

如今能夠把它與原始數據框合併:

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’可有可無,由於咱們只是單純計數。
想了解更多請閱讀Pandas Reference (merge)

2.8 給數據框排序(Sorting DataFrame)

Pandas能夠輕鬆基於多列排序。方法以下:

data_sorted = data.sort_values(['ApplicantIncome','CoapplicantIncome'], ascending=False)  data_sorted[['ApplicantIncome','CoapplicantIncome']].head(10)

注:Pandas 的「sort」函數如今已經不推薦使用,咱們用 「sort_values」函數代替。
想了解更多請閱讀Pandas Reference (sort_values)

2.9 繪圖(Boxplot & Histogram)

許多人可能沒意識到Pandas能夠直接繪製箱型圖和直方圖,沒必要單獨調用matplotlib。只須要一行代碼。舉例來講,若是咱們想根據貸款狀態Loan_Status來比較申請者收入ApplicantIncome:

data.boxplot(column="ApplicantIncome",by="Loan_Status")
data.hist(column="ApplicantIncome",by="Loan_Status",bins=30)

能夠看出得到/未得到貸款的人沒有明顯的收入差別,即收入不是決定性因素。
想了解更多請閱讀Pandas Reference (hist) | Pandas Reference (boxplot)

2.10 用cut函數分箱(Cut function for binning)

有時把數值彙集在一塊兒更有意義。例如,若是咱們要爲交通情況(路上的汽車數量)根據時間(分鐘數據)建模。具體的分鐘可能不重要,而時段如「上午」「下午」「傍晚」「夜間」「深夜」更有利於預測。如此建模更直觀,也能避免過分擬合。
這裏咱們定義一個簡單的、可複用的函數,輕鬆爲任意變量分箱。

#Binning:
def binning(col, cut_points, labels=None):
  #Define min and max values:
  minval = col.min()
  maxval = col.max()

  #create list by adding min and max to cut_points
  break_points = [minval] + cut_points + [maxval]

  #if no labels provided, use default labels 0 ... (n-1)
  if not labels:
    labels = range(len(cut_points)+1)

  #Binning using cut function of pandas
  colBin = pd.cut(col,bins=break_points,labels=labels,include_lowest=True)
  return colBin

#Binning age:
cut_points = [90,140,190]
labels = ["low","medium","high","very high"]
data["LoanAmount_Bin"] = binning(data["LoanAmount"], cut_points, labels)
print pd.value_counts(data["LoanAmount_Bin"], sort=False)

想了解更多請閱讀 Pandas Reference (cut)

2.11 爲分類變量編碼(Coding nominal data)

有時,咱們會面對要改動分類變量的狀況。緣由多是:

  1. 有些算法(如羅吉斯迴歸)要求全部輸入項目是數字形式。因此分類變量常被編碼爲0, 1….(n-1)
  2. 有時同一個分類變量可能會有兩種表現方式。如,溫度可能被標記爲「High」, 「Medium」, 「Low」,「H」, 「low」。這裏 「High」 和 「H」都表明同一類別。同理, 「Low」 和「low」也是同一類別。但Python會把它們看成不一樣的類別。
  3. 一些類別的頻數很是低,把它們歸爲一類是個好主意。

這裏咱們定義了一個函數,以字典的方式輸入數值,用‘replace’函數進行編碼。

#Define a generic function using Pandas replace function
def coding(col, codeDict):
  colCoded = pd.Series(col, copy=True)
  for key, value in codeDict.items():
    colCoded.replace(key, value, inplace=True)
  return colCoded
 
#Coding LoanStatus as Y=1, N=0:
print 'Before Coding:'
print pd.value_counts(data["Loan_Status"])
data["Loan_Status_Coded"] = coding(data["Loan_Status"], {'N':0,'Y':1})
print '\nAfter Coding:'
print pd.value_counts(data["Loan_Status_Coded"])

編碼先後計數不變,證實編碼成功。
想了解更多請閱讀 Pandas Reference (replace)

2.12 在一個數據框的各行循環迭代

這不是一個常見的操做。但你總不想卡在這裏吧?有時你會須要用一個for循環來處理每行。例如,一個常見的問題是變量處置不當。一般見於如下狀況:

帶數字的分類變量被當作數值。
(因爲出錯)帶文字的數值變量被當作分類變量。

因此一般來講手動定義變量類型是個好主意。如咱們檢查各列的數據類型:

#檢查當前數據類型:  
 data.dtypes

這裏能夠看到分類變量Credit_History被看成浮點數。對付這個問題的一個好辦法是建立一個包含變量名和類型的csv文件。經過這種方法,咱們能夠定義一個函數來讀取文件,併爲每列指派數據類型。舉例來講,咱們建立了csv文件datatypes.csv

#載入文件:  
 colTypes = pd.read_csv('datatypes.csv')  
 print colTypes

載入這個文件以後,咱們能對每行迭代,把用‘type’列把數據類型指派到‘feature’ 列對應的項目。

#迭代每行,指派變量類型。  
 #注,astype用來指定變量類型
for i, row in colTypes.iterrows():  #i: dataframe index; row: each row in series format
    if row['type']=="categorical":
        data[row['feature']]=data[row['feature']].astype(np.object)
    elif row['type']=="continuous":
        data[row['feature']]=data[row['feature']].astype(np.float)
print data.dtypes

如今信用記錄這一列的類型已經成了‘object’ ,這在Pandas中表明分類變量。
想了解更多請閱讀Pandas Reference (iterrows)

3 .總結

本文中咱們介紹了多個能夠幫助咱們減輕數據探索、特徵工程工做負擔的函數。此外,咱們也定義了一些函數,這些函數能夠在不一樣的數據集上覆用以得到相同效果。

原文連接:https://www.analyticsvidhya.com/blog/2016/01/12-pandas-techniques-python-data-manipulation/

相關文章
相關標籤/搜索