数据预处理
- 原因
在数据挖掘中,海量的原始数据中存在着大量不完整(有缺失值)、不一致、有异常的数据,严重影响到数据挖掘建模的执行效率,甚至可能导致挖掘结果的偏差。 - 概念
进行数据清洗就显得尤为重要,数据清洗完成后接着进行或者同时进行数据集成、转换、规约等一系列的处理,该过程就是数据预处理。 - 目的
数据预处理一方面是要提高数据的质量,另一方面是要让数据更好地适应特定的挖掘技术或工具。 - 重要性
统计发现,在数据挖掘的过程中,数据预处理工作 量占到了整个过程的60%。 - 过程
数据预处理的主要内容包括数据清洗、数据集成、数据变换和数据规约。
数据清洗
数据清洗主要是删除原始数据集中的无关数据、重复数据,平滑噪声数据,筛选掉与挖掘主题无关的数据,处理缺失值、异常值等。
缺失值处理
处理缺失值的方法可分为3类:删除记录、数据插补和不处理。
常用的插补方法
插补方法 | 方法描述 |
---|---|
均值/中位数/众数插补 | 根据属性值的类型,用该属性取值的平均数/中位数/众数进行插补 |
使用固定值 | 将缺失的属性值用一个常量替换。如广州一个工厂普通外来务工人员的“基本工 资”属性的空缺值可以用2015年广州市普通外来务工人员工资标准1895元/月,该方法就是使用固定值 |
最近临插补 | 在记录中找到与缺失样本最接近的样本的该属性值插补 |
回归方法 | 对带有缺失值的变量,根据已有数据和与其有关的其他变量(因变量)的数据建立拟合模型来预测缺失的属性值 |
插值法 | 插值法是利用已知点建立合适的插值函数/(X),未知值由对应点X,求出的函数值 / (X,)近似代替 |
删除数据
如果通过简单的删除小部分记录达到既定的目标,那么删除含有缺失值的记录的方法是最有效的。然而,这种方法却有很大的局限性。它是以减少历史数据来换取数据的完备,会 造成资源的大量浪费,将丢弃了大量隐藏在这些记录中的信息。尤其在数据集本来就包含很 少记录的情况下,删除少量记录可能会严重影响到分析结果的客观性和正确性。一些模型可 以将缺失值视作一种特殊的取值,允许直接在含有缺失值的数据上进行建模。重点介绍拉格朗日插值法和牛顿插值法
(1)拉格朗日插值法
根据数学知识可知,对于平面上已知的n个点(无两点在一条直线上)可以找一个n-1次多项式,使此多项式曲线过这n个点。
1)求已知的过n个点的n-1次多项式:
将n个点的坐标代入多项式函数,得:
解出拉格朗日插值多项式为:
2 )将缺失的函数值对应的点x代入插值多项式得到缺失值的近似值 A(x)。
拉格朗日插值公式结构紧凑,在理论分析中很方便,但是当插值节点增减时,插值多项式就会随之变化,这在实际计算中是很不方便的,为了克服这一缺点,提出了牛顿插值法。
(2)牛顿插值法
1)求已知的n个点对的所有阶差商公式:
2)联立以上差商公式建立如下插值多项式f(x):
其中:
P(x)是牛顿插值逼近函数,R(x)是误差函数。
3)将缺失的函数值对应的点x代入插值多项式得到缺失值的近似值L(x)。
牛顿插值法也是多项式插值,但采用了另一种构造插值多项式的方法,与拉格朗日插值相比,具有承袭性和易于变动节点的特点。从本质上来说,两者给出的结果是一样的(相同次数、相同系数的多项式),只不过表示的形式不同。因此,在Python的Scipy库中,只提供了拉格朗日插值法的函数(因为实现上比较容易),如果需要牛顿插值法,则需要自行编写函数。结合具体案例介绍拉格朗日插值实现方法
餐饮系统中的销量数据可能会出现缺失值
某餐厅 一段时间的销 量数据
时 间 | 2015/2/25 | 2015/2/24 | 2015/2/23 | 2015/2/22 | 2015/2/21 | 2015/2/20 |
---|---|---|---|---|---|---|
销售额(元) | 3442.1 | 3393.1 | 3136.6 | 3744.1 | 6607.4 | 4060.3 |
时 间 | 2015/2/19 | 2015/2/18 | 2015/2/16 | 2015/2/15 | 2015/2/14 | 2015/2/13 |
销售额(元) | 3614.7 | 3295.5 | 2332.1 | 2699.3 | 空值 | 3036.8 |
# 某餐厅一段时间的销量数据
import pandas as pd # 导入数据分析库Pandas
from scipy.interpolate import lagrange # 导入拉格朗日插值函数
import warnings
warnings.filterwarnings('ignore')
inputfile = '../data/catering_sale.xls' # 销量数据路径
outputfile = '../tmp/sales.xls' #输出数据路径
data = pd.read_excel(inputfile) # 读入数据
data['销量'][(data['销量'] < 400) | (data['销量'] > 5000)] = None # 过滤异常值,将其变为空值
# 自定义列向量插值函数
# s为列向量,n为被插值的位置,k为取前后的数据个数,默认为5
def ployinterp_column(s, n, k=5):
# y = s[list(range(n-k, n)) + list(range(n+1, n+1+k))] # 取数
y = s.reindex(list(range(n-k, n)) + list(range(n+1, n+1+k)))
y = y[y.notnull()] # 剔除空值
return lagrange(y.index, list(y))(n) # 插值并返回插值结果
# 逐个元素判断是否需要插值
for i in data.columns:
for j in range(len(data)):
if (data[i].isnull())[j]: # 如果为空即插值。
data[i][j] = ployinterp_column(data[i], j)
# data.to_excel(outputfile) #输出结果,写入文件
data
应用拉格朗日插值法算对表的缺失值进行插补,使用缺失值前后各5个未缺失的数据参与建模,得插值结果如下所示:
时 间 | 原始值 | 插 值 |
---|---|---|
2015/2/21 | 6607.4 | 4275.255 |
2015/2/14 | 空值 | 4156.86 |
在进行插值之前会对数据进行异常值检测,发现2015/2/21日的数据是异常的(数据大5000),所以也把此日期数据定义为空缺值,进行补数。利用拉格朗日插值对这2015/2/21和2015/2/14的数据进行插补,结果是4275.255和4156.86,这两天都是周末,而周末的销售额一般要比周一到周五要多,所以插值结果比较符合实际情况。
异常值处理
在数据预处理时,异常值是否剔除,需视具体情况而定,因为有些异常值可能蕴含着有用的信息。
- 异常值处理常用方法
异常值处理方法 | 方法描述 |
---|---|
删除含有异常值的记录 | 直接将含有异常值的记录删除 |
视为缺失值 | 将异常值视为缺失值,利用缺失值处理的方法进行处理 |
平均值修正 | 可用前后两个观测值的平均值修正该异常值 |
不处理 | 直接在具有异常值的数据集上进行挖掘建模 |
将含有异常值的记录直接删除的方法简单易行,但缺点也很明显,在观测值很少的情况下,这种删除会造成样本量不足,可能会改变变量的原有分布,从而造成分析结果的不准确。视为缺失值处理的好处是可以利用现有变量的信息,对异常值(缺失值)进行填补。
在很多情况下,要先分析异常值出现的可能原因,再判断异常值是否应该舍弃,如果是正确的数据,可以直接在具有异常值的数据集上进行挖掘建模。