編者按:依靠完善的編程語(yǔ)言生態(tài)系統(tǒng)和更好的科學(xué)計(jì)算庫(kù),如今Python幾乎已經(jīng)成了數(shù)據(jù)科學(xué)家的首選語(yǔ)言。如果你正開(kāi)始學(xué)習(xí)Python,而且目標(biāo)是數(shù)據(jù)分析,相信NumPy、SciPy、Pandas會(huì)是你進(jìn)階路上的必備法寶。尤其是對(duì)數(shù)學(xué)專(zhuān)業(yè)的人來(lái)說(shuō),Pandas可以作為一個(gè)首選的數(shù)據(jù)分析切入點(diǎn)。
本文將介紹12種用于數(shù)據(jù)分析的Pandas技巧,為了更好地描述它們的效果,這里我們用一個(gè)數(shù)據(jù)集輔助進(jìn)行操作。
數(shù)據(jù)集:我們研究的主題是貸款預(yù)測(cè),請(qǐng)到datahack.analyticsvidhya.com/contest/practice-problem-loan-prediction下載數(shù)據(jù)(需注冊(cè)),并開(kāi)始學(xué)習(xí)之旅。
預(yù)備!開(kāi)始!
首先,我們先導(dǎo)入模塊,并將數(shù)據(jù)集加載到Python環(huán)境中:
import pandas as pd
import numpy as np
data = pd.read_csv("train.csv", index_col="Loan_ID")
1. Boolean Indexing
在表格中,如果你想根據(jù)另一列的條件篩選當(dāng)前列的值,你會(huì)怎么做?舉個(gè)例子,假設(shè)我們想要一份所有未畢業(yè)但已經(jīng)辦理了貸款的女性清單,具體的操作是什么?在這種情況下,Boolean Indexing,也就是布爾索引能提供相應(yīng)的功能。我們只需這樣做:
data.loc[(data["Gender"]=="Female") & (data["Education"]=="Not Graduate") & (data["Loan_Status"]=="Y"), ["Gender","Education","Loan_Status"]]

2. Apply Function
Apply函數(shù)是使用數(shù)據(jù)和創(chuàng)建新變量的常用函數(shù)之一。在對(duì)DataFrame的特定行/列應(yīng)用一些函數(shù)后,它會(huì)返回相應(yīng)的值。這些函數(shù)既可以是默認(rèn)的,也可以是用戶自定義的。如這里我們就定義了一個(gè)查找每行/列中缺失值的函數(shù):
#Create a new function:
def num_missing(x):
return sum(x.isnull())
#Applying per column:
print"Missing values per column:"
print data.apply(num_missing, axis=0) #axis=0 defines that function is to be applied on each column
#Applying per row:
print" Missing values per row:"
print data.apply(num_missing, axis=1).head() #axis=1 defines that function is to be applied on each row

我們得到了預(yù)期的結(jié)果。需要注意的一點(diǎn)是,這里head() 函數(shù)只作用于第二個(gè)輸出,因?yàn)樗嘈袛?shù)據(jù)。
3. 替換缺失值
對(duì)于替換缺失值,fillna()可以一步到位。它會(huì)用目標(biāo)列的平均值/眾數(shù)/中位數(shù)更新缺失值,以此達(dá)到目的。在這個(gè)示例中,讓我們用眾數(shù)分別更新Gender、Married、Self_Employed這幾列的缺失值:
#First we import a function to determine the mode
from scipy.stats import mode
mode(data['Gender'])
輸出:
ModeResult(mode=array([‘Male’], dtype=object), count=array([489]))
我們得到了眾數(shù)及其出現(xiàn)的次數(shù)。記住很多時(shí)候眾數(shù)會(huì)是一個(gè)數(shù)組,因?yàn)榭赡軘?shù)據(jù)中存在多個(gè)高頻詞,默認(rèn)情況下,我們會(huì)選擇第一個(gè):
mode(data['Gender']).mode[0]
*‘Male’
現(xiàn)在我們就能更新缺失值,并檢測(cè)自己對(duì)Apply函數(shù)的掌握情況:
#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:
print data.apply(num_missing, axis=0)

從結(jié)果上看,缺失值的確被補(bǔ)上了,但這只是最原始的形式,在現(xiàn)實(shí)工作中,我們還要掌握更復(fù)雜的方法,如分組使用平均值/眾數(shù)/中位數(shù)、對(duì)缺失值進(jìn)行建模等。
4. Pivot Table
Pandas可以用來(lái)創(chuàng)建MS Excel樣式數(shù)據(jù)透視表(Pivot Table)。在本文的例子中,數(shù)據(jù)的關(guān)鍵列是含有缺失值的“LoanAmount”。為了獲得具體的貸款額度數(shù)字,我們可以用Gender、Married、Self_Employed這幾列的貸款情況進(jìn)行估算:
#Determine pivot table
impute_grps = data.pivot_table(values=["LoanAmount"], index=["Gender","Married","Self_Employed"], aggfunc=np.mean)
print impute_grps

5. Multi-Indexing
如果你仔細(xì)觀察了“替換缺失值”那一節(jié)的輸出,你可能會(huì)發(fā)現(xiàn)一個(gè)奇怪的現(xiàn)象,就是每個(gè)索引都由3個(gè)值組合而成。這被稱(chēng)為多重索引(Multi-Indexing),它有助于操作的快速執(zhí)行。
讓我們接著這個(gè)例子,假設(shè)現(xiàn)在我們有各列的值,但還沒(méi)有進(jìn)行缺失值估算。這時(shí)就要用到之前的各種技巧:
#iterate only through rows with missing LoanAmount
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]
#Now check the #missing values again to confirm:
print data.apply(num_missing, axis=0)

注:
多索引需要元組來(lái)定義loc語(yǔ)句中的索引組。這是一個(gè)在函數(shù)中要用到的元組。
values [0]的后綴是必需的,因?yàn)槟J(rèn)情況下返回的值與DataFrame的值不匹配。在這種情況下,直接分配會(huì)出現(xiàn)錯(cuò)誤。
6. Crosstab
這個(gè)函數(shù)可以被用來(lái)塑造對(duì)數(shù)據(jù)的初始“感覺(jué)(概覽)”,通俗地講,就是我們可以驗(yàn)證一些基本假設(shè),如在貸款案例中,“Credit_History”會(huì)影響個(gè)人貸款成功與否。這可以用交叉表(Crosstab)測(cè)試,如下所示:
pd.crosstab(data["Credit_History"],data["Loan_Status"],margins=True)

如果說(shuō)數(shù)值還不夠直觀,我們可以用apply函數(shù)把它轉(zhuǎn)換成百分比:
def percConvert(ser):
return ser/float(ser[-1])
pd.crosstab(data["Credit_History"],data["Loan_Status"],margins=True).apply(percConvert, axis=1)

顯然,有“CreditHistory”的人獲得貸款的機(jī)會(huì)更大,有80%以上的概率,而沒(méi)有“CreditHistory”的人獲得貸款的概率只有可憐的9%。
但是這就是個(gè)簡(jiǎn)單的預(yù)測(cè)結(jié)果嗎?不是的,這里包含著一個(gè)有趣的故事。已知有CreditHistory”的人獲得貸款的概率更高,那我們大可以設(shè)他們的“LoanStatus”為Y,其他人的為N,這樣一個(gè)模型的預(yù)測(cè)結(jié)果會(huì)是什么樣的?我們進(jìn)行了614次測(cè)試,而它的正確預(yù)測(cè)次數(shù)是82+378=460,75%的準(zhǔn)確率!
也許你會(huì)吐槽這么個(gè)問(wèn)題為什么要扯到統(tǒng)計(jì)模型。我不否認(rèn),但我只想說(shuō)明一點(diǎn),就是如果你能把這個(gè)模型的準(zhǔn)確率再提升哪怕0.001%,這都是個(gè)巨大的突破。
注:這里的75%是個(gè)大概的值,具體數(shù)字在訓(xùn)練集和測(cè)試集上有所不同。我希望這能直觀地解釋為什么在Kaggle這樣的比賽中,0.05%的準(zhǔn)確率提升能帶來(lái)500名以上的排名提升。
7. 合并DataFrame
當(dāng)我們需要將來(lái)自不同來(lái)源的信息進(jìn)行整合時(shí),合并DataFrame(或者你們愛(ài)說(shuō)數(shù)據(jù)框)就變得很重要了。現(xiàn)在房?jī)r(jià)很熱,炒房團(tuán)也很熱,所以我們先用數(shù)據(jù)集的數(shù)據(jù)假設(shè)一份各地區(qū)房屋均價(jià)(1平)不同的表:
prop_rates = pd.DataFrame([1000,5000,12000],index = ['Rural','Semiurban','Urban'],columns = ['rates'])
prop_rates

現(xiàn)在我們可以將這些信息與原始DataFrame合并為:
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)

反正買(mǎi)不起,好了,數(shù)據(jù)合并成功了。請(qǐng)注意,'values'參數(shù)在這里是沒(méi)什么用的,因?yàn)槲覀冎皇亲鲇?jì)數(shù)。
8. DataFrame排序
Pandas可以輕松基于多列進(jìn)行排序,如下所示
data_sorted = data.sort_values(['ApplicantIncome','CoapplicantIncome'], ascending=False)
data_sorted[['ApplicantIncome','CoapplicantIncome']].head(10)

注:Pandas的sort函數(shù)已經(jīng)不能用了,現(xiàn)在排序要調(diào)用sort_value。
9. 繪圖(Boxplot和直方圖)
很多人可能不知道自己能直接在Pandas里繪制盒形圖和直方圖,無(wú)需單獨(dú)調(diào)用matplotlib,一行命令就能搞定。例如,如果我們想比較Loan_Status的ApplicantIncome的分布情況:
import matplotlib.pyplot as plt
%matplotlib inline
data.boxplot(column="ApplicantIncome",by="Loan_Status")

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

這兩幅圖表明收入在貸款過(guò)程中所占的比重并沒(méi)有我們想象中那么高,無(wú)論是被拒的還是收到貸款的,他們的收入沒(méi)有非常明顯的區(qū)別。
10. Cut function for binning
有時(shí)候聚類(lèi)后的數(shù)據(jù)會(huì)更有意義。以今天最近車(chē)禍頻發(fā)的自動(dòng)駕駛汽車(chē)為例,如果我們要用它捕獲的數(shù)據(jù)重現(xiàn)某條路上的交通情況,比起一整天的流暢數(shù)據(jù),或是把一天均勻分割為24個(gè)小時(shí),“早上”“下午”“晚上”“夜晚”“深夜”這幾個(gè)關(guān)鍵時(shí)段的數(shù)據(jù)包含的信息量更多,也更有效。如果我們用這些數(shù)據(jù)建模,它的成果會(huì)更直觀,而且可以避免過(guò)擬合。
這里我們定義一個(gè)簡(jiǎn)單的函數(shù),它可以高效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)
ifnot 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)

11. 為nominal數(shù)據(jù)編碼
有時(shí)候我們需要對(duì)稱(chēng)名數(shù)據(jù)(nominal數(shù)據(jù))重新分類(lèi),這可能是由于各種原因造成的:
一些算法(如Logistic回歸)要求所有輸入都是數(shù)字,所以我們要把稱(chēng)名變量重新編碼為0,1 ...(n-1)。
有時(shí)一個(gè)類(lèi)別可能包含多種表達(dá),如“溫度”可以被記錄為“High”“Medium”“Low”“H”“l(fā)ow”,其中“High”和“H”是一碼事,“Low”和“l(fā)ow”也是一碼事,但Python會(huì)認(rèn)為它們是不同的。
有些類(lèi)別的頻數(shù)非常低,所以我們應(yīng)該把它們合并起來(lái)。
為了解決這個(gè)問(wèn)題,這里我們定義了一個(gè)簡(jiǎn)單的函數(shù),它把輸入作為“字典”,然后調(diào)用Pandas的replace函數(shù)重新編碼:
#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' After Coding:'
print pd.value_counts(data["Loan_Status_Coded"])

12. 迭代dataframe的行
這不是一個(gè)常用的技巧,但如果遇到這種問(wèn)題,相信沒(méi)人想到時(shí)候再絞盡腦汁想辦法,或者直接自暴自棄用for循環(huán)遍歷所有行。這里我們舉兩個(gè)要用到這種方法的場(chǎng)景:
當(dāng)帶有數(shù)字的nominal variable被當(dāng)成數(shù)字。
當(dāng)某一行帶有字符(因?yàn)閿?shù)據(jù)錯(cuò)誤)的Numeric variable被當(dāng)成分類(lèi)。
這時(shí)我們就要手動(dòng)定義列的類(lèi)別。雖然很麻煩,但這之后如果我們?cè)贆z查數(shù)據(jù)類(lèi)別:
#Check current type:
data.dtypes
它的輸出會(huì)是:

這里我們看到Credit_History是一個(gè)稱(chēng)名變量,但是它卻顯示為float。解決這些問(wèn)題的一個(gè)好方法是創(chuàng)建一個(gè)包含列名和類(lèi)型的csv文件,有了它,我們就可以創(chuàng)建一個(gè)函數(shù)來(lái)讀取文件并分配列數(shù)據(jù)類(lèi)型。
#Load the file:
colTypes = pd.read_csv('datatypes.csv')
print colTypes

加載這個(gè)文件后,我們可以遍歷每一行,并使用'type'列將數(shù)據(jù)類(lèi)型賦值給'feature'列中定義的變量名稱(chēng)。
#Iterate through each row and assign variable type.
#Note: astype is used to assign types
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

希望本文對(duì)你有用!
-
函數(shù)
+關(guān)注
關(guān)注
3文章
4413瀏覽量
67201 -
數(shù)據(jù)分析
+關(guān)注
關(guān)注
2文章
1512瀏覽量
36062 -
python
+關(guān)注
關(guān)注
57文章
4866瀏覽量
89801
原文標(biāo)題:12種用于Python數(shù)據(jù)分析的Pandas技巧
文章出處:【微信號(hào):jqr_AI,微信公眾號(hào):論智】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
python數(shù)據(jù)分析的類(lèi)庫(kù)
怎么有效學(xué)習(xí)Python數(shù)據(jù)分析?
pandas對(duì)babynames數(shù)據(jù)集的簡(jiǎn)單處理
python 數(shù)據(jù)分析基礎(chǔ) day12-python調(diào)用mysql
成為Python數(shù)據(jù)分析師,需要掌握哪些技能
成為Python數(shù)據(jù)分析師,需要掌握哪些技能
pandas是什么?
機(jī)器學(xué)習(xí)開(kāi)發(fā)課程,使用Pandas探索數(shù)據(jù)分析
解讀12 種 Numpy 和 Pandas 高效函數(shù)技巧
Python Pandas如何來(lái)管理結(jié)構(gòu)化數(shù)據(jù)
python機(jī)器學(xué)習(xí)概述
Pandas:Python中最好的數(shù)據(jù)分析工具
12種用于數(shù)據(jù)分析的Pandas技巧可用來(lái)學(xué)習(xí)Python詳細(xì)概述
評(píng)論