在數據清洗過程當中,主要處理的是缺失值、異常值和重複值。所謂清洗,是對數據集進行丟棄、填充、替換、去重等操做,實現去除異 常、糾正錯誤、補足缺失的目的。算法
數據缺失分爲兩種:一是行記錄的缺失,這種狀況又稱數據記錄丟失;二是數據列值的缺失,即因爲各類緣由致使的數據記錄中某些列的值空缺,不一樣的數據存儲和環境中對於缺失值的表示結果也不一樣,例如,數據庫中是Null,Python返回對象是None,Pandas或Numpy中是 NaN。數據庫
丟失的數據記錄一般沒法找回,這裏重點討論數據列類型缺失值的 處理,一般有四種思路:後端
這種方法簡單明瞭,直接刪除帶有缺失值的行記錄(整行刪除)或者列字段(整列刪除),減小缺失數據記錄對整體數據的影響。但丟棄 意味着會消減數據特徵,如下任意一種場景都不宜採用該方法:bash
相對丟棄而言,補全是更加經常使用的缺失值處理方式,經過必定的方法將缺失的數據補上,從而造成完整的數據記錄對於後續的數據處理、分析和建模相當重要。經常使用的補全方法包括:網絡
某些狀況下,咱們可能沒法得知缺失值的分佈規律,而且沒法對於缺失值採用上述任何一種方法作處理;或者咱們認爲數據缺失也是一種 規律,不該該輕易對缺失值隨意處理,那麼還有一種缺失值處理思路——真值轉換。dom
該思路的根本觀點是,咱們認可缺失值的存在,而且把數據缺失也做爲數據分佈規律的一部分,這將變量的實際值和缺失值都做爲輸入維度參與後續數據處理和模型計算。可是變量的實際值能夠做爲變量值參與模型計算,而缺失值一般沒法參與運算,所以須要對缺失值進行真值轉換。ui
以用戶性別字段爲例,不少數據庫集都沒法對會員的性別進行補足,但又捨不得將其丟棄,那麼咱們將選擇將其中的值,包括男、女、未知從一個變量的多個值分佈狀態轉換爲多個變量的真值分佈狀態。spa
在數據預處理階段,對於具備缺失值的數據記錄不作任何處理,也是一種思路。這種思路主要看後期的數據分析和建模應用,不少模型對於缺失值有容忍度或靈活的處理方法,所以在預處理階段能夠不作處理。常見的可以自動處理缺失值的模型包括:KNN、決策樹和隨機森林、神經網絡和樸素貝葉斯、DBSCAN(基於密度的帶有噪聲的空間聚類)等。這些模型對於缺失值的處理思路是:code
異常數據是數據分佈的常態,處於特定分佈區域或範圍以外的數據一般會被定義爲異常或「噪音」。產生數據「噪音」的緣由不少,例如業務運營操做、數據採集問題、數據同步問題等。對異常數據進行處理前,須要先辨別出到底哪些是真正的數據異常。從數據異常的狀態看分爲兩種:orm
大多數數據挖掘或數據工做中,異常值都會在數據的預處理過程當中被認爲是噪音而剔除,以免其對整體數據評估和分析挖掘的影響。但在如下幾種狀況下,無須對異常值作拋棄處理。
該場景是由業務部門的特定動做致使的數據分佈異常,若是拋棄異常值將致使沒法正確反饋業務結果。
例如:公司的A商品正常狀況下日銷量爲1000臺左右。因爲昨日舉行優惠促銷活動致使總銷量達到10000臺,因爲後端庫存備貨不足致使今日銷量又降低到100臺。在這種狀況下,10000臺和100臺都正確反映了業務運營的結果,而非數據異常。
異常檢測模型是針對總體樣本中的異常數據進行分析和挖掘以便找到其中的異常個案和規律,這種數據應用圍繞異常值展開,所以異常值 不能作拋棄處理。
異常檢測模型經常使用於客戶異常識別、信用卡欺詐、貸款審批識別、藥物變異識別、惡劣氣象預測、網絡入侵檢測、流量做弊檢測等。在這種狀況下,異常數據自己是目標數據,若是被處理掉將損失關鍵信息。
若是數據算法和模型對異常值不敏感,那麼即便不處理異常值也不會對模型自己形成負面影響。例如在決策樹中,異常值自己就能夠做爲一種分裂節點。
除了拋棄和保留,還有一種思路可對異常值進行處理,例如使用其餘統計量、預測量進行替換,但不推薦使用這種方法,緣由是這會將其中的關鍵分佈特徵消除,從而改變原始數據集的分佈規律。
數據集中的重複值包括如下兩種狀況:
去重是重複值處理的主要方法,主要目的是保留能顯示特徵的惟一數據記錄。但當遇到如下幾種狀況時,請慎重(不建議)執行數據去重。
以變化維度表爲例。例如在商品類別的維度表中,每一個商品對應了同1個類別的值應該是惟一的,例如蘋果iPhone7屬於我的電子消費品, 這樣才能將全部全部商品分配到惟一類別屬性值中。但當全部商品類別的值重構或升級時(大多數狀況下隨着公司的發展都會這麼作),原有的商品可能被分配了類別中的不一樣值。
此時,咱們在數據中使用Full join作跨重構時間點的類別匹配時,會發現蘋果iPhone7會同時匹配到我的電子消費品和手機數碼兩條記錄。對於這種狀況,須要根據具體業務需求處理:
相關知識點:變化維度表
變化維度表是數據倉庫中的概念。維度表相似於匹配表,用來存儲靜態的維度、屬性等數據,而這些數據通常都不會改變。可是變與不變 是一個相對的概念,隨着企業的不斷髮展,不少時候維度也會發生變化。所以在某個時間內的維度是不變的,而從總體來看維度是變化的。 對於維度的變化,有3種方式進行處理:
- 直接覆蓋原有值。這種狀況下每一個惟一ID就只對應一個屬性值,這樣作雖然簡單粗暴也容易實現,可是沒法保留歷史信息。
- 添加新的維度行。此時同一個ID會獲得兩條匹配記錄。
- 增長新的屬性列。此時不會新增數據行記錄,只是在原有的記錄 中新增一列用於標記不一樣時期的值。具體到企業內使用哪一種方式,一般是由數據庫管理員根據實際狀況來決定。
在開展分類數據建模工做時,樣本不均衡是影響分類模型效果的關鍵因素之一,解決分類方法的一種方法是對少數樣本類別作簡單過採樣,經過隨機過採樣採起簡單複製樣本的策略來增長少數類樣本。通過這種處理方式後,也會在數據記錄中產生相同記錄的多條數據。此時,咱們不能對其中重複值執行去重操做。
對於以分析應用爲主的數據集而言,存在重複記錄不會直接影響實際運營,畢竟數據集主要用來作分析;但對於事務型的數據而言,重複 數據可能意味着重大運營規則問題,尤爲當這些重複值出如今與企業經營中金錢相關的業務場景中,例如重複的訂單、重複的充值、重複的預定項、重複的出庫申請等。
這些重複的數據記錄一般是因爲數據採集、存儲、驗證和審覈機制的不完善等問題致使的,會直接反映到前臺生產和運營系統。以重複訂單爲例,假如前臺的提交訂單功能不作惟一性約束,那麼在一次訂單中重複點擊提交訂單按鈕,就會觸發屢次重複提交訂單的申請記錄,若是該操做審批經過後,會聯動帶動運營後端的商品分揀、出庫、送貨,若是用戶接收重複商品則會致使重大損失;若是用戶退貨則會增長反向訂單,並影響物流、配送和倉儲相關的各個運營環節,致使運營資源無故消耗、商品損耗增長、倉儲物流成本增長等問題。
所以,這些問題必須在前期數據採集和存儲時就經過必定機制解決和避免。若是確實產生了此類問題,那麼數據工做者或運營工做者能夠基於這些重複值來發現規則漏洞,並配合相關部門最大限度下降給企業帶來的運營風險。
對於缺失值的處理,主要配合使用sklearn.preprocessing中的Imputer類、Pandas和Numpy。其中因爲Pandas對於數據探索、分析和探查的支持較爲良好,所以圍繞Pandas的缺失值處理較爲經常使用。
import pandas as pd # 導入pandas庫
import numpy as np # 導入numpy庫
from sklearn.preprocessing import Imputer # 導入sklearn.preprocessing中的Imputer庫
複製代碼
經過Pandas生成一個6行4列,列名分別爲'col1'、'col2'、'col3'、'col4'的數據框。同時,數據框中增長兩個缺失 值數據。除了示例中直接經過pd.DataFrame來建立數據框外,還可使用數據框對象的df.from_records、df.from_dict、df.from_items來從元組記錄、字典和鍵值對對象建立數據框,或使用pandas.read_csv、pandas.read_table、pandas.read_clipboard等方法讀取文件或剪貼板建立數據框。
# 生成缺失數據
df = pd.DataFrame(np.random.randn(6, 4),
columns=['col1', 'col2', 'col3', 'col4']) # 生成一份數據
df.iloc[1:2, 1] = np.nan # 增長缺失值
df.iloc[4, 3] = np.nan # 增長缺失值
print(df)
複製代碼
結果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 NaN -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 NaN
5 0.918172 -0.146227 -1.087238 0.376928
複製代碼
經過df.null()方法找到全部數據框中的缺失值(默認缺失值是NaN格式),而後使用any()或all()方法來查找含有至少1個 或所有缺失值的列,其中any()方法用來返回指定軸中的任何元素爲True,而all()方法用來返回指定軸的全部元素都爲True。
# 查看哪些值缺失
nan_all = df.isnull() # 得到全部數據框中的N值
print(nan_all) # 打印輸出
複製代碼
結果
col1 col2 col3 col4
0 False False False False
1 False True False False
2 False False False False
3 False False False False
4 False False False True
5 False False False False
複製代碼
# 查看哪些列缺失
nan_col1 = df.isnull().any() # 得到含有NA的列
print(nan_col1) # 打印輸出
複製代碼
結果
col1 False
col2 True
col3 False
col4 True
dtype: bool
複製代碼
# 查看哪些列缺失
nan_col2 = df.isnull().all() # 得到所有爲NA的列
print(nan_col2) # 打印輸出
複製代碼
結果
col1 False
col2 False
col3 False
col4 False
dtype: bool
複製代碼
經過Pandas默認的dropna()方法丟棄缺失值,返回完好失值的數據記錄。該代碼段執行後返回以下結果(第2行、第5行數據記錄被刪除):
# 丟棄缺失值
df2 = df.dropna() # 直接丟棄含有NA的行記錄
print(df2) # 打印輸出
複製代碼
結果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
5 0.918172 -0.146227 -1.087238 0.376928
複製代碼
經過Sklearn的數據預處理方法對缺失值進行處理。首先經過Imputer方法建立一個預處理對象,其中strategy爲默認缺失值的字符串,默認爲NaN;
示例中選擇缺失值替換方法是均值(默認),還能夠選擇使用中位數和衆數進行替換,即strategy值設置爲median或 most_frequent;後面的參數axis用來設置輸入的軸,默認值爲0,即便用列作計算邏輯。而後使用預處理對象的fit_transform方法對df(數據框對象)進行處理,該方法是將fit和transform組合起來使用。
# 使用sklearn將缺失值替換爲特定值
nan_model = Imputer(missing_values='NaN', strategy='mean',
axis=0) # 創建替換規則:將值爲NaN的缺失值以均值作替換
nan_result = nan_model.fit_transform(df) # 應用模型規則
print(nan_result) # 打印輸出
複製代碼
結果
[[ 1.41136738 -0.36790328 2.61005414 -0.59482946]
[ 0.72341364 0.12179985 -0.66436841 -0.7401174 ]
[-0.36736481 -0.17396797 -0.73227893 0.10299754]
[ 1.81116379 0.65385047 0.60561066 1.79355171]
[ 0.0940324 0.64324712 0.25963105 0.18770606]
[ 0.91817218 -0.14622709 -1.08723833 0.37692791]]
複製代碼
代碼中的第2行第2列和第5行第4列分別被各自列的均值替換。爲了驗證咱們手動計算各自列的均值,經過使用df['col2'].mean()和df['col4'].mean()分別得到這兩列的均值,即-0.4494679289032068和-0.16611331259664791,跟Sklearn返回的結果一致。
使用Pandas作缺失值處理。Pandas對缺失值的處理方法是df.fillna(),該方法中最主要的兩個參數是value和method。前者經過 固定(或手動指定)的值替換缺失值,後者使用Pandas提供的默認方法替換缺失值,如下是method支持的方法:
# 使用pandas將缺失值替換爲特定值
nan_result_pd1 = df.fillna(method='backfill') # 用後面的值替換缺失值
# 打印輸出
print(nan_result_pd1) # 打印輸出
複製代碼
結果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 -0.173968 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 0.376928
5 0.918172 -0.146227 -1.087238 0.376928
複製代碼
# 使用pandas將缺失值替換爲特定值
nan_result_pd2 = df.fillna(method='bfill', limit=1) # 用後面的值替代缺失值,限制每列只能替代一個缺失值
# 打印輸出
print(nan_result_pd2) # 打印輸出
複製代碼
結果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 -0.173968 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 0.376928
5 0.918172 -0.146227 -1.087238 0.376928
複製代碼
# 使用pandas將缺失值替換爲特定值
nan_result_pd3 = df.fillna(method='pad') # 用前面的值替換缺失值
# 打印輸出
print(nan_result_pd3) # 打印輸出
複製代碼
結果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 -0.367903 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 1.793552
5 0.918172 -0.146227 -1.087238 0.376928
複製代碼
# 使用pandas將缺失值替換爲特定值
nan_result_pd4 = df.fillna(0) # 用0替換缺失值
# 打印輸出
print(nan_result_pd4) # 打印輸出
複製代碼
結果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 0.000000 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 0.000000
5 0.918172 -0.146227 -1.087238 0.376928
複製代碼
# 使用pandas將缺失值替換爲特定值
nan_result_pd5 = df.fillna({'col2': 1.1, 'col4': 1.2}) # 用不一樣值替換不一樣列的缺失值
# 打印輸出
print(nan_result_pd5) # 打印輸出
複製代碼
結果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 1.100000 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 1.200000
5 0.918172 -0.146227 -1.087238 0.376928
複製代碼
# 使用pandas將缺失值替換爲特定值
nan_result_pd6 = df.fillna(df.mean()['col2':'col4']) # 用平均數代替,選擇各自列的均值替換缺失值
# 打印輸出
print(nan_result_pd6) # 打印輸出
複製代碼
結果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 0.121800 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 0.187706
5 0.918172 -0.146227 -1.087238 0.376928
複製代碼
有關異常值的肯定有不少規則和方法,這裏使用Z標準化獲得的閾值做爲判斷標準:當標準化後的得分超過閾值則爲異常。完整代碼以下:
import pandas as pd # 導入pandas庫
複製代碼
直接經過DataFrame建立一個7行2列的數據框
# 生成異常數據
df = pd.DataFrame({'col1': [1, 120, 3, 5, 2, 12, 13],
'col2': [12, 17, 31, 53, 22, 32, 43]})
print(df) # 打印輸出
複製代碼
結果
col1 col2
0 1 12
1 120 17
2 3 31
3 5 53
4 2 22
5 12 32
6 13 43
複製代碼
本過程當中,先經過df.copy()複製一個原始數據框的副本用來存儲Z-Score標準化後的得分,再經過df.columns得到原始數據框的列名,接着經過循環來判斷每一列中的異常值。在判斷邏輯中,對每一列的數據使用自定義的方法作Z-Score值標準化得分計算,而後跟閾值2.2作比較,若是大於閾值則爲異常。
至於爲何閾值是2.2?有關數據標準化的話題後面再討論。
# 經過Z-Score方法判斷異常值
df_zscore = df.copy() # 複製一個用來存儲Z-score得分的數據框
cols = df.columns # 得到數據框的列名
for col in cols: # 循環讀取每列
df_col = df[col] # 獲得每列的值
z_score = (df_col - df_col.mean()) / df_col.std() # 計算每列的Z-score得分
df_zscore[
col] = z_score.abs() > 2.2 # 判斷Z-score得分是否大於2.2,若是是則是True,不然爲False
print(df_zscore) # 打印輸出
複製代碼
結果
col1 col2
0 False False
1 True False
2 False False
3 False False
4 False False
5 False False
6 False False
複製代碼
# 刪除異常值所在的行
df_drop_outlier = df[df_zscore['col1'] == False]
print(df_drop_outlier)
複製代碼
結果
col1 col2
0 1 12
2 3 31
3 5 53
4 2 22
5 12 32
6 13 43
複製代碼
上述過程當中,主要須要考慮的關鍵點是:如何判斷異常值。對於有固定業務規則的可直接套用業務規則,而對於沒有固定業務規則的,可 以採用常見的數學模型進行判斷,即基於機率分佈的模型(例如正態分佈的標準差範圍)、基於聚類的方法(例如KMeans)、基於密度的方 法(例如LOF)、基於分類的方法(例如KNN)、基於統計的方法(例 如分位數法)等,此時異常值的定義帶有較強的主觀判斷色彩,具體須要根據實際狀況選擇。
import pandas as pd # 導入pandas庫
複製代碼
該數據是一個4行2列數據框
# 生成重複數據
data1 = ['a', 3]
data2 = ['b', 2]
data3 = ['a', 3]
data4 = ['c', 2]
df = pd.DataFrame([data1, data2, data3, data4], columns=['col1', 'col2'])
print(df)
複製代碼
結果
col1 col2
0 a 3
1 b 2
2 a 3
3 c 2
複製代碼
判斷數據記錄是否爲重複值,返回每條數據記錄是否重複的結果,取值爲True或False。判斷方法爲df.duplicated(),該方法中 兩個主要的參數是subset和keep:
# 判斷重複數據
isDuplicated = df.duplicated() # 判斷重複數據記錄
print(isDuplicated) # 打印輸出
複製代碼
結果
0 False
1 False
2 True
3 False
dtype: bool
複製代碼
操做的核心方法是 df.drop_duplicates(),該方法的做用是基於指定的規則判斷爲重複值以後,刪除重複值,其參數跟df.duplicated()徹底相同。在該部分方法示例中,依次使用默認規則(所有列相同的數據記錄)、col1列相 同、col2列相同以及指定col1和col2徹底相同四種規則進行去重。
# 刪除重複值
new_df1 = df.drop_duplicates() # 刪除數據記錄中全部列值相同的記錄
print(new_df1) # 打印輸出
複製代碼
結果
col1 col2
0 a 3
1 b 2
3 c 2
複製代碼
# 刪除重複值
new_df2 = df.drop_duplicates(['col1']) # 刪除數據記錄中col1值相同的記錄
print(new_df2) # 打印輸出
複製代碼
結果
col1 col2
0 a 3
1 b 2
3 c 2
複製代碼
# 刪除重複值
new_df3 = df.drop_duplicates(['col2']) # 刪除數據記錄中col2值相同的記錄
print(new_df3) # 打印輸出
複製代碼
結果
col1 col2
0 a 3
1 b 2
複製代碼
# 刪除重複值
new_df4 = df.drop_duplicates(['col1', 'col2']) # 刪除數據記錄中指定列(col1/col2)值相同的記錄
print(new_df4) # 打印輸出
複製代碼
結果
col1 col2
0 a 3
1 b 2
3 c 2
複製代碼