Pandas的DataFrame和Series及其操作
一、Pandas資料結構介紹
Series:
Series是一種類似於一維陣列的物件,是由一組資料以及一組與之相關聯的標籤(即索引)組成的,具體的表現形式就是索引在左邊,值在右邊。
import pandas as pd
import numpy as np
1.建立Series
a.通過列表建立Series:
直接建立Series,索引的值是預設的自動建立一個0到N-1的整數索引:
obj = pd.Series([4,7,-5,3])
建立Series並且為其設定索引:
obj2 = pd.Series([4,7,-5,3], index=['d','b','a','c'])
b.通過字典建立Series:
如果只傳入一個字典,則結果Series中的索引就是原字典的鍵,而且是按鍵值有序排列:
sdata = {'Ohio':35000,'Texas':71000,'Oregon':16000,'Utah':5000}
obj3 = pd.Series(sdata)
用字典建立Series時,同時為Series設定index屬性,結果Series的索引以index的引數值為準,若存在索引沒有對應值的情況,則結果就是NaN:
在這個例子裡sdata中和索引states相匹配的那三個值會被找出來放到相應的位置上,但是'Carlifornia'所對應的sdata值找不到,其結果只能是NaNsdata = {'Ohio':35000,'Texas':71000,'Oregon':16000,'Utah':5000} states = ['California','Ohio','Oregon','Texas'] obj3 = pd.Series(sdata, index=states)
2.Series的基本屬性、函式:
a.通過Series的values和index屬性獲取其陣列表示形式和索引物件:
obj = pd.Series([4,7,-5,3])
obj.values
obj.index
b.通過pandas的isnull()函式,notnull()函式以及Series的isnull()例項方法檢測缺失資料:
pd.isnull(obj4) pd.notnull(obj4) obj4.isnull()
c.Series的name屬性和Series索引的name屬性:
obj4.name='population'
obj4.index.name='state'
DataFrame:
DataFrame是一個表型的資料結構,它含有一組有序的列,每列間可以是不同的資料型別(數值,字串,布林值等)。DataFrame既有行索引又有列索引,其中的資料是以一個或多個二維塊存放的,而不是列表,字典或別的一維資料結構。雖然它是個二維的結構,但是DataFrame任然可以表示更高維的資料(利用層次化索引的表結構)。
1.建立DataFrame:
a.由等長的列表或Numpy陣列組成的字典建立DataFrame:
data = {'state':['Ohio','Ohio','Ohio','Nevada','Nevada'],
'year':[2000,,2001,2002,2001,2002],
'pop':[1.5,1.7,3.6,2.4,2.9]}
frame = pd.DataFrame(data)
由等長的列表或Numpy陣列組成的字典建立DataFrame,同時指定列順序:
data = {'state':['Ohio','Ohio','Ohio','Nevada','Nevada'],
'year':[2000,2001,2002,2001,2002],
'pop':[1.5,1.7,3.6,2.4,2.9]}
frame = pd.DataFrame(data,columns=['year','state','pop'])
和Series一樣,如果傳入index的引數在資料中找不到對應值,就會產生NaN:
frame2 = pd.DataFrame(data,columns=['years','state','pop','dept'],index=['one','two','three','four','five'])
通過巢狀字典建立DataFrame:
如果將巢狀字典傳遞DataFrame,外層字典的鍵作為列,內層鍵則作為行索引:
pop = {'Nevada':{2001:2.4,2002:2.9},
'Ohio':{2000:1.5,2001:1.7,2002:3.6}}
frame3 = pd.DataFrame(pop)
2.DataFrame的列操作:
DataFrame的列獲取為一個Series:
frame2['state']
frame2.year
列可以通過賦值的方式進行修改:
將數值賦值給DataFrame的一列時,整個一列都是該數值;將列表或陣列賦值給DataFrame的一列時,要求其長度和DataFrame的長度相等;將一個Series賦值給DataFrame的一列,會精確的將Series和DataFrame的匹配並進行賦值,所有空位上都是缺失值:
frame2['debt'] = 16.5
frame2['debt'] = np.arange(5)
val = pd.Series([-1.2,-1.5,-1.7], index=['two','four','five'])
frame2['debt'] = val
刪除DataFrame的一行:
通過關鍵字del刪除列:
2.DataFrame的基本屬性、函式:
a.DataFrame的index屬性、columns屬性:
print(frame2.index)
print(frame2.columns)
b.DataFrame的index的name屬性、DataFrame的columns的name屬性:
frame3.index.name = 'year'
frame3.columns.name = 'state'
c.DataFrame的values屬性:
frame3.values
索引物件:
pandas的索引物件負責管理軸標籤和其他元資料(比如軸名稱等)。index物件是不可修改的,所以使用者是不能通過賦值的形式對索引進行修改。
獲得index物件:
obj = pd.Series(range(3),index=['a','b','c'])
index = obj.index
下表列出了index物件的一些方法和屬性:
二、基本功能:
重新索引:
pandas物件的用reindex()方法建立一個適應新索引的新物件,該方法會根據新索引進行重排,如果某個索引值當前不存在,就引入缺失值。reindex方法的引數如下表所示:
例1:
obj = pd.Series([4.5,7.2,-5.3,3.6], index=['d','b','a','c'])
obj2 = obj.reindex(['a','b','c','d','e'])
例2:
obj.reindex(['a','b','c','d','e'], fill_value=0)
例3:
obj3 = pd.Series(['blue','purple','yellow'],index=[0,2,4])
obj3.reindex(range(6), method='ffill')
例4:
frame = pd.DataFrame(np.arange(9).reshape((3,3)), index=['a','c','d'],columns=['Ohio','Texas','California'])
frame2 = frame.reindex(['a','b','c','d'])
例5:
states = ['Texas','Utah','California']
frame.reindex(columns=states)
這個是使用columns關鍵字按列進行重新索引:
例6:
frame.reindex(index=['a','b','c','d'],method='ffill',columns=states)
同時按行、列進行重新索引,但是插值只能按行應用:
丟棄指定軸上的項:
通過使用drop()函式可以丟棄某個軸上一個或多個項,drop()函式會返回一個在指定軸上刪除了指定值的新物件:
例1:
obj = pd.Series(np.arange(5), index=['a','b','c','d','e'])
new_obj = obj.drop('c')
obj.drop(['d','c'])
例2:
data = pd.DataFrame(np.arange(16).reshape((4,4)), index=['Ohio','Colorado','Utah','New York'],
columns=['one','two','three','four'])
data.drop(['Colorado','Ohio'])
data.drop('two',axis=1)
data.drop(['two','four'],axis=1)
索引、選取和過濾:
Series索引的工作方式類似於Numpy的陣列索引,只不過Series的索引值不只是整數。
特別要注意的是,利用標籤的切片運算與普通的python切片運算不同,其末端是包含的:
在算術方法中填充值:
在對不同索引的物件進行算術運算時,你可以希望當一個物件中某個軸標籤在另一個物件中找不到時填充一個特殊值(比如0),這時候就要呼叫Series物件或者DataFrame物件的算術方法:
例1:
df1 = pd.DataFrame(np.arange(12).reshape((3,4)),columns=list('abcd'))
df2 = pd.DataFrame(np.arange(20).reshape((4,5)),columns=list('abcde'))
df1+df2
將它們相加時,沒有重疊的位置就會產生NaN:
但是在使用df1的add()函式,傳入df2以及一個fill_value引數,fill_value引數就是相當於在沒對齊的位置上要填的值:
DataFrame和Series之間的運算:
在預設情況下,DataFrame和Series之間進行算術運算會將Series的索引匹配到DataFrame的列,然後行一直向下廣播:
frame = pd.DataFrame(np.arange(12).reshape((4,3)),columns=list('bde'),index=['Utah','Ohio','Texas','Oregon'])
series = frame.ix[0]
frame - series
如果某個索引值在DataFrame的列或Series的索引中找不到,則參與運算的兩個物件就會被重新索引形成並集:
series2 = pd.Series(range(3), index=['b','e','f'])
frame+series2
函式應用和對映:
Numpy的ufuncs(元素級陣列方法)也可以用於操作pandas物件:
frame = pd.DataFrame(np.random.randn(4,3),columns=list('bde'),index=['Utah','Ohio','Texas','Oregon'])
frame
np.abs(frame)
將函式應用到各列或各行所形成的一維陣列上,通過DataFrame的apply()方法實現:
例1:
f = lambda x: x.max() - x.min()
frame.apply(f)
frame.apply(f,axis=1)
例2:
def f(x):
return pd.Series([x.min(),x.max()],index=['min','max'])
frame.apply(f)
如果想使函式作用於DataFrame的元素,則使用applymap()函式,對於Series則要使用map()函式:
排序和排名:
根據條件對資料集排序(sorting)也是一種重要的操作,使用sort_index()函式可以對行或列進行排序(按字典順序),返回一個已排好序的新物件:
obj = pd.Series(range(4), index=['d','a','b','c'])
obj.sort_index()
frame = pd.DataFrame(np.arange(8).reshape((2,4)), index=['three','one'].columns=['d','a','b','c'])
frame.sort_index()
frame.sort_index(axis=1)
資料預設是按升序排列的,但也可以設定為降序:
frame.sort_index(axis=1,ascending=True)
若想按值對Series進行排序,可以使用其order()函式,缺失值會被放在末尾:
obj = pd.Series([4,7,-3,2])
在DataFrame上,若想根據一個或多個列中的值進行排序要使用其sort_values()函式,還需要將那些列名傳遞給by選項來達到目的:
frame = pd.Series({'b':[4,7,-3,2],'a':[0,1,0,1]})
frame.sort_values(by='b')
frame.sort_values(by=['a','b'])
排名(ranking)和排序關係密切但是卻又不相同,使用rank()函式可以得到其排名,通過幾個例子來看它們間的不同點:
例1:
obj = pd.Series([7,-5,7,4,2,0,4])
obj.rank()
例2:
frame = pd.DataFrame({'b':[4.3,7,-3,2],
'a':[0,1,0,1],
'c':[-2,5,8,-2.5]})
frame.rank(axis=1)
三、彙總和計算描述統計:
基本統計資訊:
pandas物件擁有一組常用的數學統計方法,它們大部分都是簡約和彙總統計。下表展示了一些描述和彙總統計的方法:
具體地,我們通過幾個例子來檢視這些函式的用法:
例1:使用sum()函式按行或列進行求和
df = pd.DataFrame([[1.4,np.nan],[7.1,-4.5],[np.nan,np.nan],[0.75,-1.3]],index=['a','b','c','d'],columns=['one','two'])
df.sum()
df.sum(axis=1)
例2:想要讓列或行的NaN值參與運算,要在sum()函式、mean()函式等中將skipna引數設定為False:
df.mean(axis=1,skipna=False)
例3:使用idxmax()函式、idxmin()函式獲得DataFrame中每一列的最大值、最小值的索引:
df.idxmax()
df.idxmin()
例4:使用cumsum()函式獲得每行或每列的累加和
例5:使用describe()函式,一次性產生多個基於列的彙總統計:對於數值型的資料會生成平均值、最大值、最小值等等資訊;對於非數值型的資料,會給出一些出現次數之類的統計資訊:
相關係數和協方差:
有些彙總統計如協方差和相關係數是通過引數對計算出來的。Series的corr()函式用於計算兩個Series中重疊的、非NA的、按索引對齊的值的相關係數,類似地cov用於計算協方差:
returns.MSFT.corr(returns.IBM)
returns.MSFT.cov(returns.IBM)
DataFrame的corr()函式、cov()函式將以DataFrame的形式返回完整的相關係數或協方差矩陣:
returns.corr()
returns.cov()
利用DataFrame的corrwith()函式可以計算其列或行和另一個Series或DataFrame間的相關係數:
returns.corrwith(returns.IBM)
唯一值、值計數以及成員資格:
用於對唯一值、值計數、成員資格的函式如下圖所示:
例1:利用unique()函式,獲得Series的唯一值:
obj = pd.Series(['c','a','d','a','a','b','b','c','c'])
uniques = obj.unique()
例2:利用value_counts計算出Series中各個值的出現頻率:
obj.value_counts()
pd.value_counts(obj.values,sort=False)
例3:使用isin()函式來判斷向量化集合的成員資格:
mask = obj.isin(['b','c'])
obj[mask]
例4:統計DataFrame裡的值在每一列出現的次數:
data = pd.DataFrame('Qu1':[1,3,4,3,4],'Qu2':[2,3,1,2,3],'Qu3':[1,5,2,4,4])
result = data.apply(pd.value_counts).fillna(0)
四、處理缺失資料:
基本處理方法:
缺失資料(missing data)在大部分的資料分析應用中都很常見,pandas的設計目標之一就是讓缺失資料的處理任務儘量輕鬆。pandas使用浮點數NaN(Not a Number)表示浮點和非浮點陣列中的缺失值,它只是一個便於被檢測出來的標記而已。下表展示NaN的處理方法:
濾除缺失資訊:
過濾缺失資料可以通過使用Series物件或DataFrame物件的dropna()函式實現。
例1:對於Series來說,dropna()會返回一個僅含非空資料和索引值的Series:
data = pd.Series([1,np.nan,3.5,np.nan,7])
data.dropna()
也可以通過布林索引達到這個目的:
data[data.notnull()]
例2:對於DataFrame來說,dropna()預設丟棄任何含有缺失值的行:
data = np.DataFrame([[1,6.5,3],[1,np.nan,np.nan],[np.nan,np.nan,np.nan],[np.nan,6.5,3]])
cleaned = data.dropna()
若再給dropna()傳入引數how='all'會只丟棄全為NaN的那些行:
data.dropna(how='all')
通過將設定引數axis=1可以丟棄列中的缺失資料
例2:通過設定引數thresh可以留下一部分缺失資料,thresh表示每行中非NaN值的個數,比如thresh=2表示保留那些非NaN值個數大於等於2的那些行
df = pd.DataFrame(np.random.randn(7,3))
df.iloc[:4,1] = np.nan
df.iloc[:2,2] = np.nan
df.dropna(thresh=2)
填充缺失資訊:
通過fillna()函式能解決將缺失值替換為常數值的操作,fillna()預設會返回新物件,但是可以通過設定引數inplace=True,可以對現有物件進行修改。
例1:將所有NaN值替換為0
df = pd.DataFrame(np.random.randn(7,3))
df.iloc[:4,1] = np.nan
df.iloc[:2,2] = np.nan
df.fillna(0)
例2:若是通過一個字典呼叫fillna(),就可以實現對不同的列用不同值進行填充:
df.fillna({1:0.5,3:-1})
例3:通過設定引數limit=2可以設定連續填充最大數量
df.fillna(method='ffill',limit=2)
五、層次化索引:
基本層次化索引:
層次化索引(hierarchical indexing)是pandas的一項重要功能,它使你能在一個軸上擁有多個索引級別,抽象點說,它使你以低緯度形式處理高緯度資料。 例1:建立一個Series,並用一個由列表或陣列組成的列表作為索引:
data = pd.Series(np.random.randn(10),index=[['a','a','a','b','b','b','c','c','d','d'],[1,2,3,1,2,3,1,2,2,3]])
data.index
例2:具有層次化索引的Series能通過unstack()函式轉成一個DataFrame:
data.unstack()
例3:建立一個具有層次化索引的DataFrame:
frame = pd.DataFrame(np.arange(12).reshape((4,3)),index=[['a','a','b','b'],[1,2,1,2]],columns=[['Ohio','Ohio','Colorado'],['Green','Red','Green']])
frame.index.names = ['key1','key2']
frame.columns.names = ['state','color']
重排分級順序:
有時候要重新調整某條軸上各級別的順序,或根據指定級別上的值對資料進行排序,使用swaplevel()函式能完成這個功能,並返回一個互換了級別的新物件。
例1:
frame = pd.DataFrame(np.arange(12).reshape((4,3)),index=[['a','a','b','b'],[1,2,1,2]],columns=[['Ohio','Ohio','Colorado'],['Green','Red','Green']])
frame.index.names = ['key1','key2']
frame.columns.names = ['state','color']
frame.swaplevel('key1','key2')
例2:利用sort_index()函式能根據索引的值進行排序,引數level表示排序依據的索引名:
frame.sort_index(level='key1')
frame.sort_index(level='key2')
根據級別彙總統計:
對於具有層次化索引的DataFrame和Series來說,其描述和彙總統計都有一個level引數,它用於指定在某條軸上進資料操作:
例1:根據索引名為key2進行sum()函式操作:
frame.sum(level='key2')
例2:根據列名為color進行sum()操作:
frame.sum(level='color',axis=1)
使用DataFrame的列:
通常在使用DataFrame時,人們想要把一個或者多個列當作索引來使用,或者想將行索引變成DataFrame的列,這個時候我們就可以使用set_index()函式:
例1:
frame = pd.DataFrame({'a':range(7),'b':range(7,0,-1),'c':['one','one','one','two','two','two','two'],'d':[0,1,2,0,1,2,3]})
frame2 = frame.set_index(['c','d'])
例2:預設情況下,被設定成索引的列會從DataFrame裡移除,但是通過設定引數drop=False可以保留那些資料:
frame.set_index(['c','d'],drop=False)
例3:通過reset_index()函式可以將層次化索引轉移到列裡面:
frame2.reset_index()