機器學習中處理缺失值的9種方法
數據科學就是關于數據的。它是任何數據科學或機器學習項目的關鍵。在大多數情況下,當我們從不同的資源收集數據或從某處下載數據時,幾乎有95%的可能性我們的數據中包含缺失的值。我們不能對包含缺失值的數據進行分析或訓練機器學習模型。這就是為什么我們90%的時間都花在數據預處理上的主要原因。我們可以使用許多技術來處理丟失的數據。在這個文章中,我將分享處理數據缺失的9種方法,但首先讓我們看看為什么會出現數據缺失以及有多少類型的數據缺失。
不同類型的缺失值
缺失的值主要有三種類型。
- 完全隨機缺失(MCAR):當數據為MCAR時,如果所有觀測的缺失概率都相同,則一個變量完全隨機缺失,這意味著數據缺失與數據集中任何其他觀察到的或缺失的值完全沒有關系。換句話說,那些缺失的數據點是數據集的一個隨機子集。
- 丟失數據不是隨機的(MNAR):顧名思義,丟失的數據和數據集中的任何其他值之間存在某種關系。
- 隨機丟失(MAR):這意味著數據點丟失的傾向與丟失的數據無關,但與數據集中其他觀察到的數據有關。
數據集中缺少值的原因有很多。例如,在數據集的身高和年齡,會有更多年齡列中缺失值,因為女孩通常隱藏他們的年齡相同的如果我們準備工資的數據和經驗,我們將有更多的薪水中的遺漏值因為大多數男人不喜歡分享他們的薪水。在更大的情況下,比如為人口、疾病、事故死亡者準備數據,納稅人記錄通常人們會猶豫是否記下信息,并隱藏真實的數字。即使您從第三方資源下載數據,仍然有可能由于下載時文件損壞而丟失值。無論原因是什么,我們的數據集中丟失了值,我們需要處理它們。讓我們看看處理缺失值的9種方法。
這里使用的也是經典的泰坦尼克的數據集
讓我們從加載數據集并導入所有庫開始。
- import pandas as pd
- df=pd.read_csv("data/titanic.csv",usecols=['Age','Cabin','Survived'])
- df.isnull().mean()
- df.dtypes
運行上述代碼塊后,您將看到Age、Cabin和裝載裝載包含空值。Age包含所有整數值,而Cabin包含所有分類值。
1、均值、中值、眾數替換
在這種技術中,我們將null值替換為列中所有值的均值/中值或眾數。
平均值(mean):所有值的平均值
- def impute_nan(df,column,mean):
- df[column+'_mean']=df[column].fillna(mean) ##NaN -> mean
- impute_nan(df,'Age',df.Age.mean()) ##mean of Age(29.69)

中值(median):所有值的中心值
- def impute_nan(df,column,median):
- df[column+'_mean']=df[column].fillna(median)
- impute_nan(df,'Age',df.Age.median()) ##median of Age(28.0)

眾數(mode):最常見的值
- def impute_nan(df,column,mode):
- df[column+'_mean']=df[column].fillna(mode)
- impute_nan(df,'Age',df.Age.mode()) ##mode of Age(24.0)

優點
- 易于實現(對異常值健壯)
- 獲得完整數據集的更快方法
缺點
- 原始方差的變化或失真
- 影響相關性
- 對于分類變量,我們需要眾數。平均值和中位數都不行。
2、隨機樣本估算
在這種技術中,我們用dataframe中的隨機樣本替換所有nan值。它被用來輸入數值數據。我們使用sample()對數據進行采樣。在這里,我們首先取一個數據樣本來填充NaN值。然后更改索引,并將其替換為與NaN值相同的索引,最后將所有NaN值替換為一個隨機樣本。
優點
- 容易實現
- 方差失真更小
缺點
- 我們不能把它應用于每一種情況
用隨機樣本注入替換年齡列NaN值
- def impute_nan(df,variable):
- df[variable+"_random"]=df[variable]
- ##It will have the random sample to fill the na
- random_sample=df[variable].dropna().sample(df[variable].isnull().sum(),random_state=0)
- ##pandas need to have same index in order to merge the dataset
- random_sample.index=df[df[variable].isnull()].index #replace random_sample index with NaN values index
- #replace where NaN are there
- df.loc[df[variable].isnull(),variable+'_random']=random_sample
- col=variable+"_random"
- df = df.drop(col,axis=1)
- impute_nan(df,"Age")

3、用新特性獲取NAN值
這種技術在數據不是完全隨機丟失的情況下最有效。在這里,我們在數據集中添加一個新列,并將所有NaN值替換為1。
優點
- 容易實現
- 獲取了了NaN值的重要性
缺點
- 創建額外的特性(維度詛咒)
- import numpy as np
- df['age_nan']=np.where(df['Age'].isnull(),1,0)
- ## It will create one new column that contains value 1 in the rows where Age value is NaN, otherwise 0.
4、End of Distribution
在這種技術中,我們用第3個標準偏差值(3rd standard deviation)替換NaN值。它還用于從數據集中刪除所有異常值。首先,我們使用std()計算第3個標準偏差,然后用該值代替NaN。優點
- 容易實現。
- 抓住了缺失值的重要性,如果有的話。
缺點
- 使變量的原始分布失真。
- 如果NAN的數量很大。它將掩蓋分布中真正的異常值。
- 如果NAN的數量較小,則替換后的NAN可以被認為是一個離群值,并在后續的特征工程中進行預處理。
- def impute_nan(df,variable,median,extreme):
- df[variable+"_end_distribution"]=df[variable].fillna(extreme)
- extreme=df.Age.mean()+3*df.Age.std() ##73.27--> 3rd std deviation
- impute_nan(df,'Age',df.Age.median(),extreme)



5、任意值替換
在這種技術中,我們將NaN值替換為任意值。任意值不應該更頻繁地出現在數據集中。通常,我們選擇最小離群值或最后離群值作為任意值。
優點
- 容易實現
- 獲取了缺失值的重要性,如果有的話
缺點
- 必須手動確定值。
- def impute_nan(df,var):
- df[var+'_zero']=df[var].fillna(0) #Filling with 0(least outlier)
- df[var+'_hundred']=df[var].fillna(100) #Filling with 100(last)
- impute_nan(df,'Age')


6、頻繁類別歸責
該技術用于填充分類數據中的缺失值。在這里,我們用最常見的標簽替換NaN值。首先,我們找到最常見的標簽,然后用它替換NaN。
優點
- 容易實現
缺點
- 由于我們使用的是更頻繁的標簽,所以如果有很多NaN值,它可能會以一種過度表示的方式使用它們。
- 它扭曲了最常見的標簽之間的關系。
- def impute_nan(df,variable):
- most_frequent_category=df[variable].mode()[0] ##Most Frequent
- df[variable].fillna(most_frequent_category,inplace=True)
- for feature in ['Cabin']: ##List of Categorical Features
- impute_nan(df,feature)



7、nan值視為一個新的分類
在這種技術中,我們只需用一個新的類別(如Missing)替換所有NaN值。
- df['Cabin']=df['Cabin'].fillna('Missing') ##NaN -> Missing
8、使用KNN填充
在這項技術中,我們使用sklearn創建一個KNN imputer模型,然后我們將該模型與我們的數據進行擬合,并預測NaN值。它被用來計算數值。這是一個5步的過程。
- 創建列列表(整數、浮點)
- 輸入估算值,確定鄰居。
- 根據數據擬合估算。
- 轉換的數據
- 使用轉換后的數據創建一個新的數據框架。
優點
- 容易實現
- 結果一般情況下會最好
缺點
- 只適用于數值數據
我們在上篇文章中已經有過詳細的介紹,這里就不細說了
9、刪除所有NaN值
它是最容易使用和實現的技術之一。只有當NaN值小于10%時,我們才應該使用這種技術。
優點:
- 容易實現
- 快速處理
缺點:
- 造成大量的數據丟失
- df.dropna(inplace=True) ##Drop all the rows that contains NaN
總結
還有更多處理丟失值的其他技術。我們的目標是找到最適合我們的問題的技術,然后實施它。處理丟失的值總是一個更好的主意,但有時我們不得不刪除所有的值。它基本上取決于數據的類型和數量。