一.匯總和計算描述統計
pandas對象擁有一組常用的數學和統計方法。它們大部分屬於約簡和匯總統計,用於從Series中提取單個值(如sum或mean)或從DataFrame的行或列中提取一個Series。跟對應的Numpy數組方法相比,它們都是基於沒有缺失數據的假設而構建的。接下來看一個簡單的DataFrame:
In [1]: import numpy as np
In [2]: from pandas import Series,DataFrame
In [3]: df=DataFrame([[1.4,np.nan],[8.4,-3.5],[np.nan,np.nan],[0.65,-2.3]],inde
...: x=['a','b','c','d'],columns=['one','two'])
In [4]: df
Out[4]:
one two
a 1.40 NaN
b 8.40 -3.5
c NaN NaN
d 0.65 -2.3
調用DataFrame的sum方法將會返回一個含有列小計的Series:
In [5]: df.sum()
Out[5]:
one 10.45
two -5.80
dtype: float64
傳入axis=1將會按行進行求和運算:
In [6]: df.sum(axis=1)
Out[6]:
a 1.40
b 4.90
c 0.00
d -1.65
dtype: float64
NA值會自動被排除,除非整個切片(這里指的是行或列)都是NA.通過skipna選項可以禁用該功能:
In [7]: df.sum(axis=1,skipna=False)
Out[7]:
a NaN
b 4.90
c NaN
d -1.65
dtype: float64
In [8]: df.mean(axis=1,skipna=False) #求每行的平均值,顯示NA值,如果某行有NaN值,則這行平均值為NaN
Out[8]:
a NaN
b 2.450
c NaN
d -0.825
dtype: float64
下表列出了這些約簡方法的常用選項。
選項 說明
axis 約簡的軸。DataFrame的行用0,列用1
skipna 排除缺失值,默認值為True
level 如果軸是層次化索引的(積MultiIndex),則根據level分組約簡
有些方法(如idxmin何idxmax)返回的是間接統計(比如達到最小值或最大值的索引):
In [12]: df.idxmax()
Out[12]:
one b
two d
dtype: object
In [13]: df.idxmin()
Out[13]:
one d
two b
dtype: object
另一些方法則是累計型的:
In [14]: df.cumsum()
Out[14]:
one two
a 1.40 NaN
b 9.80 -3.5
c NaN NaN
d 10.45 -5.8
還有一種方法,它既不是約簡型也不是累計型。describe就是一個例子,它用於一次性產生多個匯總統計:
In [16]: df.describe()
Out[16]:
one two
count 3.000000 2.000000
mean 3.483333 -2.900000
std 4.274440 0.848528
min 0.650000 -3.500000
25% 1.025000 -3.200000
50% 1.400000 -2.900000
75% 4.900000 -2.600000
max 8.400000 -2.300000
對於非數值型數據,describe會產生另一種匯總統計
In [17]: obj=Series(['a','a','b','c']*3)
In [18]: obj
Out[18]:
0 a
1 a
2 b
3 c
4 a
5 a
6 b
7 c
8 a
9 a
10 b
11 c
dtype: object
In [19]: obj.describe()
Out[19]:
count 12
unique 3
top a
freq 6
dtype: object
下表列出了所有與描述統計相關的方法。
方法 說明
count 非NA值的數量
describe 針對Series或各DataFrame列計算匯總統計
min、max 計算最小值和最大值
argmin、argmax 計算能夠獲取到最小值和最大值的索引位置(整數)
idxmin、idxmax 計算能夠獲取到最小值和最大值的索引值
quantile 計算樣本的分位數(0到1)
sum 值的總和
mean 值的平均值
median 值的算術中位數(50%分位數)
mad 根據平均值計算平均絕對離差
var 樣本值的標准差
skew 樣本值的偏度(三階矩)
kurt 樣本值的峰值(四階矩)
cumsum 樣本值的累計和
cummin、cummax 樣本值的累計最大值和累計最小值
cumprod 樣本值的累計積
diff 計算一階差分(對時間序列很有用)
pct_change 計算百分數變化
二.相關系數與協方差
有些匯總統計(如相關系數和協方差)是通過參數對計算出來的。我們來看幾個DataFrame:
In [30]: df=DataFrame(np.arange(20).reshape(10,2))
In [31]: df
Out[31]:
0 1
0 0 1
1 2 3
2 4 5
3 6 7
4 8 9
5 10 11
6 12 13
7 14 15
8 16 17
9 18 19
#計算列的百分比變化,如果要計算行,設置axis=1
In [32]: df.pct_change()
Out[32]:
0 1
0 NaN NaN
1 inf 2.000000
2 1.000000 0.666667
3 0.500000 0.400000
4 0.333333 0.285714
5 0.250000 0.222222
6 0.200000 0.181818
7 0.166667 0.153846
8 0.142857 0.133333
9 0.125000 0.117647
In [34]: df.pct_change(axis=1)
Out[34]:
0 1
0 NaN inf
1 NaN 0.500000
2 NaN 0.250000
3 NaN 0.166667
4 NaN 0.125000
5 NaN 0.100000
6 NaN 0.083333
7 NaN 0.071429
8 NaN 0.062500
9 NaN 0.055556
#默認輸出5行,可以設置n參數來設置輸出的行數
In [33]: df.head()
Out[33]:
0 1
0 0 1
1 2 3
2 4 5
3 6 7
4 8 9
In [33]: df.head()
Out[33]:
0 1
0 0 1
1 2 3
2 4 5
3 6 7
4 8 9
In [36]: df.tail()
Out[36]:
0 1
5 10 11
6 12 13
7 14 15
8 16 17
9 18 19
計算DataFrame列與列的相關系數和協方差
In [38]: df=DataFrame(np.arange(9).reshape((3,3)),index=['a','b','c'],columns=[
...: 'one','two','three'])
In [39]: df
Out[39]:
one two three
a 0 1 2
b 3 4 5
c 6 7 8
#計算第一列和第二列的相關系數
In [40]: df.one.corr(df.two)
Out[40]: 1.0
#返回一個相關系數矩陣
In [41]: df.corr()
Out[41]:
one two three
one 1.0 1.0 1.0
two 1.0 1.0 1.0
three 1.0 1.0 1.0
#計算第一列和第二列的協方差
In [42]: df.one.cov(df.two)
Out[42]: 9.0
#返回一個協方差矩陣
In [43]: df.cov()
Out[43]:
one two three
one 9.0 9.0 9.0
two 9.0 9.0 9.0
three 9.0 9.0 9.0
計算DataFrame與列或者Series的相關系數
In [38]: df=DataFrame(np.arange(9).reshape((3,3)),index=['a','b','c'],columns=[
...: 'one','two','three'])
In [39]: df
Out[39]:
one two three
a 0 1 2
b 3 4 5
c 6 7 8
#計算df與第三列的相關系數
In [44]: df.corrwith(df.three)
Out[44]:
one 1.0
two 1.0
three 1.0
dtype: float64
#計算df與Series的相關系數,在定義Series時,索引一定要和df索引一樣
In [45]: obj=Series([8,24,23],index=['a','b','c'])
In [46]: obj
Out[46]:
a 8
b 24
c 23
dtype: int64
In [47]: df.corrwith(obj)
Out[47]:
one 0.836784
two 0.836784
three 0.836784
dtype: float64
注意:在使用DataFrame或Series在計算相關系數或者協方差的時候,都會計算索引重疊的、非NA的、按照索引對齊原則,對於無法對齊的索引會使用NA值進行填充。在使用DataFrame與指定的行或列或Series計算協方差和相關系數的時候,默認都是與DataFrame的列進行計算,如果想要計算行,設置axis參數為1即可。
三.唯一值、值計數以及成員資格
還有一類方法可以從一維Series的值中抽取信息。以下面這個Series為例:
In [50]: obj=Series(['c','a','d','a','a','c','c','b','b'])
In [51]: obj
Out[51]:
0 c
1 a
2 d
3 a
4 a
5 c
6 c
7 b
8 b
dtype: object
第一個函數是unique,它可以得到Series中的唯一值數組:
In [52]: uniques=obj.unique()
In [53]: uniques
Out[53]: array(['c', 'a', 'd', 'b'], dtype=object)
返回的唯一值是未排序的,如果需要的話,可以對結果再次進行排序(uniques.sort())。value_counts用於計算一個Series各值出現的頻率:
In [54]: uniques.sort()
In [58]: uniques
Out[58]: array(['a', 'b', 'c', 'd'], dtype=object)
In [60]: obj.value_counts()
Out[60]:
a 3
c 3
b 2
d 1
dtype: int64
為了便於查看,結果Series是按值頻率降序排列的。value_counts還是一個頂級pandas方法,可用於任何數組或序列:
In [61]: pd.value_counts(obj.values,sort=False)
Out[61]:
d 1
c 3
b 2
a 3
dtype: int64
最后是isin,它用於判斷矢量化集合的成員資格,可用於選取Series中或DataFrame列中數據的子集:
In [63]: mask=obj.isin(['b','c'])
In [64]: mask
Out[64]:
0 True
1 False
2 False
3 False
4 False
5 True
6 True
7 True
8 True
dtype: bool
In [65]: obj[mask]
Out[65]:
0 c
5 c
6 c
7 b
8 b
dtype: object
下表為唯一值,值計數,成員資格方法
方法 說明
isin 計算一個表示"Series各值是否包含於傳入的值序列中"的布爾型數組
unique 計算Series中的唯一值數組,按發現的順序返回
value_counts 返回一個Series,其索引為唯一值,其值為頻率,按計數值降序排列
四.處理缺失數據
缺失數據(missing data)在大部分數據分析應用中都很常見,pandas的設計目標之一就是讓缺失數據的處理任務盡量輕松。例如,pandas對象上的所有描述統計都排除了缺失數據,正如我們在本章稍早的地方所看到的那樣。
pandas使用浮點值NaN(Not a Number)表示浮點和非浮點數組中的缺失數據。它只是一個便於被檢測出來的標記而已:
In [66]: s=Series(['Calvin','Kobe',np.nan,'Michale'])
In [67]: s
Out[67]:
0 Calvin
1 Kobe
2 NaN
3 Michale
dtype: object
In [68]: s.isnull()
Out[68]:
0 False
1 False
2 True
3 False
dtype: bool
Python內置的None值也會被當做NA處理:
In [69]: s[0]=None
In [70]: s.isnull()
Out[70]:
0 True
1 False
2 True
3 False
dtype: bool
不敢說pandas的NA表現形式是最優的,但它確實很簡單也很可靠。由於Numpy的數據類型體系中缺乏真正的NA數據類型或位模式,所以它是能想到的最佳解決方案(一套簡單的API以及足夠全面的性能特征)。隨着Numpy的不斷發展,這個問題今后可能會發生變化。
下表為NA處理方法
方法 說明
dropna 根據各標簽的值中是否存在缺失數據對軸標簽進行過濾,可通過閾值調節對缺失值的容忍度
fillna 用指定值或插值方法(如ffill或bfill)填充缺失數據
isnull 返回一個含有布爾值的對象,這些布爾值表示哪些值是缺失值NA,該對象的類型與源類型一樣
notnull isnull的否定式
1.濾除缺失數據
過濾掉缺失數據的辦法有很多種。純手工操作永遠都是一個辦法,但dropna可能會更實用一些。對於一個Series,dropna返回一個僅含非空數據和索引值的Series:
In [71]: from numpy import nan as NA
In [72]: data=Series([1,NA,5.5,NA,24])
In [73]: data.dropna()
Out[73]:
0 1.0
2 5.5
4 24.0
dtype: float64
當然,也可以通過布爾型索引達到這個目的:
In [74]: data[data.notnull()]
Out[74]:
0 1.0
2 5.5
4 24.0
dtype: float64
而對於DataFrame對象,事情就有點復雜了,你可能希望丟棄全NA或含有NA的行或列。dropna默認丟棄任何含有缺失值的行:
In [75]: data=DataFrame([[1,3,8.5],[1.4,NA,NA],[NA,NA,NA],[NA,8.8,3]])
In [77]: cleaned=data.dropna()
In [78]: data
Out[78]:
0 1 2
0 1.0 3.0 8.5
1 1.4 NaN NaN
2 NaN NaN NaN
3 NaN 8.8 3.0
In [79]: cleaned
Out[79]:
0 1 2
0 1.0 3.0 8.5
傳入how='all'將只丟棄全為NA的那些行:
In [80]: cleaned=data.dropna(how='all')
In [81]: cleaned
Out[81]:
0 1 2
0 1.0 3.0 8.5
1 1.4 NaN NaN
3 NaN 8.8 3.0
要用這種方式丟棄列,只需傳入axis=1即可:
In [82]: data[4]=NA
In [83]: data
Out[83]:
0 1 2 4
0 1.0 3.0 8.5 NaN
1 1.4 NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN 8.8 3.0 NaN
In [84]: data.dropna(axis=1,how='all')
Out[84]:
0 1 2
0 1.0 3.0 8.5
1 1.4 NaN NaN
2 NaN NaN NaN
3 NaN 8.8 3.0
另一個濾除DataFrame行的問題涉及時間序列數據。假設你只想留下一部分觀測數據,可以用thresh參數實現此目的:
In [85]: df=DataFrame(np.random.randn(7,3))
In [86]: df.iloc[:4,1]=NA;df.iloc[:2,2]=NA
In [87]: df
Out[87]:
0 1 2
0 -0.361517 NaN NaN
1 -0.527158 NaN NaN
2 0.126102 NaN -2.513174
3 -0.585159 NaN -2.297443
4 1.030365 -0.192859 0.251283
5 -1.505839 -0.057001 0.193328
6 -1.102120 1.768084 0.280802
In [88]: df.dropna(thresh=3)
Out[88]:
0 1 2
4 1.030365 -0.192859 0.251283
5 -1.505839 -0.057001 0.193328
6 -1.102120 1.768084 0.280802
2.填充缺失數據
我們可能不想濾除缺失數據(有可能會丟棄跟它有關的其他數據),而是希望通過其他方式填補那些“空洞”。對於大多數情況而言,fillna方法是最主要的函數。通過一個常數調用fillna就會將缺失值替換為那個常數值:
In [89]: df.fillna(0)
Out[89]:
0 1 2
0 -0.361517 0.000000 0.000000
1 -0.527158 0.000000 0.000000
2 0.126102 0.000000 -2.513174
3 -0.585159 0.000000 -2.297443
4 1.030365 -0.192859 0.251283
5 -1.505839 -0.057001 0.193328
6 -1.102120 1.768084 0.280802
若是通過一個字典調用fillna,就可以實現對不同的列填充不同的值:
In [91]: df.fillna({1:0.5,2:-1}) #第二列NaN值填充為0,第二列的NaN值填充為-1
Out[91]:
0 1 2
0 -0.361517 0.500000 -1.000000
1 -0.527158 0.500000 -1.000000
2 0.126102 0.500000 -2.513174
3 -0.585159 0.500000 -2.297443
4 1.030365 -0.192859 0.251283
5 -1.505839 -0.057001 0.193328
6 -1.102120 1.768084 0.280802
fillna默認會返回新對象,但也可以對現有對象進行就地修改:
#總是返回被填充對象的引用
In [92]: _=df.fillna(0,inplace=True)
In [93]: df
Out[93]:
0 1 2
0 -0.361517 0.000000 0.000000
1 -0.527158 0.000000 0.000000
2 0.126102 0.000000 -2.513174
3 -0.585159 0.000000 -2.297443
4 1.030365 -0.192859 0.251283
5 -1.505839 -0.057001 0.193328
6 -1.102120 1.768084 0.280802
對reindex有效的那些插值方法也可用與fillna:
In [94]: df=DataFrame(np.random.randn(6,3))
In [95]: df.iloc[2:,1]=NA;df.iloc[4:,2]=NA
In [96]: df
Out[96]:
0 1 2
0 -0.098323 -2.351729 1.333503
1 0.006153 0.344866 0.729309
2 1.830895 NaN -1.002160
3 -0.573513 NaN 0.436669
4 -1.499363 NaN NaN
5 -1.371960 NaN NaN
In [97]: df.fillna(method='ffill')
Out[97]:
0 1 2
0 -0.098323 -2.351729 1.333503
1 0.006153 0.344866 0.729309
2 1.830895 0.344866 -1.002160
3 -0.573513 0.344866 0.436669
4 -1.499363 0.344866 0.436669
5 -1.371960 0.344866 0.436669
In [98]: df.fillna(method='ffill',limit=2)
Out[98]:
0 1 2
0 -0.098323 -2.351729 1.333503
1 0.006153 0.344866 0.729309
2 1.830895 0.344866 -1.002160
3 -0.573513 0.344866 0.436669
4 -1.499363 NaN 0.436669
5 -1.371960 NaN 0.436669
只要稍微動動腦子,我們就可以利用fillna實現許多別的功能。比如說,你可以傳入Series的平均值或中位數:
In [99]: data=Series([1,NA,5.6,NA,8])
In [100]: data.fillna(data.mean())
Out[100]:
0 1.000000
1 4.866667
2 5.600000
3 4.866667
4 8.000000
dtype: float64
下表是fillna函數的參數
參數 說明
value 用於填充缺失值的標量值或字典對象
method 插值方式。如果函數調用時未指定其他參數的話,默認為"ffill"
axis 待填充的軸,默認axis=0
inplace 修改調用者對象而不產生副本
limit (對於前向和后向)填充可以連續填充的最大數量
