IO Tools (Text, CSV, HDF5, ...)¶
The pandas I/O API is a set of top level reader functions accessed like pd.read_csv() that generally return a pandasobject.
- read_csv
- read_excel
- read_hdf
- read_sql
- read_json
- read_msgpack (experimental)
- read_html
- read_gbq (experimental)
- read_stata
- read_sas
- read_clipboard
- read_pickle
The corresponding writer functions are object methods that are accessed like df.to_csv()
Here is an informal performance comparison for some of these IO methods.
Note
For examples that use the StringIO class, make sure you import it according to your Python version, i.e.from StringIO import StringIO for Python 2 and from io import StringIO for Python 3.
pandas.read_csv參數詳解
- boolean. True -> 解析索引
- list of ints or names. e.g. If [1, 2, 3] -> 解析1,2,3列的值作為獨立的日期列;
- list of lists. e.g. If [[1, 3]] -> 合並1,3列作為一個日期列使用
- dict, e.g. {‘foo’ : [1, 3]} -> 將1,3列合並,並給合並后的列起名為"foo"
導語
Python正迅速成為數據科學家偏愛的語言,這合情合理。它擁有作為一種編程語言廣闊的生態環境以及眾多優秀的科學計算庫。如果你剛開始學習Python,可以先了解一下Python的學習路線。
在眾多的科學計算庫中,我認為Pandas對數據科學運算最有用。Pandas,加上Scikit-learn幾乎能構成了數據科學家所需的全部工具。本文旨在提供Python數據處理的12種方法。文中也分享了一些會讓你的工作更加便捷的小技巧。
在繼續推進之前,我推薦讀者閱覽一些關於數據探索 (data exploration)的代碼。
為了幫助理解,本文用一個具體的數據集進行運算和操作。本文使用了貸款預測(loan prediction) 問題數據集,下載數據集請到http://datahack.analyticsvidhya.com/contest/practice-problem-loan-prediction。
開始工作
首先我要導入要用的模塊,並把數據集載入Python環境。
import pandas as pd import numpy as np data = pd.read_csv("train.csv", index_col="Loan_ID")
1.布爾索引(Boolean Indexing)
如何你想用基於某些列的條件篩選另一列的值,你會怎么做?例如,我們想要一個全部無大學學歷但有貸款的女性列表。這里可以使用布爾索引。代碼如下:
data.loc[(data["Gender"]=="Female") & (data["Education"]=="Not
Graduate") & (data["Loan_Status"]=="Y"),
["Gender","Education","Loan_Status"]]
想了解更多請閱讀 Pandas Selecting and Indexing
2.Apply函數
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)
4.透視表
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)
5.多重索引
你可能注意到上一步驟的輸出有個奇怪的性質。每個索引都是由三個值組合而成。這叫做多重索引。它可以幫助運算快速進行。
延續上面的例子,現在我們有了每個分組的值,但還沒有替換。這個任務可以用現在學過的多個技巧共同完成。
#只在帶有缺失值的行中迭代: 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]后綴。因為默認情況下元素返回的順序與原數據庫不匹配。在這種情況下,直接指派會返回錯誤。
6. 二維表
這個功能可被用來獲取關於數據的初始“印象”(觀察)。這里我們可以驗證一些基本假設。例如,本例中“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)
用 Python 做數據處理必看:12 個使效率倍增的 Pandas 技巧(上)《用 Python 做數據處理必看:12 個使效率倍增的 Pandas 技巧》
7 – 數據框合並
當我們有收集自不同來源的數據時,合並數據框就變得至關重要。假設對於不同的房產類型,我們有不同的房屋均價數據。讓我們定義這樣一個數據框:
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)
8 – 給數據框排序
Pandas可以輕松基於多列排序。方法如下:
data_sorted = data.sort_values(['ApplicantIncome','CoapplicantIncome'],
ascending=False)
data_sorted[['ApplicantIncome','CoapplicantIncome']].head(10)

注:Pandas 的“sort”函數現在已經不推薦使用,我們用 “sort_values”函數代替。
想了解更多請閱讀Pandas Reference (sort_values)
9 – 繪圖(箱型圖&直方圖)
許多人可能沒意識到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)
10 – 用Cut函數分箱
有時把數值聚集在一起更有意義。例如,如果我們要為交通狀況(路上的汽車數量)根據時間(分鍾數據)建模。具體的分鍾可能不重要,而時段如“上午”“下午”“傍晚”“夜間”“深夜”更有利於預測。如此建模更直觀,也能避免過度擬合。
這里我們定義一個簡單的、可復用的函數,輕松為任意變量分箱。
#分箱: def binning(col, cut_points, labels=None): #Define min and max
values: minval = col.min() maxval = col.max()
#利用最大值和最小值創建分箱點的列表 break_points = [minval] + cut_points + [maxval]
#如果沒有標簽,則使用默認標簽0 ... (n-1) if not labels: labels =
range(len(cut_points)+1) #使用pandas的cut功能分箱 colBin =
pd.cut(col,bins=break_points,labels=labels,include_lowest=True)
return colBin #為年齡分箱: 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)
11 – 為分類變量編碼
有時,我們會面對要改動分類變量的情況。原因可能是:
有些算法(如羅吉斯回歸)要求所有輸入項目是數字形式。所以分類變量常被編碼為0, 1….(n-1)
有時同一個分類變量可能會有兩種表現方式。如,溫度可能被標記為“High”, “Medium”, “Low”,“H”, “low”。這里 “High” 和 “H”都代表同一類別。同理, “Low” 和“low”也是同一類別。但Python會把它們當作不同的類別。
一些類別的頻數非常低,把它們歸為一類是個好主意。
這里我們定義了一個函數,以字典的方式輸入數值,用‘replace’函數進行編碼。
#使用Pandas replace函數定義新函數: def coding(col, codeDict): colCoded =
pd.Series(col, copy=True) for key, value in codeDict.items():
colCoded.replace(key, value, inplace=True) return colCoded
#把貸款狀態LoanStatus編碼為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)
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索引; row: 連續的每行 if row['feature']=="categorical":
data[row['feature']]=data[row['feature']].astype(np.object) elif
row['feature']=="continuous":
data[row['feature']]=data[row['feature']].astype(np.float) print
data.dtypes
現在信用記錄這一列的類型已經成了‘object’ ,這在Pandas中代表分類變量。
想了解更多請閱讀Pandas Reference (iterrows)
結語
本文中我們介紹了多個可以幫助我們減輕數據探索、特征工程工作負擔的函數。此外,我們也定義了一些函數,這些函數可以在不同的數據集上復用以獲得相同效果。
