5.3匯總和計(jì)算描述性統(tǒng)計(jì)
pandas對(duì)象擁有一組常用的數(shù)學(xué)和統(tǒng)計(jì)方法毛仪。他們大部分都屬于約簡(jiǎn)和匯總統(tǒng)計(jì)簇宽,用于從Series中提取單個(gè)值(如mean或sum)或從DataFrame的行或列中提取一個(gè)Series晦譬。跟對(duì)應(yīng)的NumPy數(shù)組方法相比,他們都是基于沒(méi)有缺失數(shù)據(jù)的假設(shè)而構(gòu)建的。
下面是一個(gè)簡(jiǎn)單的DataFrame:
In [90]: df=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'])
In [91]: df
Out[91]:
one two
a 1.40 NaN
b 7.10 -4.5
c NaN NaN
d 0.75 -1.3
調(diào)用DataFrame的sum方法將會(huì)返回一個(gè)含有列的小計(jì)的Series:
In [92]: df.sum()
Out[92]:
one 9.25
two -5.80
dtype: float64
傳入axis=1 將會(huì)按行進(jìn)行求和計(jì)算:
In [93]: df.sum(axis=1)
Out[93]:
a 1.40
b 2.60
c 0.00
d -0.55
dtype: float64
NA值將會(huì)被自動(dòng)剔除,除非整個(gè)切片都是NA报亩。通過(guò)skipna選項(xiàng)可以禁用該功能:
In [94]: df.mean(axis=1,skipna=False)
Out[94]:
a NaN
b 1.300
c NaN
d -0.275
dtype: float64
表5-9給出了約簡(jiǎn)方法常用選項(xiàng)
有些方法(如idxmin和idxmax)返回的是間接統(tǒng)計(jì)(比如達(dá)到最大值或最小值的索引):
In [95]: df.idxmax()
Out[95]:
one b
two d
dtype: object
一些方法則是累計(jì)型的:
In [96]: df.cumsum()
Out[96]:
one two
a 1.40 NaN
b 8.50 -4.5
c NaN NaN
d 9.25 -5.8
還有一些方法,既不是約簡(jiǎn)型也不是累計(jì)型井氢。
In [97]: df.describe()
Out[97]:
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
對(duì)于非數(shù)值型的數(shù)據(jù)弦追,describe會(huì)產(chǎn)生另一種匯總統(tǒng)計(jì):
In [98]: obj=Series(['a','a','b','c']*4)
In [99]: obj.describe()
Out[99]:
count? 16
unique? 3
top? ? ? ? a
freq ? ? 8
dtype:? ? object
表5-10列出了所有與描述統(tǒng)計(jì)相關(guān)的方法。
5.3.1相關(guān)系數(shù)和協(xié)方差
有些匯總統(tǒng)計(jì)(如先關(guān)系數(shù)和協(xié)方差)是通過(guò)參數(shù)計(jì)算出來(lái)的花竞。
5.3.2唯一值劲件、值計(jì)數(shù)以及成員資格
從一維Series的值中抽取信息掸哑。以下這個(gè)Series為例:
In [107]: obj=Series(['c','a','d','a','a','b','b','c','c'])
第一個(gè)函數(shù)是unique,可以得到Sseries中的唯一數(shù)組:
In [108]: uniques=obj.unique()
In [109]: uniques
Out[109]: array(['c', 'a', 'd', 'b'], dtype=object)
返回值的唯一未排序的零远,如果需要的話苗分,可以對(duì)結(jié)果再次進(jìn)行排序(unique.sort())
value_counts 用于計(jì)算一個(gè)Series中各值出現(xiàn)的頻率:
In [110]: obj.value_counts()
Out[110]:
c 3
a 3
b 2
d 1
dtype: int64
為了方便查看,結(jié)果Series是按值頻率降序排列的牵辣。
value_counts 還是一個(gè)頂級(jí)的pandas方法摔癣,可用于任何數(shù)組的或序列:
In [111]: pd.value_counts(obj.values,sort=False)
Out[111]:
a 3
c 3
b 2
d 1
dtype: int64
最后isin,它用于判斷矢量化最集合的成員資格纬向,可用于選取Series中或DataFrame列中的數(shù)據(jù)的子集:
In [112]: mask=obj.isin(['b','c'])
In [113]: mask
Out[113]:
0 True
1 False
2 False
3 False
4 False
5 True
6 True
7 True
8 True
dtype: bool
In [114]: obj[mask]
Out[114]:
0 c
5 b
6 b
7 c
8 c
dtype: object
有時(shí)择浊,你可能需要得到DataFrame中多個(gè)相關(guān)的一張柱狀圖。
In [115]: data=DataFrame({'Qu1':[1,3,4,3,4],'Qu2':[2,3,1,2,3],'Qu3':[1,5,2,4,4]})
In [116]: data
Out[116]:
Qu1 Qu2 Qu3
0 1 2 1
1 3 3 5
2 4 1 2
3 3 2 4
4 4 3 4
In [117]: result=data.apply(pd.value_counts).fillna(0)
In [118]: result
Out[118]:
Qu1 Qu2 Qu3
1 1.0 1.0 1.0
2 0.0 2.0 1.0
3 2.0 2.0 0.0
4 2.0 0.0 2.0
5 0.0 0.0 1.0
5.4處理缺失數(shù)據(jù)
處理缺失數(shù)據(jù)(missing data)在大部分的數(shù)據(jù)分析應(yīng)用中很常見逾条。pandas的設(shè)計(jì)目標(biāo)之一就是讓缺失數(shù)據(jù)的處理任務(wù)盡量輕松琢岩。
pandas使用浮點(diǎn)數(shù)NaN(Not a Number)表示浮點(diǎn)和非浮點(diǎn)數(shù)組中的缺失數(shù)據(jù)。只是一個(gè)便于檢測(cè)出來(lái)的標(biāo)記而已:
In [119]: string_data=Series(['aardvark','arrichoke',np.nan,'avocado'])
In [120]: string_data
Out[120]:
0? ? aardvark
1? ? arrichoke
2? ? ? ? ? NaN
3? ? ? avocado
dtype: object
In [121]: string_data.isnull()
Out[121]:
0? ? False
1? ? False
2? ? True
3? ? False
dtype: bool
python內(nèi)置的None值也會(huì)被當(dāng)做NA處理:
In [123]: string_data.isnull()
Out[123]:
0 True
1 False
2 True
3 False
dtype: bool
5.4.1濾除缺失數(shù)據(jù)
對(duì)于一個(gè)Series师脂,dropna返回一個(gè)僅含有非空數(shù)據(jù)的和索引值的Series:
In [124]: from numpy import nan as NA
In [125]: data=Series([1,NA,3.5,NA,7])
In [126]: data.dropna()
Out[126]:
0 1.0
2 3.5
4 7.0
dtype: float64
還可以通過(guò)布爾型索引達(dá)到這個(gè)目的:
In [127]: data[data.notnull()]
Out[127]:
0 1.0
2 3.5
4 7.0
dtype: float64
對(duì)于DataFrame對(duì)象担孔,如果希望丟棄全NA或NA的行貨列,dropna默認(rèn)丟棄任何含有缺失值的行:
In [129]: data=DataFrame([[1.,6.5,3.],[1.,NA,NA],[NA,NA,NA],[NA,6.5,3.]])
In [130]: cleaned=data.dropna()
In [131]: data
Out[131]:
0 1 2
0 1.0 6.5 3.0
1 1.0 NaN NaN
2 NaN NaN NaN
3 NaN 6.5 3.0
In [132]: cleaned
Out[132]:
0 1 2
0 1.0 6.5 3.0
傳入how=‘a(chǎn)ll’ 將只丟棄全為NA的那些行:
In [133]: data.dropna(how='all')
Out[133]:
0 1 2
0 1.0 6.5 3.0
1 1.0 NaN NaN
3 NaN 6.5 3.0
要用這種方式丟棄列吃警,只需傳入axis=1即可:
In [134]: data[4]=NA
In [135]: data
Out[135]:
0 1 2 4
0 1.0 6.5 3.0 NaN
1 1.0 NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN 6.5 3.0 NaN
In [136]: data.dropna(axis=1,how='all')
Out[136]:
0 1 2
0 1.0 6.5 3.0
1 1.0 NaN NaN
2 NaN NaN NaN
3 NaN 6.5 3.0
另一個(gè)濾出DataFrame行的問(wèn)題涉及時(shí)間序列數(shù)據(jù)糕篇。
假設(shè)你只想留下一部分觀測(cè)數(shù)據(jù),可以用thresh參數(shù)實(shí)現(xiàn)此目的:
In [137]: df=DataFrame(np.random.randn(7,3))
In [138]: df.ix[:4,1]=NA;df.ix[:2,2]=NA
In [139]: df
Out[139]:
0 1 2
0 0.452896 NaN NaN
1 1.071009 NaN NaN
2 -0.135804 NaN NaN
3 0.010116 NaN 0.064880
4 -1.038639 NaN -0.756553
5 0.738134 -1.505505 -0.052306
6 -1.712077 0.386785 0.436945
In [140]: df.dropna(thresh=3)
Out[140]:
0 1 2
5 0.738134 -1.505505 -0.052306
6 -1.712077 0.386785 0.436945
5.4.2填充缺失數(shù)據(jù)
如果不想濾除數(shù)據(jù)汤徽,而是希望填充數(shù)據(jù)娩缰。
通過(guò)一個(gè)常數(shù)來(lái)fillna就會(huì)將缺失值替換為那個(gè)常數(shù)值:
In [141]: df.fillna(0)
Out[141]:
0 1 2
0 0.452896 0.000000 0.000000
1 1.071009 0.000000 0.000000
2 -0.135804 0.000000 0.000000
3 0.010116 0.000000 0.064880
4 -1.038639 0.000000 -0.756553
5 0.738134 -1.505505 -0.052306
6 -1.712077 0.386785 0.436945
通過(guò)一個(gè)字典調(diào)用fillna,就可以實(shí)現(xiàn)對(duì)不同的列填充不同的值:
In [142]: df.fillna({1:0.5,3:-1})
Out[142]:
0 1 2
0 0.452896 0.500000 NaN
1 1.071009 0.500000 NaN
2 -0.135804 0.500000 NaN
3 0.010116 0.500000 0.064880
4 -1.038639 0.500000 -0.756553
5 0.738134 -1.505505 -0.052306
6 -1.712077 0.386785 0.436945
fillna默認(rèn)會(huì)返回新對(duì)象谒府,但是也可以對(duì)現(xiàn)有的對(duì)象進(jìn)行修改:
In [143]: _=df.fillna(0,inplace=True)
In [144]: df
Out[144]:
0 1 2
0 0.452896 0.000000 0.000000
1 1.071009 0.000000 0.000000
2 -0.135804 0.000000 0.000000
3 0.010116 0.000000 0.064880
4 -1.038639 0.000000 -0.756553
5 0.738134 -1.505505 -0.052306
6 -1.712077 0.386785 0.436945
對(duì)reindex有效的那些插值方法也可以用于fillna:
In [145]: df=DataFrame(np.random.randn(6,3))
In [146]: df.ix[2:,1]=NA;df.ix[4:,2]=NA
In [147]: df
Out[147]:
0 1 2
0 0.501394 -1.735750 0.197643
1 2.099104 1.441581 0.743717
2 -0.451567 NaN -0.150315
3 -0.032894 NaN 0.418310
4 1.285966 NaN NaN
5 -0.058611 NaN NaN
In [148]: df.fillna(method='ffill')
Out[148]:
0 1 2
0 0.501394 -1.735750 0.197643
1 2.099104 1.441581 0.743717
2 -0.451567 1.441581 -0.150315
3 -0.032894 1.441581 0.418310
4 1.285966 1.441581 0.418310
5 -0.058611 1.441581 0.418310
In [149]: df.fillna(method='ffill',limit=2)
Out[149]:
0 1 2
0 0.501394 -1.735750 0.197643
1 2.099104 1.441581 0.743717
2 -0.451567 1.441581 -0.150315
3 -0.032894 1.441581 0.418310
4 1.285966 NaN 0.418310
5 -0.058611 NaN 0.418310
只要稍微動(dòng)腦子拼坎,就可以利用fillna的=實(shí)現(xiàn)許多的別的功能。
比如完疫,傳入Series的平均值或中位數(shù):
In [150]: data=Series([1.,NA,3.5,NA,7])
In [151]: data.fillna(data.mean())
Out[151]:
0 1.000000
1 3.833333
2 3.500000
3 3.833333
4 7.000000
dtype: float64
5.5層次化索引
層次化索引泰鸡,是你能在一個(gè)軸上擁有多個(gè)(兩個(gè)以上)索引級(jí)別。
即能以低緯度形式處理高緯度數(shù)據(jù)壳鹤。
我們來(lái)創(chuàng)建一個(gè)Series盛龄,并用一個(gè)由列表或數(shù)組組成的列表作為索引:
In [152]: data=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]])
In [153]: data
Out[153]:
a? 1? ? 0.024162
2? ? 0.969526
3? -0.215712
b? 1? ? 1.136933
2? -0.158487
3? ? 0.482377
c? 1? -0.551888
2? -1.090750
d? 2? -0.073204
3? -1.217613
dtype: float64
這就是帶有MultiIndex 索引的Series 的格式輸出格式。索引之間的“間隔”表示“直接使用上面的標(biāo)簽”:
In [154]: data.index
Out[154]:
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]])
對(duì)于一個(gè)層次化索引的對(duì)象芳誓,選取數(shù)據(jù)子集的操作很簡(jiǎn)單:
data['b']
Out[155]:
1? ? 1.136933
2? -0.158487
3? ? 0.482377
dtype: float64
data['b':'c']
Out[156]:
b? 1? ? 1.136933
2? -0.158487
3? ? 0.482377
c? 1? -0.551888
2? -1.090750
dtype: float64
data.ix[['b','d']]
Out[158]:
b? 1? ? 1.136933
2? -0.158487
3? ? 0.482377
d? 2? -0.073204
3? -1.217613
dtype: float64
甚至還可以在“內(nèi)層”中進(jìn)行選扔嗖啊:
In [159]: data[:,2]
Out[159]:
a? ? 0.969526
b? -0.158487
c? -1.090750
d? -0.073204
dtype: float64
層次化索引的在數(shù)據(jù)重塑和基于分組的操作(如透視表生成)中扮演重要角色。比如說(shuō)锹淌,這段數(shù)據(jù)可以通過(guò)unstack方法被重新安排到一個(gè)DataFrame中:
n [160]: data.unstack()
Out[160]:
1? ? ? ? 2? ? ? ? 3
a? 0.024162? 0.969526 -0.215712
b? 1.136933 -0.158487? 0.482377
c -0.551888 -1.090750? ? ? NaN
d? ? ? NaN -0.073204 -1.21761
unstack的逆運(yùn)算是stack:
In [161]: data.unstack().stack()
Out[161]:
a? 1? ? 0.024162
2? ? 0.969526
3? -0.215712
b? 1? ? 1.136933
2? -0.158487
3? ? 0.482377
c? 1? -0.551888
2? -1.090750
d? 2? -0.073204
3? -1.217613
dtype: float64
對(duì)于一個(gè)DataFrame匿值,每條軸都可以分層索引:
In [162]: frame=DataFrame(np.arange(12).reshape((4,3)),index=[['a','a','b','b'],[1,2,1,2]],columns=[['Ohio','Ohio','Colorado'],['Green','Red','Green']])
In [163]: frame
Out[163]:
Ohio? ? Colorado
Green Red? ? Green
a 1? ? 0? 1? ? ? ? 2
2? ? 3? 4? ? ? ? 5
b 1? ? 6? 7? ? ? ? 8
2? ? 9? 10? ? ? 11
各層都可以有名字(可以是字符串,也可以是python對(duì)象)赂摆。如果指定了名稱挟憔,他們就會(huì)顯示在控制臺(tái)輸出中:
In [164]: frame.index.names=['key1','key2']
In [165]: frame.columns.names=['state','color']
In [166]: frame
Out[166]:
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
有了分部的列索引钟些,因此可以選取列分組:
In [167]: frame['Ohio']
Out[167]:
color? ? ? Green? Red
key1 key2
a? ? 1? ? ? ? 0? ? 1
2? ? ? ? 3? ? 4
b? ? 1? ? ? ? 6? ? 7
2? ? ? ? 9? 10
可以單獨(dú)的創(chuàng)建MultiIndex 然后復(fù)用,上面那個(gè)DataFrame中的(分級(jí))列可以這樣創(chuàng)建:
In [168]: MultiIndex.from_arrays([['Ohio','Ohio','Colorado'],['Green','Red','Green']],names=['state','color'])
5.5.1重排分級(jí)順序
如果需要調(diào)整某條軸上各級(jí)別的順序绊谭,或根據(jù)指定界級(jí)別上的值對(duì)數(shù)據(jù)進(jìn)行排序政恍。swaplevel接受兩個(gè)級(jí)別編號(hào)或名稱,并返回一個(gè)互換級(jí)別的新對(duì)象(但數(shù)據(jù)不會(huì)發(fā)生變化):
In [169]: frame.swaplevel('key1','key2')
Out[169]:
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
而sortleval則根據(jù)單個(gè)級(jí)別中的值對(duì)數(shù)據(jù)進(jìn)行排序(穩(wěn)定的)达传。交流級(jí)別時(shí)篙耗,常常也會(huì)用到sortlevel,這樣最終的結(jié)果就是有序的了:
In [170]: frame.sortlevel(1)
Out[170]:
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
In [172]: frame.swaplevel(0,1).sortlevel(0)
Out[172]:
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
5.5.2根據(jù)級(jí)別匯總統(tǒng)計(jì)
許多對(duì)DataFrame 和Series的描述和匯總統(tǒng)計(jì)都有一個(gè)leve選項(xiàng)趟大,用于指定在某條軸上對(duì)求和的級(jí)別鹤树,再也上面的那個(gè)DataFrame為例子铣焊,我們根據(jù)行或列上的級(jí)別進(jìn)行求和:
In [173]: frame.sum(level='color',axis=1)
Out[173]:
color Green Red
key1 key2
a 1 2 1
2 8 4
b 1 14 7
2 20 10
In [174]: frame.sum(level='key2')
Out[174]:
state Ohio Colorado
color Green Red Green
key2
1 6 8 10
2 12 14 16
5.5.3使用DataFrame的列
將DataFrame的一個(gè)或多個(gè)列當(dāng)做行索引來(lái)用逊朽,或者可能希望將行索引變成DataFrame要的列。
In [14]: frame=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]})
In [15]: frame
Out[15]:
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函數(shù)會(huì)將一個(gè)或多個(gè)列轉(zhuǎn)換為行索引曲伊,并創(chuàng)建一個(gè)新的DataFrame:
In [17]: frame2
Out[17]:
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
默認(rèn)情況下叽讳,那些列會(huì)從DataFrame中移除,但是也可以將其保留:
In [18]: frame.set_index(['c','d'],drop=False)
Out[18]:
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剛好相反坟募,層次化索引的級(jí)別會(huì)被轉(zhuǎn)移到列里面:
In [20]: frame2.reset_index()
Out[20]:
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
5.6其他有關(guān)pandas的話題
5.6.1整數(shù)索引
操作由整數(shù)索引的pandas對(duì)象常常會(huì)讓新手抓狂岛蚤,因?yàn)樗麄兏鷥?nèi)置的python數(shù)據(jù)結(jié)構(gòu)(如列表和元組)在索引語(yǔ)義上有些不同。
例如懈糯,你可能認(rèn)為下面的代碼不會(huì)報(bào)錯(cuò)涤妒。
In [24]: ser=Series(np.arange(3.))
In [25]: ser[-1]
---------------------------------------------------------------------------
KeyError? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Traceback (most recent call last)
in ()
----> 1 ser[-1]
pandas\src\hashtable_class_helper.pxi in pandas.hashtable.Int64HashTable.get_item (pandas\hashtable.c:85
08)()
KeyError: -1L
雖然pandas會(huì)“求助于”整數(shù)索引,但是沒(méi)有哪種方法能夠既不引入bug赚哗,又能解決問(wèn)題的她紫。
我們有一個(gè)含有0,1屿储,2的索引贿讹,但是很難推斷出用戶想要什么:
In [26]: ser
Out[26]:
0? ? 0.0
1? ? 1.0
2? ? 2.0
dtype: float64
相反,對(duì)于一個(gè)非整數(shù)索引够掠,就沒(méi)有這樣的歧義:
In [30]: ser2=Series(np.arange(3.),index=['a','b','c'])
In [31]: ser2[-1]
Out[31]: 2.0
為了保持良好的一致性民褂,如果你的軸索引含有索引器,那么根據(jù)整數(shù)進(jìn)行數(shù)據(jù)選取的操作蔣總是面向標(biāo)簽的疯潭。這也包括用ix進(jìn)行切片:
In [32]: ser.ix[:1]
Out[32]:
0? ? 0.0
1? ? 1.0
dtype: float64
如果需要可靠的赊堪,不考慮索引類型的,基于位置的索引竖哩,可以使用Series 的 iget_value 方法和DataFrame的irow和icol方法:
In [33]: ser3=Series(range(3),index=[-5,1,3])
In [35]: ser3.iget_value(2)
Out[35]: 2
In [37]: frame=DataFrame(np.arange(6).reshape(3,2),index=[2,0,1])
In [38]: frame.irow(0)
Out[38]:
0? ? 0
1? ? 1
Name: 2, dtype: int32