利用python進行資料分析-pandas入門3
1.函式應用和對映
NumPy的ufuncs(元素級陣列方法)也可用於操作pandas物件
frame=DataFrame(np.random.randn(4,3),columns=list('bde'),index=['Uath','Ohio','Texas','Oregon'])
print frame
print np.abs(frame)
結果為:
b d e
Uath 1.187068 1.589404 0.328555
Ohio -0.040634 1.489594 -0.453027
Texas 0.362667 0.601500 2.177313
Oregon 0.019020 -0.315751 -0.480646
b d e
Uath 1.187068 1.589404 0.328555
Ohio 0.040634 1.489594 0.453027
Texas 0.362667 0.601500 2.177313
Oregon 0.019020 0.315751 0.480646
另一個常見的操作是,將函式應用到由各列或行所形成的一維陣列上。DataFrame的apply方法即可實現此功能
f=lambda x:x.max()-x.min()
print frame.apply(f)
print frame.apply(f,axis=1)
結果為:
b 0.605155
d 2.173279
e 2.737098
dtype: float64
Uath 1.913344
Ohio 0.302252
Texas 1.663901
Oregon 1.654397
dtype: float64
許多最為常見的陣列統計功能都能被實現成DataFrame的方法(比如sum和mean),因此無需使用apply方法
除標量值外,傳遞給apply的函式還可以返回由多個值組成的Series
def f(x):
return Series([x.min(),x.max()],index=['min','max'])
print frame.apply(f)
結果為:
b d e
min -1.878553 -1.339043 -2.638153
max 1.051156 1.322494 0.242260
此外,元素級的Python函式也是可以用的。如你想得到frame中各個浮點值的格式化字串,可以使用applymap
format=lambda x:'%.2f' % x
print frame.applymap(format)
結果為:
b d e
Uath 0.27 0.94 0.73
Ohio -0.81 0.78 -1.04
Texas 1.00 0.64 0.61
Oregon 0.55 -0.17 -0.40
之所以叫做applymap,是因為Series有一個用於應用元素級函式的map方法
print frame['e'].map(format)
結果為:
Uath 0.17
Ohio 2.22
Texas 0.58
Oregon 0.18
Name: e, dtype: object
2.排序和排名
要對行或列索引進行排序(按字典排序),可使用sort_index方法,它將返回一個已排序的新物件
obj=Series(range(4),index=['d','a','b','c'])
print obj.sort_index()
結果為:
a 1
b 2
c 3
d 0
dtype: int64
而對於DataFrame,可以根據任意一個軸上的索引進行排序
frame2=DataFrame(np.arange(8).reshape(2,4),index=['three','one'],columns=['d','a','b','c'])
print frame2.sort_index()
print frame2.sort_index(axis=1)
結果為:
d a b c
one 4 5 6 7
three 0 1 2 3
a b c d
three 1 2 3 0
one 5 6 7 4
資料預設是按照升序排序的,也可以降序排序
print frame2.sort_index(axis=1,ascending=False)
結果為:
d c b a
three 0 3 2 1
one 4 7 6 5
若要按值對Series進行排序,可使用其order方法
obj2=Series([4,7,-3,2])
print obj2.order()
結果為:
2 -3
3 2
0 4
1 7
在排序時,任何缺失值預設都會被放到Series末尾
obj3=Series([4,np.nan,7,np.nan,-3,2])
print obj3.order()
結果為:
4 -3
5 2
0 4
2 7
1 NaN
3 NaN
dtype: float64
在DataFrame上,你可能希望根據一個或多個列中的值進行排序。將一個或多個列的名字傳遞給by選項即可達到該目的
frame3=DataFrame({'b':[4,7,-3,2],'a':[0,1,0,1]})
print frame3
print frame3.sort_index(by='b')
結果為:
a b
0 0 4
1 1 7
2 0 -3
3 1 2
a b
2 0 -3
3 1 2
0 0 4
1 1 7
要根據多個列進行排序,傳入名稱的列表即可
print frame3.sort_index(by=['a','b'])
結果為:
a b
2 0 -3
0 0 4
3 1 2
1 1 7
排名(ranking)跟排序關係密切,且它會增設一個排名值(從1開始,一直到陣列中有效資料的數量)。預設情況下,rank是通過“為各組分配一個平均排名”的方式破壞平級關係的
obj4=Series([7,-5,7,4,2,0,4])
print obj4.rank()
結果為:
0 6.5
1 1.0
2 6.5
3 4.5
4 3.0
5 2.0
6 4.5
也可以根據值在原資料中出現的順序給出排名
print obj4.rank(method='first')
結果為:
0 6
1 1
2 7
3 4
4 3
5 2
6 5
dtype: float64
也可以按降序進行排名
print obj4.rank(method='max',ascending=False)
結果為:
0 2
1 7
2 2
3 4
4 5
5 6
6 4
dtype: float64
3.帶有重複值的軸索引
索引的is_unique屬性可以告訴你它的值是否是唯一的
obj5=Series(range(5),index=['a','a','b','b','c'])
print obj5
print obj5.index.is_unique
結果為:
a 0
a 1
b 2
b 3
c 4
dtype: int64
False
如果某個索引對應多個值,則返回一個Series
print obj5['a']
結果為:
a 0
a 1
dtype: int64
對DataFrame進行索引時也是如此
df=DataFrame(np.arange(12).reshape(4,3),index=['a','a','b','b'])
print df.ix['b']
結果為:
0 1 2
b 6 7 8
b 9 10 11
4.彙總和計算描述統計
df2=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'])
print df2
print df2.sum()
print df2.sum(axis=1)
結果為:
one two
a 1.40 NaN
b 7.10 -4.5
c NaN NaN
d 0.75 -1.3
one 9.25
two -5.80
dtype: float64
a 1.40
b 2.60
c 0.00
d -0.55
dtype: float64
NA值會自動被排除,除非整個切片(這裡指的是行或列)都是NA。通過skipna選項可以禁用該功能
print df2.sum(axis=1,skipna=False)
結果為:
a NaN
b 2.60
c NaN
d -0.55
dtype: float64
有些方法(如idxmin和idxmax)返回的是間接統計(比如達到最小值或最大值的索引)
print df2.idxmax()
結果為:
one b
two d
dtype: object
另一些方法則是累計型的
print df2.cumsum()
結果為:
one two
a 1.40 NaN
b 8.50 -4.5
c NaN NaN
d 9.25 -5.8
還有一種方法,它既不是約簡型也不是累計型。describe就是一個例子,它用於一次性產生多個彙總統計
print df2.describe()
結果為:
one two
count 3.000000 2.000000
mean 3.083333 -2.900000
std 3.493685 2.262742
min 0.750000 -4.500000
25% 1.075000 -3.700000
50% 1.400000 -2.900000
75% 4.250000 -2.100000
max 7.100000 -1.300000
5.相關係數與協方差
import pandas.io.data as web
all_data={}
for ticker in ['AAPL','IBM','MSFT','GOOG']:
all_data[ticker]=web.get_data_yahoo(ticker,'1/1/2000','1/1/2010')
price=DataFrame({tic:data['Adj Close']
for tic,data in all_data.iteritems()})
volume=DataFrame({tic:data['Volume']
for tic,data in all_data.iteritems()})
returns=price.pct_change()
print returns.tail()
結果為:
AAPL GOOG IBM MSFT
Date
2009-12-24 0.034339 0.011117 0.004385 0.002587
2009-12-28 0.012294 0.007098 0.013326 0.005484
2009-12-29 -0.011861 -0.005571 -0.003477 0.007058
2009-12-30 0.012147 0.005376 0.005461 -0.013699
2009-12-31 -0.004300 -0.004416 -0.012597 -0.015504
Series的corr方法用於計算兩個Series中重疊、非NA的、按索引對齊的值的相關係數。與此類似,cov用於計算協方差
print returns.MSFT.corr(returns.IBM)
print returns.MSFT.cov(returns.IBM)
結果為:
0.495979684549
0.000215957648434
DataFrame的corr和cov方法將以DataFrame的形式返回完整的相關係數與協方差矩陣
print returns.corr()
print returns.cov()
結果為:
AAPL GOOG IBM MSFT
AAPL 1.000000 0.470676 0.410011 0.424305
GOOG 0.470676 1.000000 0.390689 0.443587
IBM 0.410011 0.390689 1.000000 0.495980
MSFT 0.424305 0.443587 0.495980 1.000000
AAPL GOOG IBM MSFT
AAPL 0.001027 0.000303 0.000252 0.000309
GOOG 0.000303 0.000580 0.000142 0.000205
IBM 0.000252 0.000142 0.000367 0.000216
MSFT 0.000309 0.000205 0.000216 0.000516
利用DataFrame的corrwith方法,你可以計算其列或行跟另一個Series或DataFrame之間的相關係數。傳入一個Series將會返回一個相關係數值Series(針對各列進行計算)
print returns.corrwith(returns.IBM)
結果為:
AAPL 0.410011
GOOG 0.390689
IBM 1.000000
MSFT 0.495980
dtype: float64
傳入一個DataFrame則會計算按列名配對的相關係數。這裡,計算百分比變化與成交量的相關係數
print returns.corrwith(volume)
結果為:
AAPL -0.057549
GOOG 0.062647
IBM -0.007892
MSFT -0.014245
dtype: float64
傳入axis=1即可按行進行計算。無論如何,在計算相關係數之前,所有的資料項都會按標籤對齊
6.唯一值、值計數以及成員資格
obj6=Series(['c','a','d','a','a','b','b','c','c'])
uniques=obj6.unique()
print uniques
結果為:
['c' 'a' 'd' 'b']
返回的唯一值是未排序的,可以對結果再次進行排序(uniques.sort())。value_counts計算一個Series中各值出現的頻率
print obj6.value_counts()
結果為:
c 3
a 3
b 2
d 1
dtype: int64
value_counts還有一個頂級pandas方法,可用於任何陣列或序列
print pd.value_counts(obj6.values,sort=False)
結果為:
a 3
c 3
b 2
d 1
dtype: int64
isin,它用於判斷向量化集合的成員資格,可用於選取Series中或DataFrame列中資料的子集
mask=obj6.isin(['b','c'])
print mask
print obj6[mask]
結果為:
0 True
1 False
2 False
3 False
4 False
5 True
6 True
7 True
8 True
dtype: bool
0 c
5 b
6 b
7 c
8 c
dtype: object
有時,你希望得到DataFrame中多個相關列的一張柱狀圖
data2=DataFrame({'Qu1':[1,3,4,3,4],
'Qu2':[2,3,1,2,3],
'Qu3':[1,5,2,4,4]})
print data2
result=data2.apply(pd.value_counts).fillna(0)
print result
結果為:
Qu1 Qu2 Qu3
0 1 2 1
1 3 3 5
2 4 1 2
3 3 2 4
4 4 3 4
Qu1 Qu2 Qu3
1 1 1 1
2 0 2 1
3 2 2 0
4 2 0 2
5 0 0 1
7.處理丟失資料
pandas使用浮點值NAN表示浮點和非浮點陣列中的缺失資料,它只是一個便於被檢測出來的標記而已
string_data=Series(['aardvark','artichoke',np.nan,'avocado'])
print string_data
print string_data.isnull()
結果為:
0 aardvark
1 artichoke
2 NaN
3 avocado
dtype: object
0 False
1 False
2 True
3 False
dtype: bool
python內建的None值也會被當做NA處理
string_data[0]=None
print string_data.isnull()
結果為:
0 True
1 False
2 True
3 False
dtype: bool
8.濾除缺失資料
對於一個Series,dropna返回一個僅含非空資料和索引值的Series
from numpy import nan as NA
data=Series([1,NA,3.5,NA,7])
print data.dropna()
print data[data.notnull()]
結果為:
0 1.0
2 3.5
4 7.0
dtype: float64
0 1.0
2 3.5
4 7.0
dtype: float64
對於DataFrame物件,事情就有點複雜了。你可能希望丟棄全NA或含有NA的行或列。dropna預設丟棄任何含有缺失值的行
data3=DataFrame([[1,6.5,3],[1,NA,NA],[NA,NA,NA],[NA,6.5,3]])
print data3
cleaned=data3.dropna()
print cleaned
結果為:
0 1 2
0 1 6.5 3
1 1 NaN NaN
2 NaN NaN NaN
3 NaN 6.5 3
0 1 2
0 1 6.5 3
傳入how='all'將只丟棄全為NA的那些行
print data3.dropna(how='all')
結果為:
0 1 2
0 1 6.5 3
1 1 NaN NaN
3 NaN 6.5 3
要用這種方式丟棄列,只需傳入axis=1即可
data3[4]=NA
print data3
print data3.dropna(axis=1,how='all')
結果為:
0 1 2 4
0 1 6.5 3 NaN
1 1 NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN 6.5 3 NaN
0 1 2
0 1 6.5 3
1 1 NaN NaN
2 NaN NaN NaN
3 NaN 6.5 3
另一個濾除DataFrame行的問題涉及到時間序列資料。假設你只想留下一部分觀測資料,可以用thresh引數實現此目的
df3=DataFrame(np.random.randn(7,3))
df3.ix[:4,1]=NA
df3.ix[:2,2]=NA
print df3
print df3.dropna(thresh=3)
結果為:
0 1 2
0 2.399544 NaN NaN
1 0.430949 NaN NaN
2 -1.083213 NaN NaN
3 -0.431232 NaN 0.756593
4 0.529114 NaN -0.595716
5 1.444382 -0.195083 -0.930979
6 -1.412920 -0.934195 2.861213
0 1 2
5 1.444382 -0.195083 -0.930979
6 -1.412920 -0.934195 2.861213
9.填充缺失資料
fillna方法是最主要的函式
print df3.fillna(0)
print df3.fillna({1:0.5,3:-1})
結果為:
0 1 2
0 -0.034171 0.000000 0.000000
1 -0.115502 0.000000 0.000000
2 0.308157 0.000000 0.000000
3 1.367718 0.000000 -0.306751
4 -1.360234 0.000000 0.999463
5 -0.148457 0.156416 -2.017497
6 -0.408602 0.403680 -1.352914
0 1 2
0 -0.034171 0.500000 NaN
1 -0.115502 0.500000 NaN
2 0.308157 0.500000 NaN
3 1.367718 0.500000 -0.306751
4 -1.360234 0.500000 0.999463
5 -0.148457 0.156416 -2.017497
6 -0.408602 0.403680 -1.352914
fillna預設會返回新物件,但也可以對現有物件進行就地修改
_=df3.fillna(0,inplace=True)
print df3
結果為:
0 1 2
0 -1.901323 0.000000 0.000000
1 -0.431574 0.000000 0.000000
2 1.452733 0.000000 0.000000
3 0.013765 0.000000 0.572696
4 0.121601 0.000000 -0.972343
5 0.411238 -0.023716 0.827292
6 0.266131 0.706082 0.859971
對reindex有效的那些插值方法也可用於fillna
df4=DataFrame(np.random.randn(6,3))
df4.ix[2:,1]=NA
df4.ix[4:,2]=NA
print df4
print df4.fillna(method='ffill')
print df4.fillna(method='ffill',limit=2)
結果為:
0 1 2
0 0.132548 0.581560 0.539203
1 0.250056 0.676504 -0.645744
2 0.760809 NaN 1.073846
3 -0.480362 NaN 0.221771
4 -0.600295 NaN NaN
5 0.005458 NaN NaN
0 1 2
0 0.132548 0.581560 0.539203
1 0.250056 0.676504 -0.645744
2 0.760809 0.676504 1.073846
3 -0.480362 0.676504 0.221771
4 -0.600295 0.676504 0.221771
5 0.005458 0.676504 0.221771
0 1 2
0 0.132548 0.581560 0.539203
1 0.250056 0.676504 -0.645744
2 0.760809 0.676504 1.073846
3 -0.480362 0.676504 0.221771
4 -0.600295 NaN 0.221771
5 0.005458 NaN 0.221771
10.層次化索引
它使你能以低緯度形式處理高緯度資料
data4=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]])
print data4
結果為:
a 1 -0.219090
2 -1.372102
3 1.108223
b 1 -0.796361
2 1.175877
3 0.520666
c 1 1.058822
2 1.325842
d 2 -0.040458
3 0.205163
dtype: float64
這就是帶有MultiIndex索引的Series的格式化輸出形式。索引之間的“間隔”表示“直接使用上面的標籤”
print data4.index
結果為:
MultiIndex(levels=[[u'a', u'b', u'c', u'd'], [1, 2, 3]],
labels=[[0, 0, 0, 1, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 1, 2]])
對於一個層次化索引的物件,選取資料子集的操作很簡單
print data4['b']
結果為:
1 -0.094394
2 0.531658
3 -0.159814
dtype: float64
print data4['b':'c']
print data4.ix[['b','d']]
結果為:
b 1 -1.336168
2 0.074839
3 -0.615861
c 1 -0.349232
2 -0.024671
dtype: float64
b 1 -1.336168
2 0.074839
3 -0.615861
d 2 1.444744
3 -0.824043
dtype: float64
可以通過其unstack方法被重新安排到一個DataFrame中
print data4.unstack()
結果為:
1 2 3
a 1.483774 0.221626 0.085326
b 0.354429 -1.018716 0.423129
c -1.038540 2.103571 NaN
d NaN 0.596784 1.500782
unstack的逆運算是stack
print data4.unstack().stack()
結果為:
a 1 -0.718105
2 0.766081
3 -0.221549
b 1 -0.521521
2 -1.252716
3 -0.329751
c 1 1.912822
2 -0.794359
d 2 1.432758
3 1.244745
dtype: float64
對於一個DataFrame,每條軸上都可以有分層索引
frame4=DataFrame(np.arange(12).reshape((4,3)),
index=[['a','a','b','b'],[1,2,1,2]],
columns=[['Ohio','Ohio','Colorado'],
['Green','Red','Green']])
print frame4
frame4.index.names=['key1','key2']
frame4.columns.names=['state','color']
print frame4
結果為:
Ohio Colorado
Green Red Green
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
11.重排分級排序
swaplevel接受兩個級別編號或名稱,並返回一個互換了級別的新物件(但資料不會發生變化)
print frame4.swaplevel('key1','key2')
結果為:
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
2 a 3 4 5
1 b 6 7 8
2 b 9 10 11
而sortlevel則根據單個級別中的值對資料進行排序。交換級別時,常常也會用到sortlevel,這樣最終結果就是有序的了
print frame4.sortlevel(1)
print frame4.swaplevel(0,1).sortlevel(0)
結果為:
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
b 1 6 7 8
a 2 3 4 5
b 2 9 10 11
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
b 6 7 8
2 a 3 4 5
b 9 10 11
12.根據級別彙總統計
print frame4.sum(level='key2')
print frame4.sum(level='color',axis=1)
結果為:
state Ohio Colorado
color Green Red Green
key2
1 6 8 10
2 12 14 16
color Green Red
key1 key2
a 1 2 1
2 8 4
b 1 14 7
2 20 10
13.使用DataFrame的列
frame5=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]})
print frame5
結果為:
a b c d
0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
3 3 4 two 0
4 4 3 two 1
5 5 2 two 2
6 6 1 two 3
DataFrame的set_index函式會將其一個或多個列轉換為行索引,並建立一個新的DataFrame
frame5=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]})
print frame5
frame6=frame5.set_index(['c','d'])
print frame6
結果為:
a b c d
0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
3 3 4 two 0
4 4 3 two 1
5 5 2 two 2
6 6 1 two 3
a b
c d
one 0 0 7
1 1 6
2 2 5
two 0 3 4
1 4 3
2 5 2
3 6 1
預設情況下,那些列會從DataFrame中移除,但也可以將其保留下來
print frame5.set_index(['c','d'],drop=False)
結果為:
a b c d
c d
one 0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
two 0 3 4 two 0
1 4 3 two 1
2 5 2 two 2
3 6 1 two 3
reset_index的功能跟set_index剛好相反,層次化索引的級別會被轉移到列裡面
print frame6.reset_index()
結果為:
c d a b
0 one 0 0 7
1 one 1 1 6
2 one 2 2 5
3 two 0 3 4
4 two 1 4 3
5 two 2 5 2
6 two 3 6 1