目錄
-
- 一、缺失值的統計和删除
-
- 1. 缺失資訊的統計
- 2. 缺失資訊的删除
- 二、缺失值的填充和插值
-
- 1. 利用fillna進行填充
-
- 【練一練】
- 2. 插值函數
-
- 【NOTE】關于polynomial和spline插值的注意事項
- 三、Nullable類型
-
- 1. 缺失記号及其缺陷
- 2. Nullable類型的性質
- 3. 缺失資料的計算和分組
- 四、練習
-
- Ex1:缺失值與類别的相關性檢驗
第七章 缺失資料
```python import numpy as np import pandas as pd ```
一、缺失值的統計和删除
1. 缺失資訊的統計
缺失資料可以使用
isna
或
isnull
(兩個函數沒有差別)來檢視每個單元格是否缺失,結合
mean
可以計算出每列缺失值的比例:
df = pd.read_csv('../data/learn_pandas.csv', usecols = ['Grade', 'Name', 'Gender', 'Height', 'Weight', 'Transfer'])
df.isna().head()
df.isna().mean() # 檢視缺失的比例
df[df.Height.isna()].head()
df[df.Height.notna()].head()
sub_set=df[['Height','Weight','Transfer']]
df[sub_set.isna().all(1)]#全部缺失
df[sub_set.isna().any(1)].head() # 至少有一個缺失
df[sub_set.notna().all(1)].head()
#沒有缺失
2. 缺失資訊的删除
dropna
的主要參數為軸方向
axis
(預設為0,即删除行)、删除方式
how
、删除的非缺失值個數門檻值
thresh
( 非缺失值 \color{red}{非缺失值} 非缺失值沒有達到這個數量的相應次元會被删除)、備選的删除子集
subset
,其中
how
主要有
any
和
all
兩種參數可以選擇。
res=df.dropna(how='any',subset=['Height','Weight'])
res.shape
#使用布爾索引
res=df.loc[df[['Height','Weight']].notna().all(1)]
res.shape
#删除超過15個缺失值的列:
res=df.dropna(1,thresh=df.shape[0]-15)
# 身高被删除 thresh門檻值
res.head()
res=df.loc[:,~(df.isna().sum()>15)]
res.head()
二、缺失值的填充和插值
1. 利用fillna進行填充
在fillna有三個參數是經常使用的
value,method,limit
value
為填充值,可以是标量,也可以是索引到元素的字典映射
method
為填充方法,有用前面的元素填充
ffill
和用後面的元素填充
bfill
兩種類型
limit
參數表示連續缺失值的最大填充次數。
s=pd.Series([np.na])
#缺失值的填充和插值
s=pd.Series([np.nan,1,np.nan,np.nan,2,np.nan],list('aabcdf'))
s
s.fillna(method='ffill')
s.fillna(method='bfill')
s.fillna(s.mean())
s.fillna({'a':100,'d':200,'f':300})
#通過索引映射填充的值
#通過分組,根據年級進行身高的均值填充
df.groupby('Grade')['Height'].transform(lambda x:x.fillna(x.mean())).head()
【練一練】
對一個序列以如下規則填充缺失值:如果單獨出現的缺失值,就用前後均值填充,如果連續出現的缺失值就不填充,即序列
[1, NaN, 3, NaN, NaN]
填充後為
[1, 2, 3, NaN, NaN]
,請利用
fillna
函數實作。(提示:利用
limit
參數)
temps=pd.Series([1,np.nan,3,np.nan,np.nan,np.nan])
s1=temps.fillna(method='ffill',limit=1)
s2=temps.fillna(method='bfill',limit=1)
print(s2)
print(s1)
s_new=(s1+s2)/2
print(s_new)
#總結一個函數
def convert_series(s):
s1=s.fillna(method='ffill',limit=1)
s2=s.fillna(method='bfill',limit=1)
s_new=(s1+s2)/2
return s_new
s_new2=convert_series(pd.Series([1,np.nan,3,np.nan,np.nan]))
print(s_new2)
2. 插值函數
插值函數文檔,interpolate 文檔
列舉了許多插值方法,引用了大量
Scipy
中的方法
線性插值,最近鄰插值,索引插值
對于
interpolate
而言,除了插值方法(預設為
linear
線性插值)之外
有與
fillna
類似的兩個常用參數
- 一個是控制方向的
limit_direction
- 是控制最大連續缺失值插值個數的
。limit
限制插值的方向預設為
forward
,與
method
中的
ffill
backword
對應與
bfill
雙向限制插值
both
s=pd.Series([np.nan,np.nan,1,np.nan,np.nan,np.nan,2,np.nan,np.nan])
s.values
res=s.interpolate(limit_direction='backward',limit=1)
res.values
#array([ nan, 1. , 1. , nan, nan, 1.75, 2. , nan, nan])
#後向限制插值
# res=s.interpolate(li)
#雙向限制插值
res=s.interpolate(limit_direction='both',limit=1)
res
#array([ nan, 1. , 1. , 1.25, nan, 1.75, 2. , 2. , nan])
#鄰近插值
res=s.interpolate('nearest').values
res
#array([nan, nan, 1., 1., 1., 2., 2., nan, nan])
#索引插值
s=pd.Series([0,np.nan,10],index=[0,1,10])
res=s.interpolate()
print(res.values)
#[ 0. 5. 10.]
#預設的線性插值等于計算中點的值
s.interpolate(method='index')
#和索引有關的線性插值,計算相應索引大小對應的值
#array([ 0., 1., 10.])
#對于時間戳索引有關的值
s=pd.Series([0,np.nan,10,np.nan],index=pd.to_datetime(['20200101','20200102','20200111','20200222']))
s
# 2020-01-01 0.0
# 2020-01-02 NaN
# 2020-01-11 10.0
s.interpolate()
# 2020-01-01 0.0
# 2020-01-02 5.0
# 2020-01-11 10.0
s.interpolate(method='index')
# 2020-01-01 0.0
# 2020-01-02 1.0
# 2020-01-11 10.0
# 2020-02-22 10.0
# dtype: float64
【NOTE】關于polynomial和spline插值的注意事項
interpolate polynomial 是樣條插值
interpolate spine Univariate Spline 不是普通的樣條插值
在
interpolate
中如果選用
polynomial
的插值方法,它内部調用的是
scipy.interpolate.interp1d(*,*,kind=order)
,這個函數内部調用的是
make_interp_spline
方法,是以其實是樣條插值而不是類似于
numpy
中的
polyfit
多項式拟合插值;而當選用
spline
方法時,
pandas
調用的是
scipy.interpolate.UnivariateSpline
而不是普通的樣條插值。這一部分的文檔描述比較混亂,而且這種參數的設計也是不合理的,當使用這兩類插值方法時,使用者一定要小心謹慎地根據自己的實際需求選取恰當的插值方法。
三、Nullable類型
1. 缺失記号及其缺陷
python中的缺失值使用
None
表示
#1. python中缺失值用None表示,與其他元素不相等
None == None
#True
None==False
#False
None==[]
#False
None==''
#False
#2。 numpy 中利用np.nan表示缺失值,自己也不等
np.nan=np.nan
#False
np.nan==None
#False
np.nan==False
#False
s1=pd.Series([1,np.nan])
s2=pd.Series([1,np.nan,np.nan])
s3=pd.Series([1,np.nan])
s4=pd.Series([1,2])
s1==1
#會進行廣播然後比較
# 0 True
# 1 False
s1.equals(s2)
#False
s1.equals(s3)
#True
s1.equals(s4)
#False
#3. 在時間序列對象中,pandas使用pd.NaT指代缺失值(作用與np.nan一緻)
pd.to_timedelta(['30s',np.nan])
#Timedelta中的naT
#TimedeltaIndex(['0 days 00:00:30', NaT], dtype='timedelta64[ns]', freq=None)
pd.to_datetime(['20200101',np.nan])
#Datetime中的naT
#DatetimeIndex(['2020-01-01', 'NaT'], dtype='datetime64[ns]', freq=None)
#為什麼引入pd.NaT 表示時間對象中的缺失值
#np.nan有什麼問題
#出現多個類型元素同時存儲在Series的時候類型就會變為object#object是一種混雜對象類型
pd.Series([1,'two'])
# 0 1
# 1 two
# dtype: object
type(np.nan)
#float
#NaT問題的根源來自于np.nan本身是一種浮點類型
#如果浮點類型和時間類型混合存儲,不涉及新的内置缺失類型來處理,就會變成含糊不清的object類型
#由于np.nan浮點類型,如果在一個整數的Series出現缺失,類型會轉變為float64
#如果在一個布爾類型的序列出現缺失類型會轉變為object而不是bool
pd.Series([1,np.nan]).dtype
#dtype('float')
pd.Series([True,False,np.nan]).dtype
#dtype('O')
#1.0.0後pandas引入缺失類型pd.NA,以及三種Nullable序列類型來對這些缺陷
#Int,boolean和string
2. Nullable類型的性質
Nullable
是可空的,序列不受缺失值的影響
在上述
Nullable
類型中存儲缺失值會轉為pandas 内置的
pd.NA
s=pd.Series([np.nan,1],dtype='Int64')
print(s)
# 0 <NA>
# 1 1
# dtype: Int64
pd.Series([np.nan,True],dtype='boolean')
# 0 <NA>
# 1 True
# dtype: boolean
pd.Series([np.nan,'my_str'],dtype='string')
# 0 <NA>
# 1 my_str
# dtype: string
pd.Series([np.nan, 0], dtype = 'Int64') + 1
# 0 <NA>
# 1 1
# dtype: Int64
pd.Series([np.nan, 0], dtype = 'Int64') == 0
# 0 <NA>
# 1 True
# dtype: boolean
pd.Series([np.nan, 0], dtype = 'Int64') * 0.5 # 隻能是浮點
# 0 NaN
# 1 0.0
# dtype: float64
#對于boolean序列,與bool序列的行為是
#1. `boolean`會把缺失值看作`False
#帶有缺失的布爾清單無法進行索引器中的選擇
s=pd.Series(['a','b'])
s_bool=pd.Series([True,np.nan])
s_boolean=pd.Series([True,np.nan]).astype('boolean')
s[s_boolean]
# s[s_bool]# 報錯
#2. 進行邏輯運算的時候bool類型在缺失值出永遠傳回False
# boolean根據邏輯運算是否能夠确定唯一結果來傳回相應的值
#True|pd.NA傳回True,False|pd.NA 傳回pd.NA
#False&pd.NA傳回False,pd.NA&True傳回pd.NA
#~pd.NA傳回pd.NA
~s_boolean
s_boolean&True
s_boolean|True
#關于string在文本資料讨論
#實際資料處理時,可以在資料集讀入之後,先通過convert_dtypes轉為Nullable類型
df=pd.read_csv('../data/learn_pandas.csv')
df=df.convert_dtypes()#将資料類型轉換為Nullable類型
df.dtypes
3. 缺失資料的計算和分組
當調用函數
sum,prod
使用加法和乘法的時候,缺失資料等價于被視作0和1,不改變原來的計算結果
s=pd.Series([2,3,np.nan,4,5])
s.sum()
#14
s.prod()
#120
#使用累計函數的時候,自動跳過缺失值所在的位置
s.cumsum()
#0 2.0
# 1 5.0
# 2 NaN
# 3 9.0
# 4 14.0
#進行單個标量計算的時候,除了np.nan **0 和1**np.nan
#所有運算結果全為缺失
np.nan**0#1.0
1**np.nan#1.0
#np.nan比較操作的時候一定傳回False, pd.NA傳回pd.NA
np.nan==0
#False
pd.NA==0
#<NA>
np.nan>0
#False
pd.NA>0
#<NA>
np.nan+1
#nan
np.log(np.nan)
#nan
np.add(np.nan,1)
#nan
np.nan**0
#1.0
1**np.nan
#1.0
pd.NA**0
#1
1**pd.NA
#1
#diff參與缺失值計算的部分全部設定為缺失值
#pct_change缺失值位置會被設定為0%的變化率
s.diff()
# 0 NaN
# 1 1.0
# 2 NaN
# 3 NaN
# 4 1.0
# dtype: float64
s.pct_change()
# 0 NaN
# 1 0.500000
# 2 0.000000
# 3 0.333333
# 4 0.250000
# dtype: float64
#對于一些函數而言,缺失可以作為一個類别處理,
#在groupby,get_dummies中可以設定相應的參數來進行增加确實類别
df_nan=pd.DataFrame({'category':['a','a','b',np.nan,np.nan],
'value':[1,3,5,7,9]})
df_nan
# category value
# 0 a 1
# 1 a 3
# 2 b 5
# 3 NaN 7
# 4 NaN 9
df_nan.groupby('category',dropna=False)['value'].mean()
#pandas版本大于1.1.0
# category
# a 2
# b 5
# NaN 8
pd.get_dummies(df_nan.category,dummy_na=True)
# 在`groupby, get_dummies`中可以設定相應的參數來進行增加缺失類别
# a b NaN
# 0 1 0 0
# 1 1 0 0
# 2 0 1 0
# 3 0 0 1
# 4 0 0 1
四、練習
Ex1:缺失值與類别的相關性檢驗
在資料進行中,含有過多缺失值的列往往會被删除,除非缺失情況與标簽強相關。下面有一份關于二分類問題的資料集,其中
X_1, X_2
為特征變量,
y
為二分類标簽。
df = pd.read_csv('../data/missing_chi.csv')
df.head()
# X_1 X_2 y
# 0 NaN NaN 0
# 1 NaN NaN 0
# 2 NaN NaN 0
# 3 43.0NaN 0
# 4 NaN NaN 0
df.isna().mean()
# X_1 0.855
# X_2 0.894
# y 0.000
# dtype: float64
df.y.value_counts(normalize=True)
# 0 0.918
# 1 0.082
# Name: y, dtype: float64
這裡是引用