python科學計算四:pandas
Pandas是python的一個數據分析包,最初由AQR Capital Management於2008年4月開發,並於2009年底開源出來,目前由專注於Python資料包開發的PyData開發team繼續開發和維護,屬於PyData專案的一部分。Pandas最初被作為金融資料分析工具而開發出來,因此,pandas為時間序列分析提供了很好的支援。
Pandas的名稱來自於面板資料(panel data)和python資料分析(data analysis)。panel data是經濟學中關於多維資料集的一個術語,在Pandas中也提供了panel的資料型別。 這篇文章會介紹一些Pandas的基本知識,偷了些懶其中採用的例子大部分會來自官方的
Pandas中的資料結構
Series:一維陣列,與Numpy中的一維array類似。二者與Python基本的資料結構List也很相近,其區別是:List中的元素可以是不同的資料型別,而Array和Series中則只允許儲存相同的資料型別,這樣可以更有效的使用記憶體,提高運算效率。
Time- Series:以時間為索引的Series。
DataFrame:二維的表格型資料結構。很多功能與R中的data.frame類似。可以將DataFrame理解為Series的容器。以下的內容主要以DataFrame為主。
Panel :三維的陣列,可以理解為DataFrame的容器。
建立DataFrame
首先引入Pandas及Numpy:
Python1 2 | importpandas aspd importnumpy asnp |
官方推薦的縮寫形式為pd,你可以選擇其他任意的名稱。 DataFrame是二維的資料結構,其本質是Series的容器,因此,DataFrame可以包含一個索引以及與這些索引聯合在一起的Series,由於一個Series中的資料型別是相同的,而不同Series的資料結構可以不同。因此對於DataFrame來說,每一列的資料結構都是相同的,而不同的列之間則可以是不同的資料結構。或者以資料庫進行類比,DataFrame中的每一行是一個記錄,名稱為Index的一個元素,而每一列則為一個欄位,是這個記錄的一個屬性。 建立DataFrame有多種方式:
1、以字典的字典或Series的字典的結構構建DataFrame,這時候的最外面字典對應的是DataFrame的列,內嵌的字典及Series則是其中每個值。
Python 使用 CTRL+C 複製,使用 CTRL+V 貼上。1 2 | d={’one’:Series([1.,2.,3.],index=[’a’,’b’,’c’]),’two’:Series([1.,2.,3.,4.],index=[’a’,’b’,’c’,’d’])} df=pd.DataFrame(d) |
輸出:
可以看到d是一個字典,其中one的值為Series有3個值,而two為Series有4個值。由d構建的為一個4行2列的DataFrame。其中one只有3個值,因此d行one列為NaN(Not a Number)–Pandas預設的缺失值標記。
2、從列表的字典構建DataFrame,其中巢狀的每個列表(List)代表的是一個列,字典的名字則是列標籤。這裡要注意的是每個列表中的元素數量應該相同。否則會報錯:
Python1 | ValueError:arrays must allbe same length |
3、從字典的列表構建DataFrame,其中每個字典代表的是每條記錄(DataFrame中的一行),字典中每個值對應的是這條記錄的相關屬性。
Python1 2 3 | d=[{'one':1,'two':1},{'one':2,'two':2},{'one':3,'two':3},{'two':4}] df=pd.DataFrame(d,index=['a','b','c','d'],columns=['one','two']) df.index.name='index' |
以上的語句與以Series的字典形式建立的DataFrame相同,只是思路略有不同,一個是以列為單位構建,將所有記錄的不同屬性轉化為多個Series,行標籤冗餘,另一個是以行為單位構建,將每條記錄轉化為一個字典,列標籤冗餘。使用這種方式,如果不通過columns指定列的順序,那麼列的順序會是隨機的。
個人經驗是對於從一些已經結構化的資料轉化為DataFrame似乎前者更方便,而對於一些需要自己結構化的資料(比如解析Log檔案,特別是針對較大資料量時),似乎後者更方便。建立了DataFrame後可以通過index.name屬性為DataFrame的索引指定名稱。
檢視資料
head和tail方法可以顯示DataFrame前N條和後N條記錄,N為對應的引數,預設值為5。這通常是拿到DataFrame後的第一個命令,可以方便的瞭解資料內容和含義。
index(行)和columns(列)屬性,可以獲得DataFrame的行和列的標籤。這也是瞭解資料內容和含義的重要步驟。
decribe方法可以計算各個列的基本描述統計值。包含計數,平均數,標準差,最大值,最小值及4分位差。
行列轉置
DataFrame提供了多種排序方式。
Python1 | df.sort_index(axis=1,ascending=False) |
sort_index可以以軸的標籤進行排序。axis是指用於排序的軸,可選的值有0和1,預設為0即行標籤(Y軸),1為按照列標籤排序。 ascending是排序方式,預設為True即降序排列。
Python1 2 | df.sort(columns='two') df.sort(columns=['one','two'],ascending=[0,1]) |
DataFrame也提供按照指定列進行排序,可以僅指定一個列作為排序標準(以單獨列名作為columns的引數),也可以進行多重排序(columns的引數為一個列名的List,列名的出現順序決定排序中的優先順序),在多重排序中ascending引數也為一個List,分別與columns中的List元素對應。
讀寫資料
DataFrame可以方便的讀寫資料檔案,最常見的檔案為CSV或Excel。Pandas讀寫Excel檔案需要openpyxl(Excel 2007), xlrd/xlwt(Excel 2003)。
從CSV中讀取資料:
Python1 | df=pd.read_csv('foo.csv') |
將DataFrame寫入CSV:
Python1 | df.to_csv('foo.csv') |
從Excel中讀取資料:
Python1 2 | xls=ExcelFile('foo.xlsx') xls.parse('sheet1',index_col=None,na_values=['NA']) |
先定義一個Excel檔案,用xls.parse解析sheet1的內容,index_col用於指定index列,na_values定義缺失值的標識。
將DataFrame寫入Excel檔案:
Python1 | df.to_excel('foo.xlsx',sheet_name='sheet1') |
預設的sheet為sheet1,也可以指定其他sheet名。
資料切片
通過下標選取資料:
Python1 2 | df['one'] df.one |
以上兩個語句是等效的,都是返回df名稱為one列的資料,返回的為一個Series。
Python1 2 | df[0:3] df[0] |
下標索引選取的是DataFrame的記錄,與List相同DataFrame的下標也是從0開始,區間索引的話,為一個左閉右開的區間,即[0:3]選取的為1-3三條記錄。與此等價,還可以用起始的索引名稱和結束索引名稱選取資料:
Python1 | df['a':'b'] |
有一點需要注意的是使用起始索引名稱和結束索引名稱時,也會包含結束索引的資料。以上兩種方式返回的都是DataFrame。
使用標籤選取資料:
Python1 2 3 | df.loc[行標籤,列標籤] df.loc['a':'b']#選取ab兩行資料 df.loc[:,'one']#選取one列的資料 |
df.loc的第一個引數是行標籤,第二個引數為列標籤(可選引數,預設為所有列標籤),兩個引數既可以是列表也可以是單個字元,如果兩個引數都為列表則返回的是DataFrame,否則,則為Series。
使用位置選取資料:
Python1 2 3 4 5 6 | df.iloc[行位置,列位置] df.iloc[1,1]#選取第二行,第二列的值,返回的為單個值 df.iloc[0,2],:]#選取第一行及第三行的資料 df.iloc[0:2,:]#選取第一行到第三行(不包含)的資料 df.iloc[:,1]#選取所有記錄的第一列的值,返回的為一個Series df.iloc[1,:]#選取第一行資料,返回的為一個Series |
PS:loc為location的縮寫,iloc則為integer & location的縮寫
通過邏輯指標進行資料切片:
Python1 2 3 | df[邏輯條件] df[df.one>=2]#單個邏輯條件 df[(df.one>=1)&(df.one<3)]#多個邏輯條件組合 |
這種方式獲得的資料切片都是DataFrame。
基本運算
Pandas支援基本的運算及向量化運算。
Python1 2 3 | df.mean()#計算列的平均值,引數為軸,可選值為0或1.預設為0,即按照列運算 df.sum(1)#計算行的和 df.apply(lambdax:x.max()-x.min())#將一個函式應用到DataFrame的每一列,這裡使用的是匿名lambda函式,與R中apply函式類似 |
DataFrame的合併
Contact:
Python1 2 3 4 | ds=[{'one':4,'two':2},{'one':5,'two':3},{'one':6,'two':4},{'two':7,'three':10}] dfs=pd.DataFrame(ds,index=['e','f','g','h']) ##構建一個新的DataFrame,dfs df_t=pd.concat([df,dfs])#合併兩個DataFrame |
Merge(類似SQL中的Join操作):
Python1 2 3 4 | left=pd.DataFrame({'key':['foo1','foo2'],'lval':[1,2]}) right=pd.DataFrame({'key':['foo1','foo2'],'rval':[4,5]}) #構建了兩個DataFrame pd.merge(left,right,on='key')#按照key列將兩個DataFrame join在一起 |
DataFrame中的Group by:
Python1 2 3 | df=pd.DataFrame({'A':['foo','bar','foo','bar','foo','bar','foo','foo'],'B':['one','one','two','three','two','two','one','three'],'C':randn(8),'D':randn(8)}) df.groupby('A').sum()#按照A列的值分組求和 df.groupby(['A','B']).sum()##按照A、B兩列的值分組求和 |
構建透視表
Python1 2 | df=pd.DataFrame({'A':['one','one','two','three']*3,'B':['A','B','C']*4,'C':['foo','foo','foo','bar','bar','bar']*2,'D':np.random.randn(12),'E':np.random.randn(12)}) pd.pivot_table(df,values='D',rows=[ |