python3 科學計算之pandas入門(四)


一.匯總和計算描述統計

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                  (對於前向和后向)填充可以連續填充的最大數量


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM