1. 程式人生 > >第3章 Pandas資料處理(3.4-3.5)_Python資料科學手冊學習筆記

第3章 Pandas資料處理(3.4-3.5)_Python資料科學手冊學習筆記

3.4 Pandas 數值運算方法

對於一元運算(像函式與三角函式),這些通用函式將在輸出結果中保留索引和列標籤; 而對於二元運算(如加法和乘法), Pandas在傳遞通用函式時會自動對齊索引進行計算. 這就意味著,儲存資料內容和組合不同來源的資料—兩處在NumPy陣列中容易出錯的地方,變成了Pandas的殺手鐗.

3.4.1 通用函式: 保留索引

因為Pandas是建立在NumPy基礎之上的, 所以NumPy的通用函式也同樣適用於Pandas的Series和DataFrame.

import pandas as pd
import numpy as np
rng = np.random.RandomState(
42) ser = pd.Series(rng.randint(0,10,4)) ser
0    6
1    3
2    7
3    4
dtype: int32
df = pd.DataFrame(rng.randint(0,10,(3,4)),columns=['a','b','c','d'])   # 列標籤只有4個,必須和陣列列數量一致
df
a b c d
0 6 9 2 6
1 7 4 3 7
2 7 2 5 4

3.4.2 通用函式: 索引對齊

當在兩個Series或DataFrame物件進行二元計算時, Pandas會在計算過程中對齊兩個物件的索引.

Series索引對齊

rk = pd.Series({'湖北':1234,'湖南':3242,'廣東':3233},name='人口')    # Series有個name屬性, 可以作為DataFrame列名稱嗎
mj = pd.Series({'湖北':123,'湖南'
:321,'山東':21},name='面積') rk /mj
山東          NaN
廣東          NaN
湖北    10.032520
湖南    10.099688
dtype: float64

結果陣列的索引是兩個陣列的並集. 也可以用另一種運演算法則

rk.index | mj.index
Index(['山東', '廣東', '湖北', '湖南'], dtype='object')
a = pd.Series([2,4,6],index=[0,1,2])
b = pd.Series([1,3,5],index=[1,2,3])
a + b
# 為什麼不把缺失的當0處理呢?
0    NaN
1    5.0
2    9.0
3    NaN
dtype: float64
a | b   # a 並 b 表示什麼意思
0     True
1     True
2     True
3    False
dtype: bool
a & b  # a 交 b 表示什麼意思
0    False
1    False
2    False
3    False
dtype: bool
a ^ b
0     True
1     True
2     True
3    False
dtype: bool
a * b
0     NaN
1     4.0
2    18.0
3     NaN
dtype: float64
a.add(b,fill_value=0)  # 缺失值當0處理
0    2.0
1    5.0
2    9.0
3    5.0
dtype: float64

DataFrame索引對齊
在計算兩個DataFrame時, 類似的索引對齊規則同樣會出現在共同列

A = pd.DataFrame(rng.randint(0,20,(2,2)),columns=list("AB"))
# 生成一個2*2的陣列,數值都小於20. DataFrame列用list('AB')生成
B = pd.DataFrame(rng.randint(0,20,(3,3)),columns=list('ABC'))
print(A)
print('*'*20)
print(B)
print('*'*20)
print(A+B)
   A   B
0  1  11
1  5   1
********************
    A   B   C
0   0  11  11
1  16   9  15
2  14  14  18
********************
      A     B   C
0   1.0  22.0 NaN
1  21.0  10.0 NaN
2   NaN   NaN NaN

處理方法一: 用A中所有值得均值來填充缺失值. 計算A的均值需要用stack將二維陣列壓縮成一維陣列

fill = A.stack().mean()
print(fill)
A.add(B,fill_value=fill)
# 比較下維度差,A陣列缺的位置,都用均值填充
4.5
A B C
0 1.0 22.0 15.5
1 21.0 10.0 19.5
2 18.5 18.5 22.5

Python運算子和Pandas方法的對映關係(下面必須空一行)

Python運算子 Pandas方法
+ add()
- sub(),subtract()
* mul(),multiply()
/ truediv(),div(),divide()
// floordiv()
% mod()
** pow()

3.4.3 通用函式: DataFrame與Series的運算

一個二維陣列減去自身的一行資料

rng = np.random.RandomState(42)
a = rng.randint(10,size=(3,4))
print(type(a))
a
<class 'numpy.ndarray'>





array([[6, 3, 7, 4],
       [6, 9, 2, 6],
       [7, 4, 3, 7]])
a - a[0]     # 0 表示第1行  
array([[ 0,  0,  0,  0],
       [ 0,  6, -5,  2],
       [ 1,  1, -4,  3]])
df = pd.DataFrame(a,columns=list('QRST'))
pd.DataFrame(a,columns=['q','r','s','t'])
pd.DataFrame(a,columns=('a','b','c','d'))
print(df)
   Q  R  S  T
0  6  3  7  4
1  6  9  2  6
2  7  4  3  7

一個DataFrame減去自身第1行

print(df-df.iloc[0])
print(df.subtract(df['R'],axis=0)   #此句報錯, 可能是2.7 和3.+版本不相容問題
  File "<ipython-input-49-0b4659832f8f>", line 2
    print(df.subtract(df['R'],axis=0)
                                     ^
SyntaxError: unexpected EOF while parsing

3.5 處理缺失值

三種方法: null, NaN 和NA.

識別缺失值的方法: 通過一個覆蓋全域性的掩碼表示缺失值, 另一種方法用一個標籤紙表示.

3.5.2 Pandas的缺失值

Pandas最終選擇用標籤方法表示缺失值, 包括兩種Python原有的缺失值: 浮點資料型別的NaN值, 以及Python的None物件. 後面我們將會發現,雖然這麼做也有一些副作用, 但是在實際運用中夠用.

None: Python物件型別的缺失值
- None是一個Python單體物件, 經常在程式碼中表示缺失值. 由於None是一個Python物件, 所以不能作為任何NumPy/Pandas陣列型別的缺失值, 只能用於’object’資料型別(即由Python物件構成的陣列). 什麼意思?

x1 = np.array([1,None,3,4])
x1
array([1, None, 3, 4], dtype=object)

使用Python物件構成的陣列就意味著你對一個包含None的陣列進行累計操作,如sum()和min(),通常會報錯: 為什麼?

x1.sum()
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-52-0c8c176901d3> in <module>()
----> 1 x1.sum()


D:\Anaconda3\lib\site-packages\numpy\core\_methods.py in _sum(a, axis, dtype, out, keepdims)
     30 
     31 def _sum(a, axis=None, dtype=None, out=None, keepdims=False):
---> 32     return umr_sum(a, axis, dtype, out, keepdims)
     33 
     34 def _prod(a, axis=None, dtype=None, out=None, keepdims=False):


TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

NaN: 數值型別的缺失值
- NaN(全程 Not a Number), 在任何系統中都相容的特殊浮點數

x2 = np.array([1,np.nan,3,4])    # 要寫成 np.nan
x2.dtype
dtype('float64')

NaN就像病毒一樣會將它接觸過的資料同化

1 + np.nan
nan
0 + np.nan
nan
x2.sum(),x2.max(),x2.min()
(nan, nan, nan)

NumPy也提供了一些特殊的累計函式, 可以忽略缺失值的影響

np.nansum(x2), np.nanmin(x2), np.nanmax(x2)
#  x2.nansum()   報錯
(8.0, 1.0, 4.0)

Pandas中NaN與None的差異
- Pandas把它們看成是可以等價交換的, 在適當的時候會將兩者進行替換.
- Pandas會將沒有標籤值得資料型別自動轉換成NA

3.5.3 處理缺失值

發現,剔除,替換資料中的缺失值的方法:
- isnull(), 建立一個布林型別的掩碼標籤缺失值
- notnull(), 與isnull()相反的操作
- dropna(), 返回一個剔除缺失值的資料
- fillna(), 返回一個填充了缺失值的資料副本

發現缺失值
- Pandas中有兩種有效的方法可以發現缺失值: isnull()和notnull(),都返回布林型別的掩碼資料.

data = pd.Series([1,np.nan,'Hello',None])
data.isnull()
0    False
1     True
2    False
3     True
dtype: bool
data[data.notnull()]
0        1
2    Hello
dtype: object

剔除缺失值
- dropna(),剔除缺失值
- fillna(),填充缺失值

data.dropna()
0        1
2    Hello
dtype: object

而在DataFrame上使用時需要設定一些引數

df = pd.DataFrame([[1,np.nan,2],
                 [2,3,5],
                 [np.nan,4,6]])
df
0 1 2
0 1.0 NaN 2
1 2.0 3.0 5
2 NaN 4.0 6

沒法從DataFrame中單獨剔除一個值, 要麼是剔除缺失值所在的整行,要麼是整列. 根據實際需求.
- 預設情況下,dropna(),會剔除任何包含缺失值的整行資料

df.dropna()
0 1 2
1 2.0 3.0 5

可以設定引數 axis=1 剔除任何包含缺失值的整列資料

df.dropna(axis=1)
2
0 2
1 5
2 6
df[3] = np.nan    # 增加第4列,都為缺失值
df
0 1 2 3
0 1.0 NaN 2 NaN
1 2.0 3.0 5 NaN
2 NaN 4.0 6 NaN
df.dropna(axis='columns',how='all')    #  如果某一個列全為缺失值,則刪除 ,how的引數還可以等於any, 預設是any
0 1 2
0 1.0 NaN 2
1 2.0 3.0 5
2 NaN 4.0 6

還可以通過引數thresh設定非缺失值的最小數量

填充缺失值

data = pd.Series([1,np.nan,2,None,3],index=list("abcde"))
data
a    1.0
b    NaN
c    2.0
d    NaN
e    3.0
dtype: float64

用一個單獨的值來填充缺失值,比如0或者100

data.fillna(0)
data.fillna(100)
a      1.0
b    100.0
c      2.0
d    100.0
e      3.0
dtype: float64

可以用缺失值前面的有效值來從前往後填充

# 從前往後填充
data.fillna(method='ffill')
a    1.0
b    1.0
c    2.0
d    2.0
e    3.0
dtype: float64
# 從後往前填充
data.fillna(method='bfill')
a    1.0
b    2.0
c    2.0
d    3.0
e    3.0
dtype: float64

注意: 如果從前往後填充時, 需要填充的缺失值前面沒有值, 那麼它就仍然是缺失值.