天天看點

Task07|缺失資料|DataWhale組隊學習第七章 缺失資料

目錄

    • 一、缺失值的統計和删除
      • 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

           
這裡是引用