数据挖掘实战—餐饮行业的数据挖掘之数据预处理



引言

  数据挖掘过程中,海量的数据中存在缺失、异常、不一致的数据,数据的质量决定模型的质量,所以进行数据清洗非常重要。数据预处理包括数据清洗、数据集成、数据变换和数据归约

一、数据清洗

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

1.缺失值处理

  处理缺失值的方法可分为3类:删除记录、数据插补和不处理。其中常用的数据插补方法有
在这里插入图片描述

删除记录: 如果简单删除小部分记录就可以达到既定目标,那么这种方法是最有效的,但容易造成资源的浪费,丢失掉大量隐藏在这些记录中的信息,尤其是数据很少的情况下
不处理: XGBoost模型可以直接对缺失值进行处理
数据插补: 重点介绍拉格朗日插值法和牛顿差值法,在进行插值前需要对数据的异常值进行检测,根据业务逻辑将全部异常值或者部分异常值定义为空缺值,然后进行插补

1.1 拉格朗日插值法

  拉格朗日插值法当插值节点增减时,插值多项式会发生变化。牛顿差值法改进了它的缺点。以销量数据为例,运用拉格朗日插值法补充缺失值

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.interpolate import lagrange

cat_sale = pd.read_excel('data/catering_sale.xls')
cat_sale.drop('日期', axis=1, inplace=True)

# 过滤异常值,并置为空值
cat_sale['销量'][(cat_sale['销量'] < 400) | (cat_sale['销量'] > 5000)] = np.NAN


# 自定义列向量插值函数
def ployinterp_columns(s, n, k=4):
    if n < k:
        y = s[list(range(0, n)) + list(range(n + 1, n + k + 1))]
    elif n > len(s) - k - 1:
        y = s[list(range(n - k, n)) + list(range(n + 1, len(s)))]
    else:
        y = s[list(range(n - k, n)) + list(range(n + 1, n + k + 1))]  # 取空值处的前后3个数
    y = y[y.notnull()]  # 剔除空值
    return lagrange(y.index, list(y))(n)  # 插值并返回插值结果


# 逐个判断元素是否需要插值
for i in cat_sale.columns:
    for j in range(len(cat_sale)):
        if (cat_sale[i].isnull())[j]:  # 如果为空则插值
            print(ployinterp_columns(cat_sale[i], j))
            cat_sale[i][j] = ployinterp_columns(cat_sale[i], j)

cat_sale.to_csv('sales.csv')  # 输出结果,写入文件

在这里插入图片描述

1.2牛顿差值法

  牛顿插值法与拉格朗日插值法相比,具有承袭性和易于变动节点的特点

import numpy as np
import pandas as pd


cat_sale = pd.read_excel('data/catering_sale.xls')
cat_sale.drop('日期', axis=1, inplace=True)

# 过滤异常值,并置为空值
cat_sale['销量'][(cat_sale['销量'] < 400) | (cat_sale['销量'] > 5000)] = np.NAN


# 分别定义求插商与求w的函数
def cal_f(x, y):
    """
    计算插商
    """
    f0 = np.zeros((len(x), len(y)))  # 定义一个存储插商的数组
    for k in range(len(y) + 1):  # 遍历列
        for i in range(k, len(x)):  # 遍历行
            if k == 0:
                f0[i, k] = y[i]
            else:
                f0[i, k] = (f0[i, k - 1] - f0[i - 1, k - 1]) / (x[i] - x[i - 1])
    print('差商表', '\n', f0)
    return f0


def newton(x, y, x_j):
    """
    牛顿差值多项式
    """
    f0 = cal_f(x, y)  # 计算插商
    f0 = f0.diagonal()
    # 与w相乘
    f1 = 0
    for i in range(len(f0)):
        s = 1
        k = 0
        while k < i:
            s = s * (x_j - x[k])
            k += 1
        f1 = f1 + f0[i] * s
    return f1


# 自定义列向量插值函数
def ployinterp_columns(s, n, x_j, k=2):
    if n < k:
        y = s[list(range(0, n)) + list(range(n + 1, n + k + 1))]
    elif n > len(s) - k - 1:
        y = s[list(range(n - k, n)) + list(range(n + 1, len(s)))]
    else:
        y = s[list(range(n - k, n)) + list(range(n + 1, n + k + 1))]  # 取空值处的前后5个数
    y = y[y.notnull()]  # 剔除空值
    return newton(y.index, list(y), x_j)  # 插值并返回插值结果


for i in cat_sale.columns:
    for j in range(len(cat_sale)):
        if (cat_sale[i].isnull())[j]:
            x_j = cat_sale.index[j]
            print(ployinterp_columns(cat_sale[i], j, x_j))
            cat_sale[i][j] = ployinterp_columns(cat_sale[i], j, x_j)

cat_sale.to_excel('saless.xls')

在这里插入图片描述

2.异常值的处理

  数据预处理中,异常值是否剔除需要视情况而定,因为有些异常值可能蕴含着有用的信息。
在这里插入图片描述
  很多情况下,要先分析异常值出现的可能原因,在判断异常值是否应该舍弃。如果是正确的数据,可以直接在具有异常值的数据集上进行挖掘建模。

扫描二维码关注公众号,回复: 13146400 查看本文章

二、数据集成

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

1.实体识别

在这里插入图片描述

2.冗余属性识别

在这里插入图片描述

3.数据变换

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

3.1 简单函数变换

  简单函数变换是对原始数据进行某些数学函数变换,如:平方、开方、取对数、差分运算。简单的函数变换常用于将不具有正态分布的数据变换成具有正态分布的数据;在时间序列分析中,有时,简单的对数变换或者差分运算就可以将非平稳序列变换为平稳序列。在数据挖掘中,如个人年收入是10万到10亿元,这是一个很大的区间,可以使用对数变换来对区间进行压缩
在这里插入图片描述

3.2 规范化

  不同评价指标往往具有不同的量纲,数值间的差别很大,不进行处理可能会影响数据分析的结果。为了消除指标之间量纲和取值范围的影响,需要进行标准化处理。将数据按照比例进行缩放,使之落入一个特定区域。数据规范化对基于距离的挖掘算法尤为重要。

3.2.1 最小-最大规范化

在这里插入图片描述

3.2.2 零-均值规范化(标准化)

在这里插入图片描述
在这里插入图片描述

3.2.3 小数定标规范化

在这里插入图片描述

3.3 连续属性离散化

  一些数据挖掘算法,特别是某些分类算法,如ID3算法,要求数据是分类属性形式。这样就需要将连续属性变换为分类属性
  连续属性离散化指的是在数据取值范围内设定若干个离散的划分点,将取值范围划分为一些离散化的区间,最后用不同的符号或整数值代表落在每个子区间中的数据值。离散化涉及两个任务:

  1. 确定分类数
  2. 如何将连续属性值映射到这些分类值
3.3.1 离散化方法

  常用的离散化方法有等宽法、等频法和(一维)聚类
等宽法

含义:将属性的值域分成具有相同宽度的区间,区间的个数由数据本身的特点决定或者用户指定
缺点:等宽法由于对离群点比较敏感,倾向于不均匀的把属性值分布在各个区间。有些区间包含很多数据,而另外一些区间的数据极少,这样会严重损坏建立的决策模型。
pandas中的cut函数实现了等距分箱

等频法

含义:将相同数量的记录放进每个区间里
缺点:虽然避免了数据不均匀,但是却有可能将相同的数据值分在不同的区间内,以满足每个区间中有相同的数据个数。

基于聚类分析的方法

含义:首先将连续属性的值用聚类算法(如K-means算法)进行聚类,然后将聚类得到的簇进行处理,合并到一个簇的连续属性值做同一标记。簇的个数可以用户指定,或者是使用轮廓系数silhouette_score来寻找最佳的簇的个数。

#!usr/bin/env python
# -*- coding:utf-8 -*-
"""
@author: admin
@file: 连续属性离散化.py
@time: 2021/03/30
@desc:
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

data = pd.read_excel('data/discretization_data.xls')
# data = data['肝气郁结证型系数'].copy()
k = 4  # 4分箱
"""
1.等宽离散化
"""
d1 = pd.cut(data['肝气郁结证型系数'], k, labels=range(k))
# data['等宽'] = d1

"""
2.等频离散化
"""
d2 = pd.qcut(data['肝气郁结证型系数'], k, labels=range(k))
# data['等频'] = d2

"""
3.聚类法
"""
kmodel = KMeans(n_clusters=k)
kmodel.fit(np.array(data['肝气郁结证型系数']).reshape(len(data), 1))
# 聚类中心并排序
c = pd.DataFrame(kmodel.cluster_centers_).sort_values(by=0)
# 相邻聚类中心两项求中点,作为边界点
w = c.rolling(2).mean()
# 取出NaN
w = w.dropna()
# 添加首尾边界点
w = [0] + list(w[0]) + [data.max()]
# 分箱
d3 = pd.cut(data['肝气郁结证型系数'], k, labels=range(k))
# data['聚类'] = d3

"""
自定义作图函数显示连续离散化(分箱)结果
"""
def bin_plot(d, k):
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False

    plt.figure(figsize=(8, 3))
    colors = ['ko', 'ro', 'yo', 'bo']
    for i in range(k):
        plt.plot(np.array(data[d == i]).flatten(), [i for j in d[d == i]], colors[i])
    plt.ylim(-0.5, k-0.5)
    return plt


bin_plot(d1, k).show()
bin_plot(d2, k).show()
bin_plot(d3, k).show()

等距
在这里插入图片描述
等频
在这里插入图片描述
聚类
在这里插入图片描述

4.属性构造

  在数据挖掘中,为了帮助用户提取更有用的信息,挖掘更深层次的模式,提高挖掘结果的精度,需要利用已有的属性集构造出新的属性,并加入到现有的属性集合中
在这里插入图片描述
在这里插入图片描述

5.小波变换

  小波变换具有多分辨率的特点,在时域频域都具有表征信号局部特征的能力,通过伸缩和平移等运算过程对信号进行多尺度聚焦分析,提供一种非平稳信号时频分析手段,可以由粗及细地逐步观察信号,从中提取有用信息。
  能够刻画某个问题的特征量往往隐含在一个信号中的某个或者某些分量中,小波变换可以将非平稳信号分解为不同层次、不同频带信息的数据序列,即小波系数,选择适当的小波系数,即完成了信号的特征提取分析。

5.1 基于小波变换的特征提取方法

在这里插入图片描述
在这里插入图片描述

5.2 基于小波变换的多尺度空间能量分布特征提取方法

在这里插入图片描述
  使用PyWavelets库进行小波变换,提取特征
在这里插入图片描述

三、数据归约

  数据归约产生更小且保持原始数据完整性的新数据集,提高效率。

  • 可以降低无效、错误数据对建模的影响
  • 少量且具有代表性的数据将大幅度缩短数据挖掘的时间
  • 降低存储数据的成本

1.属性归约

  属性归约的目标是寻找最小的属性子集并确保新数据子集的概率分布尽可能接近原来数据集的概率分布。属性归约的常用方法如下:
在这里插入图片描述
在这里插入图片描述

1.1 前向挑选、后向挑选、双向挑选

我之前实现过,可以查看链接数据预处理—3.变量选择之逐步挑选—向前挑选、向后挑选、双向挑选python实现

1.2 主成分分析

数据

from sklearn.decomposition import PCA
import pandas as pd

data = pd.read_excel('data/principal_component.xls',header=None)
pca = PCA()
pca.fit(data)
print(pca.components_)    # 返回各模型的特征向量
print(pca.explained_variance_ratio_.cumsum())  # 返回各个成分各自的方差占比

# 发现选取前3个累计贡献率就达到了97%
pca1 = PCA(n_components=3,copy=True,whiten=False)
pca1.fit(data)
low_data = pca1.transform(data)    # 降维后的数据
pd.DataFrame(low_data).to_excel('low_data.xls')

pca1.inverse_transform(low_data)    # 可以使用inverse_transform函数复原数据

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

2.数值归约

  数值归约通过选择替代的、较小的数据来减小数据量,包括有参数方法和无参数方法。有参数方法是使用一个模型来评估数据,只需存放参数,而不需要存放实际数据。无参数方法是需要存放实际数据的,例如直方图、聚类、抽样。

2.1 直方图

  直方图使用分箱来近似数据分布。属性A的直方图将A的数据分布划分为不相交的子集或桶。如果某个桶只代表单个属性值/频率对,则成为单桶。

2.2 聚类

在这里插入图片描述

2.3 抽样

在这里插入图片描述

2.4 参数回归

  简单线性模型和对数线性模型可以用来近似给定数据。用简单线性模型对数据建模,使之拟合一条直线。对数线性模型用来描述期望频数与协变量之间的关系
在这里插入图片描述


如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论留言!
在这里插入图片描述


猜你喜欢

转载自blog.csdn.net/weixin_46649052/article/details/115324398
今日推荐