缺失值的類型
首先對數據的變量(特征)按照缺失和不缺失進行分類:不含有缺失值的變量稱為完全變量,含有缺失值的變量稱為非完全變量。
缺失值的類型分為三種:完全隨機缺失,隨機缺失和非隨機缺失。
完全隨機缺失: 缺失的變量和其余的變量沒有關系。比如”家庭住址“這個信息,和”身高“等其余的變量沒有關系。
隨機缺失: 缺失的變量和完全變量存在一定的關系。假如“學歷”中不含缺失值,“收入”和它有關,那么“收入”為隨機缺失。
非隨機缺失:缺失的變量和非完全變量存在一定的關系。
根據上面變量的分類,其實我們已經大致可以想出來一些處理缺失值的方法了:比如對於完全隨機缺失,我們可以選擇丟棄或者是依靠變量自身未缺失值的信息(均值、方差)進行補全。 而對於隨機缺失,我們可以利用完全變量的信息來進行補全。
數據處理的方法
總的來說,在處理缺失值的時候我們可以采用三種方法,第一種是不作處理,這個很簡單,把缺失值放在那里就可以了。 第二種方法是進行刪除操作。 第三種方法就是進行數據的補全操作。
刪除操作
當某個特征上面的數據缺失太大的時候,直接將這個特征刪除了。
而當特征上面的缺失值很少的時候,比如只有幾個缺失值的時候,可以考慮把包含這些缺失值的元組進行刪除。
補全操作
實際當中用的最多的還是補全操作,補全操作有很多種,按照參考文章一的划分有很多種,可以看原文查看具體的類型,這里我只介紹自己目前明白的幾種:
1:人工填充:根據已經掌握的數據的知識進行填充,但是這個方法在數據量很大,缺失值很多的時候明顯是不可以的。
2:特殊值填充:將缺失值用unknown表示,這和原來的缺失值的意思還是有一點差別的。在這里unknown可以當做一種取值的可能性。
3:平均值填充。 對於數字類型的變量,可以使用沒有缺失值的一些信息進行估計,使用用平均值進行的估計稱為平均值填充。對於分類變量可以使用眾數來進行填充。其實也可以加上一點方差的信息來進行估計,我在后面的例子當中來說明這一點。
4:將數據映射到高維,第二個參考文章。這個方法有點暴力,使得特征的數量大大的增加,但是保留原始數據的全部信息。
5:使用其它的變量來進行預估。 這里的方法就多了,包括文章中講的回歸,期望最大化方法和C4.5方法。這里因為都沒有接觸過,就不寫了。
下面我將用一些例子來說明如何如何處理缺失值
使用pandas來處理泰坦尼克號的數據
數據集的准備:
我們使用kaggle 的titanic的數據來進行實驗,https://www.kaggle.com/c/titanic/data
首先導入數據集
import pandas as pd
train_df = pd.read_csv('../input/train.csv') print(train_df.info())
看一下各個特征里面數據的缺失情況
<class 'pandas.core.frame.DataFrame'> RangeIndex: 891 entries, 0 to 890 Data columns (total 12 columns): PassengerId 891 non-null int64 Survived 891 non-null int64 Pclass 891 non-null int64 Name 891 non-null object Sex 891 non-null object Age 714 non-null float64 SibSp 891 non-null int64 Parch 891 non-null int64 Ticket 891 non-null object Fare 891 non-null float64 Cabin 204 non-null object Embarked 889 non-null object dtypes: float64(2), int64(5), object(5) memory usage: 83.6+ KB
其中Age,Cabin,和Embarked三個數據有缺失,
對Cabin和Embarked進行處理
對於Cabin的數據,因為它的缺失值太多了,所以我們的做法就是直接刪除掉,直接把這一個特征刪除了就可以了
train_df = train_df.drop(['Cabin'], axis=1)
對於Embarked特征來說,它有兩個缺失值,我們可以刪除了包含有缺失值的兩條記錄
train_df = train_df.drop(train_df[train_df['Embarked'].isnull()].index, axis=0)
也可以用眾數進行填充
embarked_mode = train_df['Embarked'].mode()[0] train_df['Embarked'] = train_df['Embarked'].fillna(embarked_mode)
對於Age信息的補全
最容易想到的就是用平均值來進行補充
age_mean = train_df['Age'].dropna().mean() train_df['Age'] = train_df['Age'].fillna(age_mean)
當然也可以利用均值和方差(標准差)的信息進行一些填充
import numpy as np age_mean = train_df['Age'].dropna().mean() age_std = train_df['Age'].dropna().std() age_nan_num = train_df['Age'].isnull().sum() #在 (均值-標准差) 和 (均值+標准差) 之間產生一些均分分布的數作為填充 fill_age = np.random.randint(age_mean - age_std, age_mean + age_std , size=age_nan_num) train_df.loc[train_df['Age'].isnull(),'Age'] = fill_age
此外,就是利用別的屬性的信息進行填充,比如在泰塔尼克號數據當中,我們分析性別和登陸的港口不同,他們的年齡可能也不同,於是我們可以這樣做,為每個類別的人填充不同的值。
#先將數據轉換一下,好進行處理 train_df['Sex'] = train_df['Sex'].map({'male':0, 'female':1}) train_df['Embarked'] = train_df['Embarked'].map({'C':0, 'Q':1, 'S':2}) fill_ages = np.zeros((2, 3)) for i in range(0, 2): for j in range(0, 3): age_i_j = train_df.loc[(train_df['Sex'] == i) & (train_df['Embarked'] == j), \ 'Age'].dropna() fill_ages[i, j] = age_i_j.median() #這里可以選擇均值,還有隨機值等 for i in range(0, 2): for j in range(0, 3): train_df.loc[(train_df['Age'].isnull()) & (train_df['Sex'] == i) & \ (train_df['Embarked'] == j), 'Age'] = fill_ages[i, j]
sklearn中處理缺失值的方法
sklearn.preprocessing的Imputer方法可以進行缺失值的處理,可以選擇平均數,眾數或者中位數來填充缺失的值。
from sklearn.preprocessing import Imputer import numpy as np #strategy表示采用何種策略,有mean,median, most_frequent #axis=0, 表示在咧上面進行操作, axis=1表示在行上面進行操作 imp = Imputer(missing_values='NaN', strategy='mean', axis=0) #通過fit以后,得到第一列的均值為(1+7)/2 = 4 ,第二列的均值為11/3, ## 以后進行transform的時候,直接將這些值填充過去就可以了 imp.fit([[1, 2], [np.nan, 3], [7, 6]]) X = [[np.nan, 2], [6, np.nan], [7, 6]] print(imp.transform(X))
輸出結果如下:
[[4. 2. ] [6. 3.66666667] [7. 6. ]]
參考:
