Python数据分析与挖掘实战学习笔记(3)

Chapter4 数据预处理

序言

 在数据挖掘中,海量的原始数据中存在着大量不完整(有缺失值)、不一致、有异常的数据,严重影响到数据挖掘建模的执行效率,甚至可能导致挖掘结果的偏差,所以进行数据清洗显得尤为重要,数据清洗完成后接着进行或者同时进行数据集成、转换、规约等一系列的处理,该过程就是数据预处理。数据预处理一方面是要提高数据的质量,另一方面是要让数据更好地适应特定的挖掘技术或工具。

数据清洗

 数据清洗主要是删除原始数据集中的无关数据、重复数据,平滑噪声数据,筛选掉与挖掘主题无关的数据,处理缺失值、异常值等。

缺失值处理

 处理缺失值的方法可分为3类:删除记录、数据插补和不处理。其中常用的数据插补方法下下表:

插补方法 方法描述
均值/中位数/众数插补 根据属性值的类型,用该属性值的平均数/中位数/众数进行插补
使用固定值 将缺失的属性值用一个常量替换
最近临插补 在记录中找到与缺失样本最接近的样本的该属性值插补
回归方法 对带有缺失值的变量,根据已有数据和与其有关的其他变量的数据建立拟合模型来预测缺失的属性值
插值法 插值法是利用已知点建立合适的插值函数f(x),未知值由对应点xi求出的函数值f(xi)近似代替

 如果通过删除小部分记录达到既定的目标,那么删除含有缺失值的记录的方法是最有效的。然而,这种方法却有很大的局限性。它是以减少历史数据来换取数据的完备,会造成资源的大量浪费,将丢弃了大量隐藏在这些记录中的信息。尤其在数据集本来就包含很少的情况下,删除少量记录可能会严重影响到分析结果的客观性和正确性。一些模型可以将缺失值视作一种特殊的取值,允许直接在含有缺失值的数据集上进行建模。
 餐饮系统中的销量数据可能会出现缺失值,如下表所示,让我们用拉格朗日插值法进行插补。
在这里插入图片描述
拉格朗日插值代码:

import pandas as pd   # 导入数据分析库Pandas
from scipy.interpolate import lagrange   # 导入拉格朗日插值函数
inputfile = './data/catering_sale.xls'  # 销量数据路径
outputfile = './tmp/sales.xls'  # 输出数据路径
data = pd.read_excel(inputfile)  # 读入数据
data[u'销量'][(data[u'销量'] < 400) | (data[u'销量'] > 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 = 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)  # 输出结果,写入文件

结果:
在这里插入图片描述

异常值处理

 在数据预处理时,异常值是否剔除,需视具体情况而定,因为有些异常值可能蕴含着有用的信息。异常值常用方法见下表:

异常值处理方法 方法描述
删除含有异常值的记录 直接将含有异常值的记录删除
视为缺失值 将异常值视为缺失值,利用缺失值处理的方法进行处理
平均值修正 可用前后两个观测值的平均值修正该异常值
不处理 直接在具有异常值的数据集上进行挖掘建模

 将含有异常值的记录直接删除的方法简单易行,但缺点也很明显,在观测值很少的情况下,这种删除会造成样本量不足,可能会改变变量的原有分布,从而造成分析结果的不准确。视为缺失值处理的好处是可以利用现有变量的信息,对异常值(缺失值)进行填补。
 在很多情况下,要先分析异常值出现的可能原因,再判断异常值是否应该舍弃,如果是正确的数据,可以直接在具有异常值的数据集上进行挖掘建模。

数据集成

 数据挖掘需要的数据往往分布在不同的数据源中,数据集成就是将多个数据源合并存放在一个一致的数据存储(数据仓库)中的过程。
 在数据集成时,来自多个数据源的现实世界实体的表达形式是不一样的,有可能不匹配,要考虑实体识别问题和属性冗余问题,从而将源数据在最低层上加以转换、提炼和集成。

实体识别

 实体识别是指从不同数据源识别出现实世界的实体,它的任务是统一不同数据源的矛盾之处,常见形式有:

  1. 同名异义
  2. 异名异义
  3. 单位不统一

冗余属性识别

 数据集成往往导致数据冗余,例如:

  1. 同一属性多次出现
  2. 同一属性命名不一致导致重复

 仔细整合不同源数据能减少甚至避免数据冗余与不一致,从而提高数据挖掘的速度和质量。对于冗余属性要先分析,检测到后再将其删除。

数据变换

 数据变换主要是对数据进行规范化处理,将数据转化成“适当的”形式,以适用于挖掘任务及算法的需要。

简单函数变换

 简单函数变换是对原始数据进行某些数学函数变换,常用的变换包括平方、开方、取对数、差分运算等。简单函数变换常用来将不具有正态分布的数据变换成具有正态分布的数据。在时间序列分析中,有时简单的对数变换或者差分运算就可以将非平稳序列转换成平稳序列。

规范化

 数据规范化(归一化)处理是数据挖掘的一项基础工作。不同评价指标往往具有不同的量纲,数值间的差别可能很大,不进行处理可能会影响到数据分析的结果。为了消除指标间的量纲和取值范围差异的影响,需要进行标准化处理,将数据按照比例进行缩放,使之落入一个特定的区域,便于进行综合分析。

# 规范化包括最小-最大规范化(离差标准化)、
# 零-均值规范化(标准差标准化)、小数定标规范化
import pandas as pd
import numpy as np
datafile = './data/normalization_data.xls'  # 参数标准化
data = pd.read_excel(datafile, header=None)  # 读取数据
normalizeddata1 = (data - data.min()) / (data.max() - data.min())   # 最小-最大规范化
normalizeddata2 = (data - data.mean()) / data.std()   # 零-均值规范化
normalizeddata3 = data / 10**np.ceil(np.log10(data.abs().max()))  # 小数定标规范化
print(data, '\n')  # 查看原始数据
print(normalizeddata1, '\n')  # 查看最小-最大规范化数据
print(normalizeddata2, '\n')  # 查看零-均值规范化数据
print(normalizeddata3)  # 查看小数定标规范化数据
      原始数据
    0    1    2     3
0   78  521  602  2863
1  144 -600 -521  2245
2   95 -457  468 -1283
3   69  596  695  1054
4  190  527  691  2051
5  101  403  470  2487
6  146  413  435  2571 
           最小-最大规范化数据
      0         1         2         3
0  0.074380  0.937291  0.923520  1.000000
1  0.619835  0.000000  0.000000  0.850941
2  0.214876  0.119565  0.813322  0.000000
3  0.000000  1.000000  1.000000  0.563676
4  1.000000  0.942308  0.996711  0.804149
5  0.264463  0.838629  0.814967  0.909310
6  0.636364  0.846990  0.786184  0.929571 
            零-均值规范化数据
          0         1         2         3
0 -0.905383  0.635863  0.464531  0.798149
1  0.604678 -1.587675 -2.193167  0.369390
2 -0.516428 -1.304030  0.147406 -2.078279
3 -1.111301  0.784628  0.684625 -0.456906
4  1.657146  0.647765  0.675159  0.234796
5 -0.379150  0.401807  0.152139  0.537286
6  0.650438  0.421642  0.069308  0.595564 
      小数定标规范化数据
       0      1      2       3
0  0.078  0.521  0.602  0.2863
1  0.144 -0.600 -0.521  0.2245
2  0.095 -0.457  0.468 -0.1283
3  0.069  0.596  0.695  0.1054
4  0.190  0.527  0.691  0.2051
5  0.101  0.403  0.470  0.2487
6  0.146  0.413  0.435  0.2571

连续离散属性化

 一些数据挖掘算法,特别是某些分类算法(如ID3算法、Apriori算法等),要求数据是分类属性形式。这样,常常需要将连续属性变换成分类属性,即连续属性离散化。

离散化过程

 连续属性离散化就是在数据的取值范围内设定若干个离散的划分点,将取值范围划分为一些离散化的区间,最后用不同的符号或整数值代表落在每个子区间中的数据值。离散化涉及的两个子任务:确定分类数、将连续属性值映射到这些分类值。

常用的离散化方法

 等宽法、等频法、基于聚类分析的方法(如k-means算法)

# 下面使用上述的三种离散化方法对“医学中中医证型
# 的相关数据”进行连续属性离散化的对比。
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans  # 引入KMeans
# 数据规范化
datafile = './data/discretization_data.xls'  # 参数初始化
data = pd.read_excel(datafile)  # 读取数据
data = data[u'肝气郁结证型系数'].copy()
k = 4
d1 = pd.cut(data, k, labels=range(k))  # 等高离散化,各个类比依次命名为0,1,2,3
# 等频率离散化
w = [1.0*i/k for i in range(k+1)]
w = data.describe(percentiles=w)[4:4+k+1]  # 使用describe函数自动计算分位数
w[0] = w[0] * (1-1e-10)
d2 = pd.cut(data, w, labels=range(k))
# 基于聚类分析的方法
kmodel = KMeans(n_clusters=k, n_jobs=4)  # 建立模型,n_jobs是并行数,一般等于CPU数较好
kmodel.fit(data.values.reshape((len(data), 1)))  # 训练模型
c = pd.DataFrame(kmodel.cluster_centers_).sort_values(0)  # 输出聚类中心,并且排序(默认是随机序的)
w = c.rolling(2).mean().iloc[1:]  # 相邻两项求中点,作为边界点
w = [0] + list(w[0]) + [data.max()]  # 把首末边界点加上
d3 = pd.cut(data, w, labels=range(k))
def cluster_plot(d, k):  # 自定义作图函数来显示聚类结果
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    plt.figure(figsize=(8, 3))
    for j in range(0, k):
        plt.plot(data[d == j], [j for i in d[d == j]], 'o')
    plt.ylim(-0.5, k-0.5)
    return plt
cluster_plot(d1, k).show()
cluster_plot(d2, k).show()
cluster_plot(d3, k).show()

等宽离散化结果:
在这里插入图片描述

属性构造

  为了提取更有用的信息,挖掘更深层次的模式,提高挖掘结果的精度,我们需要利用已有的属性集构造出新的属性,并加入到现有的属性集合中。

# 在进行防窃漏电诊断建模时,已有的属性包括供入电量、
# 供出电量(线路上各大用户用电量之和),
# 为了判断是否有大用户存在切漏电行为,
# 可以构造出一个新的指标----线损率
# ((供入电量 - 供出电量)/供入电量),正常范围一般为3%-15%,
# 如果远远超过该范围,就可以认为该条线路的大用户很可能
# 存在窃漏电等用电异常行为。
# 由供入电量、供出电量进行线损率的属性构造
import pandas as pd
# 参数初始化
inputfile = './data/electricity_data.xls'  # 供入供出电量数据
outputfile = './tmp/electricity_data.xls'  # 属性构造后数据文件
data = pd.read_excel(inputfile)  # 读入数据
data[u'线损率'] = (data[u'供入电量'] - data[u'供出电量']) / data[u'供入电量']
data.to_excel(outputfile, index=False)  # 保存结果

小波变换

  小波变换具有多分辨率的特点,在时域和频域都具有表征局部信号的能力,通过伸缩和平移等运算过程对信号进行多尺度聚焦分析,提供了一种非平稳信号的时频分析手段,小波变换可以把非平稳信号分解为表达不同的层次、不同频带信息的数据序列,即小波系数,可以由粗及细地逐步观察信号,从中提取出有用的信息。基于小波变换的特征提取方法:基于小波变换的多尺度空间能量分布特征提取、基于小波变换的多尺度空间的模极大值特征提取、基于小波包变换的特征提取、基于适应性小波神经网络的特征提取。

# 利用小波分析进行特征分析:
import pandas as pd
from scipy.io import loadmat  # mat是Python专用格式,需要用loadmat读取它。
import pywt  # 导入PyWavelets
inputfile = './data/leleccum.mat'  # 参数初始化-----提取自Matlab的信号文件
mat = loadmat(inputfile)
signal = mat['leleccum'][0]
# 返回结果为level+1个数字,第一个数组为逼近系数数组,后面的依次是细节系数数组
coeffs = pywt.wavedec(signal, 'bior3.7', level=5)
print(coeffs)
 部分结果:
[2415.1478541 , 2395.74470824, 2402.22022728, 2408.90987352,
   2402.22022728, 2395.74470824, 2415.1478541 , 2369.53622493,
   1958.0913368 , 1983.87619596, 1901.68851538, 1651.86483216,
   1482.45129628, 1356.98779058, 1257.4459793 , 1265.75505172,
   1363.66712581, 1427.53767222, 1568.87951307, 1893.80694993,
   2295.89161125, 2555.9239482 , 2778.31817145, 2871.0940301 ,...]

数据规约

 在大数据集上进行复杂的数据分析和挖掘需要很长的时间,数据规约产生更小但担保原数据完整性的新数据集。在规约后的数据集上进行分析和挖掘将更加有效率。
数据规约的意义:

  1. 降低无效或错误数据对建模的影响,提高数据的准确性;
  2. 少量且具有代表性的数据将大幅缩减数据挖掘所需的时间;
  3. 降低存储数据的成本。

属性规约

 属性规约通过属性合并来创建新属性维数,或者直接通过删除不相关属性(维)来减少数据的维数,从而提高数据挖掘的效率、降低计算成本。属性规约的目标是寻找出最小的属性子集并确保新数据子集的概率分布尽可能地接近原来数据集的概率分布。
属性规约常用方法:
 合并属性、逐步向前选择、逐步向后删除、决策树归纳、主成分分析(PCA)
PCA算法:
 它是一种用于连续属性的数据降维方法,它构造了原始数据的一个正交变换,新空间的基底去除了原始空间基底下的数据的相关性,只需使用少数新变量就能够解释原始数据中的大部分变异。

# 主成分分析代码
import pandas as pd
from sklearn.decomposition import PCA
# 参数初始化
inputfile = './data/principal_component.xls'
data = pd.read_excel(inputfile, header=None)  # 读入数据
pca = PCA()
pca.fit(data)
print(pca.components_, '\n')  # 返回模型的各个特征向量
print(pca.explained_variance_ratio_)  #返回各个成分各自的方差百分比(贡献率)

结果:

各个特征向量
[[ 0.56788461 0.2280431 0.23281436 0.22427336 0.3358618 0.43679539
0.03861081 0.46466998]
[ 0.64801531 0.24732373 -0.17085432 -0.2089819 -0.36050922 -0.55908747
0.00186891 0.05910423]
[-0.45139763 0.23802089 -0.17685792 -0.11843804 -0.05173347 -0.20091919
-0.00124421 0.80699041]
[-0.19404741 0.9021939 -0.00730164 -0.01424541 0.03106289 0.12563004
0.11152105 -0.3448924 ]
[-0.06133747 -0.03383817 0.12652433 0.64325682 -0.3896425 -0.10681901
0.63233277 0.04720838]
[ 0.02579655 -0.06678747 0.12816343 -0.57023937 -0.52642373 0.52280144
0.31167833 0.0754221 ]
[-0.03800378 0.09520111 0.15593386 0.34300352 -0.56640021 0.18985251
-0.69902952 0.04505823]
[-0.10147399 0.03937889 0.91023327 -0.18760016 0.06193777 -0.34598258
-0.02090066 0.02137393]]
[7.74011263e-01 1.56949443e-01 4.27594216e-02 2.40659228e-02
1.50278048e-03 4.10990447e-04 2.07718405e-04 9.24594471e-05] (模型的各个成分各自的方差百分比(贡献率))

由结果可知,当选取前4个成分时,累计贡献率已达到97.37%,说明选取前3个主成分进行计算已经相当不错了,因此可以重新建立PCA模型。

# 设置n_components=3, 计算出成分结果:
import pandas as pd
from sklearn.decomposition import PCA
# 参数初始化
inputfile = './data/principal_component.xls'
outputfile = './tmp/dimention_reducted.xls'  # 降维后的数据
data = pd.read_excel(inputfile, header=None)  # 读入数据
pca = PCA(3)
pca.fit(data)
low_d = pca.transform(data)  # 用它来降低维度
pd.DataFrame(low_d).to_excel(outputfile)  # 保存结果
pca.inverse_transform(low_d)  # 必要时可以用inverse_transfrom()函数来复原数据
print(low_d)

[[ 8.19133694 16.90402785 3.90991029]
[ 0.28527403 -6.48074989 -4.62870368]
[-23.70739074 -2.85245701 -0.4965231 ]
[-14.43202637 2.29917325 -1.50272151]
[ 5.4304568 10.00704077 9.52086923]
[ 24.15955898 -9.36428589 0.72657857]
[ -3.66134607 -7.60198615 -2.36439873]
[ 13.96761214 13.89123979 -6.44917778]
[ 40.88093588 -13.25685287 4.16539368]
[ -1.74887665 -4.23112299 -0.58980995]
[-21.94321959 -2.36645883 1.33203832]
[-36.70868069 -6.00536554 3.97183515]
[ 3.28750663 4.86380886 1.00424688]
[ 5.99885871 4.19398863 -8.59953736]]

原始数据从8维降到了3维,同时这3维数据占了原始数据95%以上的信息。

数值规约

 数值规约指通过替代的、较小的数据来减少数据量,包括有参数方法和无参数方法两类。有参数方法是使用一个模型来评估数据,只需存放参数,而不需要存放实际数据,例如回归(线性回归和多元回归)和对数线性模型(近似离散属性集中的多维概率分布)。无参数方法就需要存放实际数据,例如直方图、聚类、抽样(采样)。

小结

 本章主要介绍了数据预处理的4个主要任务:数据清洗、数据集成、数据变换和数据规约。数据清洗主要介绍了对缺失值和异常值的处理,延续了第三章的缺失值和异常值分析的内容,本章主要介绍的处理缺失值的方法分为3类:删除记录、数据插补和不处理,处理异常值的方法有删除含有异常值的记录、不处理、平均值修正和视为缺失值;数据集成是合并多个数据源中的数据,并存放到一个数据存储的过程,对该部分的介绍从实体识别问题和冗余属性两个方面进行;数据变换介绍了如何从不同角度对已有属性进行函数变换;数据规约从属性(纵向)规约和数值(横向)规约两个方面介绍了如何对数据进行规约,使挖掘的性能和效率得到了很大的提高。通过对原始数据的处理,将为后续挖掘建模提供良好的数据基础。

发布了9 篇原创文章 · 获赞 67 · 访问量 5679
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章