缺失值的类型
首先对数据的变量(特征)按照缺失和不缺失进行分类:不含有缺失值的变量称为完全变量,含有缺失值的变量称为非完全变量。
缺失值的类型分为三种:完全随机缺失,随机缺失和非随机缺失。
完全随机缺失: 缺失的变量和其余的变量没有关系。比如”家庭住址“这个信息,和”身高“等其余的变量没有关系。
随机缺失: 缺失的变量和完全变量存在一定的关系。假如“学历”中不含缺失值,“收入”和它有关,那么“收入”为随机缺失。
非随机缺失:缺失的变量和非完全变量存在一定的关系。
根据上面变量的分类,其实我们已经大致可以想出来一些处理缺失值的方法了:比如对于完全随机缺失,我们可以选择丢弃或者是依靠变量自身未缺失值的信息(均值、方差)进行补全。 而对于随机缺失,我们可以利用完全变量的信息来进行补全。
数据处理的方法
总的来说,在处理缺失值的时候我们可以采用三种方法,第一种是不作处理,这个很简单,把缺失值放在那里就可以了。 第二种方法是进行删除操作。 第三种方法就是进行数据的补全操作。
删除操作
当某个特征上面的数据缺失太大的时候,直接将这个特征删除了。
而当特征上面的缺失值很少的时候,比如只有几个缺失值的时候,可以考虑把包含这些缺失值的元组进行删除。
补全操作
实际当中用的最多的还是补全操作,补全操作有很多种,按照参考文章一的划分有很多种,可以看原文查看具体的类型,这里我只介绍自己目前明白的几种:
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. ]]
参考: