一、缺失預測及其類型
- 瞭解缺失值信息
- df.isna() #或者df.列名.isna()
- df.info()
- df.notna()# 非空信息
- df[~df.列名.isna()] 對空取反操作,就是找非空
- 求缺失個數 df.isna().sum()
- 通過布爾值選擇缺失值所在行 df[df.列名.isna()]
- 選擇所有非缺失值列 df[df.notna().all(1)] 就是每一列都沒有缺失值,相當於尋找一條完整記錄。
- 三種缺失值符號
- np.nan 特點
- 浮點類型的數據,填充np.nan後會變爲object類型
- 修改布爾列表時,會改變列表類型,s=pd.Series([True,False],dtype='bool') s[1]=np.nan dtype 爲float
- 對於布爾類型,如果事np.nan填充,值會變爲True pd.Series([1,np.nan,3],dtype='bool') True True True
- 整數列,如果存在缺失值就會變成浮點型pd.Series([1,2,3]) .dtype int64 pd.Series([1,np.nan,3]).dtype flost64
- 在numpy中,np.nan的類型爲float,可以通過type(np.nan)得到
- 在使用equals時,自動掠奪兩側全是空值的單元,df.equals(df)會得到True
- np.nan 不等於None
- np.nan 不等於0
- 自身不等於自身
- None
- None==None True
- 布爾值爲False
- 修改布爾值時,不改變數據類型
- 傳入數值後,自動變爲np.nan
- 傳入object類型時保持不變
- 使用equals函數時不會掠過,pd.Series([None]).equals(pd.Series([np.nan])
- NaT
- NaT是針對時間序列的缺失值,是pandas的內置類型,時序版本的np.nan與自己不等,使用equals是也會被跳過
- pd.Series([pd.Timestamp('20200202')]*5) datetime64[ns]類型
- 爲datetime64添加空值,類型爲NaT pd.NaT
- None NaT np.nan 在datetime類型中都是NaT
- pd.NaT==pd.NaT false
- pd.NaT.equals(pd.NaT)
- np.nan 特點
- Nullable類型與Na符號
- Nullable 是1.0新本中引入的,目的是爲了統一缺失值處理方法。
- 整型 s_new=pd.Series([1,2],dtype='Int64) 更新後的是使用大寫Int,在這個基礎上無論是np.nan None還是pd.NaT最後都是顯示<NA> 不改變之前的類型;
- 布爾 s_new=pd.Series([0,1],dtype='boolean') 不改變類型
- string pd.Series(['dog','cat'],dtype='string) 添加缺失值,不會改變類型 <NA>
- Na的特性
- 邏輯運算
- 邏輯運算的結果根據是否依賴pd.NA的取值,依賴的話就是NA,不依賴的直接計算結果
- 算數運算和比較運算
- pd.NA**0 結果爲1
- 1**pd.NA 結果爲1
- 其他結果都是NA
- pd.NA+1 <NA>
- 'a'*pd.NA <NA>
- pd.NA==pd.NA <NA>
- pd.NA<2.5 <NA>
- 邏輯運算
- convert_dtype方法
- pd.read_csv(''路徑').convert_dtypes() 把數據轉化爲Nullable類型
二、缺失數據的運算與分組
- 使用加法時缺失值爲0 s.sum()
- 使用乘法缺失值爲1 s.prod()
- 使用累加函數時缺失值自動略過 s.cumsum()
- 使用累乘函數缺失值自動掠過 s.cumprod()
- 默認比較和前一個的比值 s.pct_change() 第一個值之前沒有值,結果爲NaN 缺失值一列爲0
- groupby時自動忽略缺失值的組
三、填充與剔除
- fillna方法
-
值填充與向前後填充
df.列名.fillna('missing')
df.列名.fillna(method='ffill')
df.列名.fillna(method='backfill')
-
- 填充中的對齊特性(不是特別懂)
- df_f=pd.DataFrame({'A':[1,3,np.nan],'B':[2,4,np.nan],'C':[3,5,np.nan]})
- df_f.fillna(df_f.mean())
- df_f.fillna(df_f.mean()[['A','B']]) 返回的結果沒有c,不會被填充
- dropna方法
- df.dropna(axis=0) 行
- df.dropna(axis=1) 列
- df.dropna(axis=1,how='all) 全部爲缺失值時去除
- df.dropna(axis=0,subset=['B','C']) 只爲BC兩列去除空值
四、插值
s.interpolate(method='linear', axis=0, limit=None, inplace=False, limit_direction='forward', limit_area=None, downcast=None, **kwargs)
s=pd.Series([1,10,15,-5,-2,np.nan,np.nan,28])
s
out:
0 1.0
1 10.0
2 15.0
3 -5.0
4 -2.0
5 NaN
6 NaN
7 28.0
dtype: float64
帶有多索引的只支持線性插值方法
- method
- linear :忽略索引,平等對待間隔。多值索引的唯一方法。
- time 時間索引,和索引無關
- pad 使用過去的值填充
-
s.interpolate(method='pad') Out[104]: 0 1.0 1 10.0 2 15.0 3 -5.0 4 -2.0 5 -2.0 6 -2.0 7 28.0
-
- ‘nearest’, ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’, ‘spline’, ‘barycentric’, ‘polynomial’
- ‘spline’和‘polynomial’需要添加order
df.interpolate(method='polynomial', order=5)
-
'krogh', 'piecewise_polynomial', 'spline', 'pchip', 'akima'
-
'from_derivatives'
- limit 表示最多插入多少個
- inplace
- limit_direction 表示插值方向,默認前向
- forward
- backword
- both
- limit_area 表示插值區域
問題1:如何刪除缺失值佔比超過25%的列?
方法一:
l=(df.isna().sum()/df.shape[0]).sort_values()>0.25 #先找到缺失值大於0.25的布爾值
df.drop(columns=l[l].index) l[l].index 找到男足條件的列
方法二:
df.dropna(axis=1,thresh=df.shape[0]*(1-0.25)) thresh 保留至少n個不爲空的 使用axis選擇行或者列
問題2:什麼是Nullable類型?請談談爲什麼要引入這個設計?
它是一種特殊的整型,是爲了解決pandas前幾個版本對於空值不統一的問題。
問題3 對於一份有缺失值的數據,可以採取哪些策略或方法深化對它的瞭解
- 判斷缺失值數量及特徵重要性再選擇策略;
- 對於不是特別重要的特徵且缺失數據量較大,考慮刪除特徵,dropna或者drop;
- 對於重要特徵,那麼考慮進行插值,除了本文所說的插值,也可以考慮使用決策樹等機器學習方法進行填補
練習
現有一份虛擬數據集,列類型分別爲string/浮點/整型,請解決如下問題:
- 請以列類型讀入數據,並選出C爲缺失值的行。
data=pd.read_csv('data/Missing_data_one.csv').convert_dtypes()
data[data.C.isna()]
A B C
1 not_NaN 0.700 <NA>
5 not_NaN 0.972 <NA>
11 not_NaN 0.736 <NA>
19 not_NaN 0.684 <NA>
21 not_NaN 0.913 <NA>
- 現需要將A中的部分單元轉爲缺失值,單元格中的最小轉換概率爲25%,且概率大小與所在行B列單元的值成正比。
total_b = data['B'].sum() min_b = data['B'].min() data['A'] = pd.Series(list(zip(data['A'].values ,data['B'].values))).apply(lambda x:x[0] if np.random.rand()>0.25*x[1]/min_b else np.nan) data.head()
現有一份缺失的數據集,記錄了36個人來自的地區、身高、體重、年齡和工資,請解決如下問題
- 統計各列缺失的比例並選出在後三列中至少有兩個非缺失值的
#讀入數據 d=pd.read_csv('data/Missing_data_two.csv').convert_dtypes() #查看各列缺失比例 d.isnull().sum()/d.shape[0] #後三列至少有兩個非缺失值的行 d[d.iloc[:,-3:].notna().sum(axis=1)>=2]
- 請結合身高列和地區列中的數據,對體重進行合理插值。
d3 = d2.copy() for name,group in d2.groupby('地區'): d2.loc[group.index,'體重'] = group[['身高','體重']].sort_values(by='身高')['體重'].interpolate() d2['體重'] = d2['體重'].round(decimals=2) d2.head() def set_missing_w(data): # 把已有的數值型特徵取出來丟進Random Forest Regressor中 df=data.copy() dis = {'A':'0','B':'1','C':'2'} df['地區'] = df['地區'].map(dis) w_df = df[['地區','身高', '體重']] # 分成已知體重和未知體重兩部分 known_w = w_df[w_df.體重.notnull()] unknown_w = w_df[w_df.體重.isna()] # y即目標體重 y = known_w.iloc[:, 2] # print(y) # X即特徵屬性值 X = known_w.iloc[:, :2] # print(X) # fit到RandomForestRegressor之中 rfr = RandomForestClassifier(random_state=0, n_estimators=2000, n_jobs=-1) rfr.fit(X, y.astype('int')) # 用得到的模型進行未知體重結果預測 predictedAges = rfr.predict(unknown_w.iloc[:,:2]) # 用得到的預測結果填補原缺失數據 df.loc[ (df.體重.isnull()), '體重' ] = predictedAges return df, rfr