特征工程系列:數據清洗
本文為數據茶水間群友原創,經授權在本公眾號發表。
關於作者:JunLiang,一個熱愛挖掘的數據從業者,勤學好問、動手達人,期待與大家一起交流探討機器學習相關內容~
0x00 前言
數據和特征決定了機器學習的上限,而模型和算法只是逼近這個上限而已。由此可見,特征工程在機器學習中占有相當重要的地位。在實際應用當中,可以說特征工程是機器學習成功的關鍵。
那特征工程是什么?
特征工程是利用數據領域的相關知識來創建能夠使機器學習算法達到最佳性能的特征的過程。
特征工程又包含了Data PreProcessing(數據預處理)、Feature Extraction(特征提取)、Feature Selection(特征選擇)和Feature construction(特征構造)等子問題,本章內容主要討論數據預處理的方法及實現。
特征工程是機器學習中最重要的起始步驟,數據預處理是特征工程的最重要的起始步驟,而數據清洗是數據預處理的重要組成部分,會直接影響機器學習的效果。
0x01 數據清洗介紹
數據清洗(Data cleaning)– 對數據進行重新審查和校驗的過程,目的在於刪除重復信息、糾正存在的錯誤,並提供數據一致性。
數據清洗, 是整個數據分析過程中不可缺少的一個環節,其結果質量直接關系到模型效果和最終結論。
0x02 格式內容清洗
1.格式內容問題產生的原因
-
數據是由人工收集或用戶填寫而來,則有很大可能性在格式和內容上存在一些問題;
-
不同版本的程序產生的內容或格式不一致;
-
不同數據源采集而來的數據內容和格式定義不一致。
2.時間、日期格式不一致清洗
根據實際情況,把時間/日期數據庫轉換成統一的表示方式。
例子:
-
日期格式不一致:
’2019-07-20’、’20190720’、’2019/07/20’、’20/07/2019’;
-
時間戳單位不一致,有的用秒表示,有的用毫秒表示;
-
使用無效時間表示,時間戳使用0表示,結束時間戳使用FFFF表示。
3.數值格式不一致清洗
根據實際情況,把數值轉換成統一的表示方式。
例子:1、2.0、3.21E3、四
4.全半角等顯示格式不一致清洗
這個問題在人工錄入數據時比較容易出現。
5.內容中有不該存在的字符清洗
某些內容可能只包括一部分字符,比如身份證號是數字+字母,中國人姓名是漢字(趙C這種情況還是少數)。最典型的就是頭、尾、中間的空格,也可能出現姓名中存在數字符號、身份證號中出現漢字等問題。
這種情況下,需要以半自動校驗半人工方式來找出可能存在的問題,並去除不需要的字符。
6.內容與該字段應有內容不符清洗
姓名寫了性別,身份證號寫了手機號等等,均屬這種問題。但該問題特殊性在於:並不能簡單的以刪除來處理,因為成因有可能是人工填寫錯誤,也有可能是前端沒有校驗,還有可能是導入數據時部分或全部存在列沒有對齊的問題,因此要詳細識別問題類型。
7.數據類型不符清洗
由於人為定義錯誤、轉存、加載等原因,數據類型經常會出現數據類型不符的情況。例如:金額特征是字符串類型,實際上應該轉換成int/float型。
0x03 邏輯錯誤清洗
邏輯錯誤除了以下列舉的情況,還有很多未列舉的情況,在實際操作中要酌情處理。另外,這一步驟在之后的數據分析建模過程中有可能重復,因為即使問題很簡單,也並非所有問題都能夠一次找出,我們能做的是使用工具和方法,盡量減少問題出現的可能性,使分析過程更為高效。
1.數據重復清洗
1)存在各個特征值完全相同的兩條/多條數據
此時直接刪除並只保留其中一條數據。
df.drop_duplicates()
2)數據不完全相同,但從業務角度看待數據是同一個數據
如頁面埋點時,進入頁面和退出頁面都會上報一次數據,只有時間不一樣,其他字段相同,在統計pv/uv時應該進行去重。
# 根據某個/多個特征值唯一區分每個樣本,則可使用該特征/多個特征進行去重。df.drop_duplicates(subset=['ID'], keep='last')
2.不合理值清洗
根據業務常識,或者使用但不限於箱型圖(Box-plot)發現數據中不合理的特征值。
不合理值的例子:
-
年齡:
200歲;
-
個人年收入:
100000萬;
-
籍貫:
漢族。
3.矛盾內容修正
有些字段是可以互相驗證的,舉例:身份證號是1101031980XXXXXXXX,然后年齡填18歲。在這種時候,需要根據字段的數據來源,來判定哪個字段提供的信息更為可靠,去除或重構不可靠的字段。
0x04 異常值清洗
異常值是數據分布的常態,處於特定分布區域或范圍之外的數據通常被定義為異常或噪聲。異常分為兩種:“偽異常”,由於特定的業務運營動作產生,是正常反應業務的狀態,而不是數據本身的異常;“真異常”,不是由於特定的業務運營動作產生,而是數據本身分布異常,即離群點。
1.異常值檢查方法
1)基於統計分析
異常檢測問題就在統計學領域里得到廣泛研究,通常用戶用某個統計分布對數據點進行建模,再以假定的模型,根據點的分布來確定是否異常。
如通過分析統計數據的散度情況,即數據變異指標,來對數據的總體特征有更進一步的了解,對數據的分布情況有所了解,進而通過數據變異指標來發現數據中的異常點數據。常用的數據變異指標有極差、四分位數間距、均差、標准差、變異系數等等,變異指標的值大表示變異大、散布廣;值小表示離差小,較密集。
譬如最大最小值可以用來判斷這個變量的取值是否超過了合理的范圍,如客戶的年齡為-20歲或200歲,顯然是不合常理的,為異常值。
2)3σ原則
若數據存在正態分布,在3σ原則下,異常值為一組測定值中與平均值的偏差超過3倍標准差的值。如果數據服從正態分布,距離平均值3σ之外的值出現的概率為P(|x - μ| > 3σ) <= 0.003,屬於極個別的小概率事件。如果數據不服從正態分布,也可以用遠離平均值的多少倍標准差來描述。
3)箱線圖分析
箱線圖提供了識別異常值的一個標准:如果一個值小於QL-1.5IQR或大於OU+1.5IQR的值,則被稱為異常值。
* QL為下四分位數,表示全部觀察值中有四分之一的數據取值比它小;* QU為上四分位數,表示全部觀察值中有四分之一的數據取值比它大;* IQR為四分位數間距,是上四分位數QU與下四分位數QL的差值,包含了全部觀察值的一半。
箱型圖判斷異常值的方法以四分位數和四分位距為基礎,四分位數具有魯棒性:25%的數據可以變得任意遠並且不會干擾四分位數,所以異常值不能對這個標准施加影響。因此箱型圖識別異常值比較客觀,在識別異常值時有一定的優越性。
4)基於模型檢測
首先建立一個數據模型,異常是那些同模型不能完美擬合的對象;如果模型是簇的集合,則異常是不顯著屬於任何簇的對象;在使用回歸模型時,異常是相對遠離預測值的對象。
優點:
-
有堅實的統計學理論基礎,當存在充分的數據和所用的檢驗類型的知識時,這些檢驗可能非常有效。
缺點:
-
對於多元數據,可用的選擇少一些,並且對於高維數據,這些檢測可能性很差。
5)基於距離
基於距離的方法是基於下面這個假設:即若一個數據對象和大多數點距離都很遠,那這個對象就是異常。通過定義對象之間的臨近性度量,根據距離判斷異常對象是否遠離其他對象,主要使用的距離度量方法有絕對距離(曼哈頓距離)、歐氏距離和馬氏距離等方法。
優點:
-
基於距離的方法比基於統計類方法要簡單得多;
因為為一個數據集合定義一個距離的度量要比確定數據集合的分布容易的多。
缺點:
-
基於鄰近度的方法需要O(m2)時間,大數據集不適用;
-
該方法對參數的選擇也是敏感的;
-
不能處理具有不同密度區域的數據集,因為它使用全局閾值,不能考慮這種密度的變化。
6)基於密度
考察當前點周圍密度,可以發現局部異常點,離群點的局部密度顯著低於大部分近鄰點,適用於非均勻的數據集。
優點:
-
給出了對象是離群點的定量度量,並且即使數據具有不同的區域也能夠很好的處理。
缺點:
-
與基於距離的方法一樣,這些方法必然具有O(m2)的時間復雜度。
對於低維數據使用特定的數據結構可以達到O(mlogm);
-
參數選擇困難。
雖然算法通過觀察不同的k值,取得最大離群點得分來處理該問題,但是,仍然需要選擇這些值的上下界。
7)基於聚類
對象是否被認為是異常點可能依賴於簇的個數(如k很大時的噪聲簇)。該問題也沒有簡單的答案。一種策略是對於不同的簇個數重復該分析。另一種方法是找出大量小簇,其想法是:
-
較小的簇傾向於更加凝聚;
-
如果存在大量小簇時一個對象是異常點,則它多半是一個真正的異常點。
不利的一面是一組異常點可能形成小簇而逃避檢測。
優點:
-
基於線性和接近線性復雜度(k均值)的聚類技術來發現離群點可能是高度有效的;
-
簇的定義通常是離群點的補,因此可能同時發現簇和離群點。
缺點:
-
產生的離群點集和它們的得分可能非常依賴所用的簇的個數和數據中離群點的存在性;
-
聚類算法產生的簇的質量對該算法產生的離群點的質量影響非常大。
8)基於鄰近度的異常點檢測
一個對象是異常的,如果它遠離大部分點。這種方法比統計學方法更一般、更容易使用,因為確定數據集的有意義的鄰近性度量比確定它的統計分布更容易。一個對象的異常點得分由到它的k-最近鄰的距離給定。異常點得分對k的取值高度敏感。如果k太小(例如1),則少量的鄰近異常異常點可能導致較異常低的異常點得分;如果K太大,則點數少於k的簇中所有的對象可能都成了異常異常點。為了使該方案對於k的選取更具有魯棒性,可以使用k個最近鄰的平均距離。
優點:
-
簡單。
缺點:
-
基於鄰近度的方法需要O(m2)時間,大數據集不適用;
-
該方法對參數的選擇也是敏感的;
-
不能處理具有不同密度區域的數據集,因為它使用全局閾值,不能考慮這種密度的變化。
在數據處理階段將離群點作為影響數據質量的異常點考慮,而不是作為通常所說的異常檢測目標點,因而樓主一般采用較為簡單直觀的方法,結合箱線圖和MAD的統計方法判斷變量的離群點。
2.數據光滑處理
除了檢測出異常值然后再處理異常值外,還可以使用以下方法對異常數據進行光滑處理。
1)分箱
分箱方法通過考察數據的“近鄰”(即周圍的值)來光滑有序數據的值,有序值分布到一些“桶”或箱中。由於分箱方法考察近鄰的值,因此進行局部光滑。
分箱方法:
-
等高方法:
每個bin中的個數相等;
-
等寬方法:
每個bin的取值間距相等;
-
按具體業務場景划分。
一般而言,寬度越大,光滑效果越明顯。箱也可以是等寬的,其中每個箱值的區間范圍是個常量。分箱也可以作為一種離散化技術使用。
幾種分箱光滑技術:
-
用箱均值光滑:
箱中每一個值被箱中的平均值替換;
-
用箱中位數平滑:
箱中的每一個值被箱中的中位數替換;
-
用箱邊界平滑:
箱中的最大和最小值同樣被視為邊界。
箱中的每一個值被最近的邊界值替換。
2)回歸
可以用一個函數(如回歸函數)擬合數據來光滑數據。線性回歸涉及找出擬合兩個屬性(或變量)的“最佳”線,是的一個屬性可以用來預測另一個。多元線性回歸是線性回歸的擴展,其中涉及的屬性多於兩個,並且數據擬合到一個多維曲面。
3.異常值處理方法
對異常值處理,需要具體情況具體分析,異常值處理的方法常用有四種:
-
刪除含有異常值的記錄;
某些篩選出來的異常樣本是否真的是不需要的異常特征樣本,最好找懂業務的再確認一下,防止我們將正常的樣本過濾掉了。
-
將異常值視為缺失值,交給缺失值處理方法來處理;
-
使用均值/中位數/眾數來修正;
-
不處理。
0x05 缺失值清洗
沒有高質量的數據,就沒有高質量的數據挖掘結果,數據值缺失是數據分析中經常遇到的問題之一。
1.造成缺失值的原因
-
信息暫時無法獲取;
-
如商品售后評價、雙十一的退貨商品數量和價格等具有滯后效應。
-
信息被遺漏;
-
可能是因為輸入時認為不重要、忘記填寫了或對數據理解錯誤而遺漏,也可能是由於數據采集設備的故障、存儲介質的故障、傳輸媒體的故障、一些人為因素等原因而丟失。
這個在很多公司恐怕是習以為常的事情。
-
獲取這些信息的代價太大;
-
如統計某校所有學生每個月的生活費,家庭實際收入等等。
-
系統實時性能要求較高;
-
即要求得到這些信息前迅速做出判斷或決策。
-
有些對象的某個或某些屬性是不可用的。
-
如一個未婚者的配偶姓名、一個兒童的固定收入狀況等。
2.缺失數據處理方法
1) 刪除元組
也就是將存在遺漏信息屬性值的對象(元組,記錄)刪除,從而得到一個完備的信息表。
-
優點:
簡單易行,在對象有多個屬性缺失值、被刪除的含缺失值的對象與初始數據集的數據量相比非常小的情況下非常有效;
-
不足:
當缺失數據所占比例較大,特別當遺漏數據非隨機分布時,這種方法可能導致數據發生偏離,從而引出錯誤的結論。
2)數據填充
用一定的值去填充空值,從而使信息表完備化。通常基於統計學原理,根據初始數據集中其余對象取值的分布情況來對一個缺失值進行填充。
數據填充的方法有多種,此處先不展開,下面章節將會詳細介紹。
3)不處理
不處理缺失值,直接在包含空值的數據上進行數據挖掘的方法包括XGBoost、貝葉斯網絡和人工神經網絡等。
補齊處理只是將未知值補以我們的主觀估計值,不一定完全符合客觀事實,在對不完備信息進行補齊處理的同時,我們或多或少地改變了原始的信息系統。而且,對空值不正確的填充往往將新的噪聲引入數據中,使挖掘任務產生錯誤的結果。因此,在許多情況下,我們還是希望在保持原始信息不發生變化的前提下對信息系統進行處理。
3.數據填充的方法
1)人工填充(filling manually)
根據業務知識來進行人工填充。
2)特殊值填充(Treating Missing Attribute values as Special values)
將空值作為一種特殊的屬性值來處理,它不同於其他的任何屬性值。如所有的空值都用“unknown”填充。一般作為臨時填充或中間過程。
實現代碼
df['Feature'].fillna('unknown', inplace=True)
3)統計量填充
若缺失率較低(小於95%)且重要性較低,則根據數據分布的情況進行填充。
常用填充統計量:
-
平均值:
對於數據符合均勻分布,用該變量的均值填補缺失值。
-
中位數:
對於數據存在傾斜分布的情況,采用中位數填補缺失值。
-
眾數:
離散特征可使用眾數進行填充缺失值。
平均值填充法:
將初始數據集中的屬性分為數值屬性和非數值屬性來分別進行處理。
實現代碼
# 以pandas庫操作為例
display(df.head(10))
# 填充前數據
Feature1 Feature2 Label
0 1.0 A 1
1 2.0 A 1
2 3.0 A 1
3 4.0 C 1
4 NaN A 1
5 2.0 None 0
6 3.0 B 0
7 3.0 None 0
8 NaN B 0
9 NaN B 0
# 均值填充
df['Feature1'].fillna(df['Feature1'].mean(), inplace=True)
# 中位數填充
df['Feature2'].fillna(df['Feature2'].mode().iloc[0], inplace=True)
display(df.head(10))
# 填充后數據
Feature1 Feature2 Label
0 1.000000 A 1
1 2.000000 A 1
2 3.000000 A 1
3 4.000000 C 1
4 2.571429 A 1
5 2.000000 A 0
6 3.000000 B 0
7 3.000000 A 0
8 2.571429 B 0
9 2.571429 B 0
條件平均值填充法(Conditional Mean Completer):
在該方法中,用於求平均值/眾數/中位數並不是從數據集的所有對象中取,而是從與該對象具有相同決策屬性值的對象中取得。
實現代碼
# 條件平均值填充
def condition_mean_fillna(df, label_name, feature_name):
mean_feature_name = '{}Mean'.format(feature_name)
group_df = df.groupby(label_name).mean().reset_index().rename(columns={feature_name: mean_feature_name})
df = pd.merge(df, group_df, on=label_name, how='left')
df.loc[df[feature_name].isnull(), feature_name] = df.loc[df[feature_name].isnull(), mean_feature_name]
df.drop(mean_feature_name, inplace=True, axis=1)
return df
df = condition_mode_fillna(df, 'Label', 'Feature2')
4)模型預測填充
使用待填充字段作為Label,沒有缺失的數據作為訓練數據,建立分類/回歸模型,對待填充的缺失字段進行預測並進行填充。
最近距離鄰法(KNN)
先根據歐式距離或相關分析來確定距離具有缺失數據樣本最近的K個樣本,將這K個值加權平均/投票來估計該樣本的缺失數據。
關鍵代碼
from sklearn.neighbors import KNeighborsClassifier, KNeighborsRegressor
def knn_missing_filled(x_train, y_train, test, k = 3, dispersed = True):
'''
@param x_train: 沒有缺失值的數據集
@param y_train: 待填充缺失值字段
@param test: 待填充缺失值數據集
'''
if dispersed:
clf = KNeighborsClassifier(n_neighbors = k, weights = "distance")
else:
clf = KNeighborsRegressor(n_neighbors = k, weights = "distance")
clf.fit(x_train, y_train)
return test.index, clf.predict(test)
回歸(Regression)
基於完整的數據集,建立回歸方程。對於包含空值的對象,將已知屬性值代入方程來估計未知屬性值,以此估計值來進行填充。當變量不是線性相關時會導致有偏差的估計。常用線性回歸。
5)插值法填充
包括隨機插值,多重插補法,熱平台插補,拉格朗日插值,牛頓插值等。
線性插值法
使用插值法可以計算缺失值的估計值,所謂的插值法就是通過兩點(x0,y0),(x1,y1)估計中間點的值,假設y=f(x)是一條直線,通過已知的兩點來計算函數f(x),然后只要知道x就能求出y,以此方法來估計缺失值。
實現代碼
# df為pandas的DataFrame
df['Feature'] = df['Feature'].interpolate()
多重插補(Multiple Imputation)
多值插補的思想來源於貝葉斯估計,認為待插補的值是隨機的,它的值來自於已觀測到的值。具體實踐上通常是估計出待插補的值,然后再加上不同的噪聲,形成多組可選插補值。根據某種選擇依據,選取最合適的插補值。
多重插補方法分為三個步驟:
-
Step1:
為每個空值產生一套可能的插補值,這些值反映了無響應模型的不確定性;
每個值都可以被用來插補數據集中的缺失值,產生若干個完整數據集合;
-
Step2:
每個插補數據集合都用針對完整數據集的統計方法進行統計分析;
-
Step3:
對來自各個插補數據集的結果,根據評分函數進行選擇,產生最終的插補值。
6)啞變量填充
若變量是離散型,且不同值較少,可轉換成啞變量,例如性別SEX變量,存在male,fameal,NA三個不同的值,可將該列轉換成IS_SEX_MALE
、IS_SEX_FEMALE
、IS_SEX_NA
。若某個變量存在十幾個不同的值,可根據每個值的頻數,將頻數較小的值歸為一類’other’,降低維度。此做法可最大化保留變量的信息。
實現代碼
sex_list = ['MALE', 'FEMALE', np.NaN, 'FEMALE', 'FEMALE', np.NaN, 'MALE',]
df = pd.DataFrame({'SEX': sex_list})
display(df)
df.fillna('NA', inplace=True)
df = pd.get_dummies(df['SEX'],prefix='IS_SEX')
display(df)
# 原始數據
SEX
0 MALE
1 FEMALE
2 NaN
3 FEMALE
4 FEMALE
5 NaN
6 MALE
# 填充后
IS_SEX_FEMALE IS_SEX_MALE IS_SEX_NA
0 0 1 0
1 1 0 0
2 0 0 1
3 1 0 0
4 1 0 0
5 0 0 1
6 0 1 0
7)熱卡填充(Hot deck imputation,就近補齊)
熱卡填充法在完整數據中找到一個與它最相似的對象,然后用這個相似對象的值來進行填充。不同的問題可能會選用不同的標准來對相似進行判定。該方法概念上很簡單,且利用了數據間的關系來進行空值估計。
這個方法的缺點在於難以定義相似標准,主觀因素較多。
8)期望值最大化填充(Expectation maximization,EM)
EM算法是一種在不完全數據情況下計算極大似然估計或者后驗分布的迭代算法。在每一迭代循環過程中交替執行兩個步驟:E步(Excepctaion step,期望步),在給定完全數據和前一次迭代所得到的參數估計的情況下計算完全數據對應的對數似然函數的條件期望;M步(Maximzation step,極大化步),用極大化對數似然函數以確定參數的值,並用於下步的迭代。算法在E步和M步之間不斷迭代直至收斂,即兩次迭代之間的參數變化小於一個預先給定的閾值時結束。該方法可能會陷入局部極值,收斂速度也不是很快,並且計算很復雜。
缺點:由線性模型化所報告的軟件標准誤和檢驗統計量並不正確,且對於過度識別模型,估計值不是全然有效的。
4.缺失值處理步驟
1)確定缺失值范圍
對每個字段都計算其缺失值比例,然后按照缺失比例和字段重要性,分別制定策略,可用下圖表示:
2)去除不需要的字段
建議清洗每做一步都備份一下,或者在小規模數據上試驗成功再處理全量數據。
3)填充缺失內容
使用上面介紹的任意一種或多種方法填充缺失數據。
4)重新取數
如果某些指標非常重要又缺失率高,那就需要和取數人員或業務人員了解,是否有其他渠道可以取到相關數據。
0x06 非需求數據清洗
簡單來說就是把不要的字段刪了。
看起來簡單,但實際操作中容易有以下問題:
-
把看上去不需要但實際上對業務很重要的字段刪了;
-
某個字段覺得有用,但又沒想好怎么用,不知道是否該刪;
-
一時看走眼,刪錯字段了。
在實際操作中,如果不知道哪些是非需求數據,可以不進行非需求數據清洗,在數據預處理之后再進行特征篩選。
0xFF總結
1.數據清洗是特征工程的第一步,也是非常重要的一步。
2.數據清洗的一般流程:
-
Step 1:
格式內容清洗;
-
Step 2:
邏輯錯誤清洗;
-
Step 3:
異常數據清洗;
-
Step 4:
缺失數據清洗;
-
Step 5:
非需求數據清洗。
不同的數據質量不一樣,並不是所有項目中都需要進行每一項數據清洗,應該根據實際情況選擇必要的數據清洗方式。
注:文章中使用的部分圖片源於網絡。
歡迎大家一起來討論。
參考文獻
[1] 數據清洗的一些梳理. https://zhuanlan.zhihu.com/p/20571505
[2] 數據預處理——缺失值處理. https://zhuanlan.zhihu.com/p/33996846
[3] Multiple Imputation with Chained Equations. http://www.statsmodels.org/stable/imputation.html
[4] https://www.zhihu.com/question/22077960/answer/473720583