数据预处理系列:(七)处理缺失值

时间:2022-12-20 22:44:31

声明:版权所有,转载请联系作者并注明出处  http://blog.csdn.net/u013719780?viewmode=contents


博主简介:风雪夜归子(英文名: Allen),机器学习算法攻城狮,喜爱钻研Machine Learning的黑科技,对Deep Learning和Artificial Intelligence充满兴趣,经常关注kaggle数据挖掘竞赛平台,对数据、Machine Learning和Artificial Intelligence有兴趣的各位童鞋可以一起探讨哦,个人CSDN博客: http://blog.csdn.net/u013719780?viewmode=contents


处理缺失值

实践中数值计算不可或缺,好在有很多方法可用,这个主题将介绍其中一些。不过,这些方法未必能解决你的问题。

scikit-learn有一些常见的计算方法,它可以对现有数据进行变换填补NA值。但是,如果数据集中的缺失值是有意而为之的——例如,服务器响应时间超过100ms——那么更合适的方法是用其他包解决,像处理贝叶斯问题的PyMC,处理风险模型的lifelines,或者自己设计一套方法。

Getting ready

处理缺失值的第一步是创建缺失值。Numpy可以很方便的实现:

In [2]:
from sklearn import datasets
import numpy as np
iris = datasets.load_iris()
iris_X = iris.data
masking_array = np.random.binomial(1, .25, iris_X.shape).astype(bool)
iris_X[masking_array] = np.nan

让我们看看这几行代码,Numpy和平时用法不太一样,这里是在数组中用了一个数组作为索引。为了创建了随机的缺失值,先创建一个随机布尔值数组,其形状和iris_X数据集的维度相同。然后,根据布尔值数组分配缺失值。因为每次运行都是随机数据,所以masking_array每次都会不同。

In [3]:
masking_array[:5]
Out[3]:
array([[False,  True, False, False],
[False, True, False, False],
[False, False, False, False],
[ True, False, False, True],
[False, False, True, False]], dtype=bool)
In [4]:
iris_X[:5]
Out[4]:
array([[ 5.1,  nan,  1.4,  0.2],
[ 4.9, nan, 1.4, 0.2],
[ 4.7, 3.2, 1.3, 0.2],
[ nan, 3.1, 1.5, nan],
[ 5. , 3.6, nan, 0.2]])

How to do it...

本书贯穿始终的一条原则(由于scikit-learn的存在)就是那些拟合与转换数据集的类都是可用的,可以在其他数据集中继续使用。具体演示如下所示:

In [5]:
from sklearn import preprocessing
impute = preprocessing.Imputer()
iris_X_prime = impute.fit_transform(iris_X)
iris_X_prime[:5]
Out[5]:
array([[ 5.1       ,  3.05221239,  1.4       ,  0.2       ],
[ 4.9 , 3.05221239, 1.4 , 0.2 ],
[ 4.7 , 3.2 , 1.3 , 0.2 ],
[ 5.86306306, 3.1 , 1.5 , 1.21388889],
[ 5. , 3.6 , 3.82685185, 0.2 ]])

注意[3,0]位置的不同:

In [6]:
iris_X_prime[3,0]
Out[6]:
5.8630630630630645
In [8]:
iris_X[3,0]
Out[8]:
nan

How it works...

上面的计算可以通过不同的方法实现。默认是均值mean,一共是三种:

  • 均值mean(默认方法)
  • 中位数median
  • 众数most_frequent

scikit-learn会用指定的方法计算数据集中的每个缺失值,然后把它们填充好。

例如,用median方法重新计算iris_X,重新初始化impute即可:

In [9]:
impute = preprocessing.Imputer(strategy='median')
iris_X_prime = impute.fit_transform(iris_X)
iris_X_prime[:5]
Out[9]:
array([[ 5.1 ,  3.  ,  1.4 ,  0.2 ],
[ 4.9 , 3. , 1.4 , 0.2 ],
[ 4.7 , 3.2 , 1.3 , 0.2 ],
[ 5.8 , 3.1 , 1.5 , 1.3 ],
[ 5. , 3.6 , 4.45, 0.2 ]])

如果数据有缺失值,后面计算过程中可能会出问题。例如,在How to do it...一节里面,np.nan作为默认缺失值,但是缺失值有很多表现形式。有时用-1表示。为了处理这些缺失值,可以在方法中指定那些值是缺失值。方法默认缺失值表现形式是Nan,就是np.nan的值。

假设我们将iris_X的缺失值都用-1表示。看着很奇怪,但是iris数据集的度量值不可能是负数,因此用-1表示缺失值完全合理:

In [10]:
iris_X[np.isnan(iris_X)] = -1
iris_X[:5]
Out[10]:
array([[ 5.1, -1. ,  1.4,  0.2],
[ 4.9, -1. , 1.4, 0.2],
[ 4.7, 3.2, 1.3, 0.2],
[-1. , 3.1, 1.5, -1. ],
[ 5. , 3.6, -1. , 0.2]])

填充这些缺失值也很简单:

In [11]:
impute = preprocessing.Imputer(missing_values=-1)
iris_X_prime = impute.fit_transform(iris_X)
iris_X_prime[:5]
Out[11]:
array([[ 5.1       ,  3.05221239,  1.4       ,  0.2       ],
[ 4.9 , 3.05221239, 1.4 , 0.2 ],
[ 4.7 , 3.2 , 1.3 , 0.2 ],
[ 5.86306306, 3.1 , 1.5 , 1.21388889],
[ 5. , 3.6 , 3.82685185, 0.2 ]])

There's more...

pandas库也可以处理缺失值,而且更加灵活,但是重用性较弱:

In [12]:
import pandas as pd
iris_X[masking_array] = np.nan
iris_df = pd.DataFrame(iris_X, columns=iris.feature_names)
iris_df.fillna(iris_df.mean())['sepal length (cm)'].head(5)
Out[12]:
0    5.100000
1 4.900000
2 4.700000
3 5.863063
4 5.000000
Name: sepal length (cm), dtype: float64

其灵活性在于,fillna可以填充任意统计参数值:

In [13]:
iris_df.fillna(iris_df.max())['sepal length (cm)'].head(5)
Out[13]:
0    5.1
1 4.9
2 4.7
3 7.9
4 5.0
Name: sepal length (cm), dtype: float64