数据挖掘实战—餐饮行业的数据挖掘之挖掘建模



引言

  经过数据探索与数据预处理,我们得到了可以直接建模的数据,根据挖掘目标与数据形式我们可以建立分类与预测、聚类分析、关联规则、时序模式、离群点检测等模型,帮助企业提取数据中蕴含的商业价值。

一、分类与预测

  对于餐饮行业,常遇到如下问题:
在这里插入图片描述

1.常用的分类与预测算法

在这里插入图片描述

2. 回归分析

  在数据挖掘环境下。自变量与因变量具有相关关系,自变量是已知的,因变量是要预测的。常见的回归模型如下:
在这里插入图片描述
当自变量之间出现多重共线性时,用最小二乘法估计回归系数将不准确,消除多重共线性的参数改进方法主要有岭回归和主成分回归

3.决策树

  决策树是一种树状结构,它的每一个叶结点对应着一个分类,非叶结点对应着在某个属性上的划分。根据样本在该属性上的不同取值将划分成若干子集。对于非纯叶节点,多数类的标号给出到达这个节点的样本所属的类。构造决策树的核心问题是在每一步如何选择适当的属性对样本进行拆分。
在这里插入图片描述

#!usr/bin/env python
# -*- coding:utf-8 -*-
"""
@author: admin
@file: ID3决策树.py
@time: 2021/03/31
@desc:
"""
import pandas as pd
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn.preprocessing import LabelEncoder
import graphviz
import matplotlib as mpl

data = pd.read_excel('data/sales_data.xls', index_col='序号')

data[data == '好'] = 1
data[data == '高'] = 1
data[data == '是'] = 1
data[data != 1] = -1
x = data.iloc[:, :3].values.astype(int)
y = data.iloc[:, 3].values.astype(int)
dtc = DecisionTreeClassifier(criterion='entropy')
dtc.fit(x, y)

dot_data = export_graphviz(dtc, out_file='tree.dot',
                           feature_names=['天气', '是否周末', '是否有促销'],
                           class_names=['高', '低'], filled=True,
                           rounded=True, special_characters=True)

with open('tree.dot', encoding='utf-8') as f:
    dot_grapth = f.read()
dot = graphviz.Source(dot_grapth.replace("helvetica", "MicrosoftYaHei"))   # 解决中文乱码replace("helvetica", "MicrosoftYaHei")
dot.view()

在这里插入图片描述

4.人工神经网络

  使用人工神经网络模型需要确定网络连接的拓扑结构、神经元的特征和学习规则。常用来实现分类与预测的人工神经网络算法有:
在这里插入图片描述

import pandas as pd
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Model, optimizers, losses, metrics, activations
from tensorflow.keras.layers import Dense, Dropout, Input, Lambda
import matplotlib as mpl

data = pd.read_excel('data/sales_data.xls', index_col='序号')

data[data == '好'] = 1
data[data == '高'] = 1
data[data == '是'] = 1
data[data != 1] = 0
x = data.iloc[:, :3].values.astype(int)
y = data.iloc[:, 3].values.astype(int)


def bpModel():
    input = Input(shape=(3,))
    x = Dense(10, activation=tf.nn.relu)(input)
    x = Dense(10, activation=tf.nn.relu)(x)
    output = Dense(1, activation='sigmoid')(x)

    model = Model(inputs=input, outputs=output)
    model.compile(optimizer=optimizers.Adam(learning_rate=0.01),
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    return model


def cm_plot(y, yp):
    """
    混淆矩阵可视化
    :param y:
    :param yp:
    :return:
    """
    from sklearn.metrics import confusion_matrix

    cm = confusion_matrix(y, yp)
    print(cm)
    import matplotlib.pyplot as plt
    plt.matshow(cm, cmap=plt.cm.Greens)
    plt.colorbar()

    for x in range(len(cm)):
        for y in range(len(cm)):
            plt.annotate(cm[x, y], xy=(x, y), horizontalalignment='center', verticalalignment='center')

    plt.ylabel('True label')
    plt.xlabel('Predicted label')
    return plt


bp = bpModel()
bp.fit(x, y, epochs=1000, batch_size=10)
y_pred = bp.predict(x)
y_pred[y_pred >= 0.5] = 1
y_pred[y_pred < 0.5] = 0

# 可视化
cm_plot(y, y_pred).show()

在这里插入图片描述

二、聚类分析

  在当前市场环境下,消费者需求显现出日益差异化和个性化的趋势。针对餐饮行业,常碰到以下问题:
在这里插入图片描述
这些问题都可以通过聚类分析来实现。

1.常用的聚类分析算法

  聚类方法是一种无监督的学习方法。在一组未被标记的样本上,聚类根据数据自身的距离或相似度将它们划分为若干组。划分的原则是组内样本最小化而组间样本距离最大化。
常用聚类方法:
在这里插入图片描述
常用聚类分析方法:
在这里插入图片描述

2.K-Means聚类算法

  K-Means聚类算法是典型的基于距离非层次聚类算法,在最小化误差函数的基础上将数据划分为预定的类数 K K K,采用距离作为相似性的评价指标,即认为两个对象距离越近,其相似度越大。

2.1 算法过程

在这里插入图片描述
  聚类的结果依赖于初始聚类中心的随机选择,有可能使得结果严重偏离全局最优分类。实际中,多次运行K-Means算法,选择误差平方和最小的聚类结果。

2.2 数据类型与相似性的度量

  对于连续属性,要先对各属性值进行标准化,再进行距离计算。
在这里插入图片描述
  对于文档数据,可使用余弦相似性。可先将文档数据转换成文档—词矩阵
在这里插入图片描述

3. 目标函数

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

4.消费行为特征分析

  以部分餐饮客户消费行为特征数据为例,聚类分析得

import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

# 加载数据
data = pd.read_excel('data/consumption_data.xls', index_col='Id')
# 连续属性标准化
ss = StandardScaler()
x = ss.fit_transform(data)

k = 3  # 聚类中心数
n_iterations = 500  # 聚类的最大循环次数
kmeans = KMeans(n_clusters=k, max_iter=n_iterations, n_jobs=-1, random_state=1234)
kmeans.fit(data)  # 训练

# 统计各类别的数目
r1 = pd.Series(kmeans.labels_).value_counts()
# 找出聚类中心
r2 = pd.DataFrame(kmeans.cluster_centers_)
# 拼接,得到各聚类中心下类别的数目
r = pd.concat([r2, r1], axis=1)
# 重命名表头
r.columns = list(data.columns) + ['类别数目']

# 将聚类类别保存到数据中
data = pd.concat([data, pd.Series(kmeans.labels_, index=data.index)], axis=1)
data.to_excel('data/data_type.xls')

在这里插入图片描述
  绘制聚类后的概率密度图

import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt

# 加载数据
data = pd.read_excel('data/consumption_data.xls', index_col='Id')
# 连续属性标准化
ss = StandardScaler()
x = ss.fit_transform(data)

k = 3  # 聚类中心数
n_iterations = 500  # 聚类的最大循环次数
kmeans = KMeans(n_clusters=k, max_iter=n_iterations, n_jobs=-1, random_state=1234)
kmeans.fit(data)  # 训练

# 统计各类别的数目
r1 = pd.Series(kmeans.labels_).value_counts()
# 找出聚类中心
r2 = pd.DataFrame(kmeans.cluster_centers_)
# 拼接,得到各聚类中心下类别的数目
r = pd.concat([r2, r1], axis=1)
# 重命名表头
r.columns = list(data.columns) + ['类别数目']
print(r)
# 将聚类类别保存到数据中
rs = pd.concat([data, pd.Series(kmeans.labels_, index=data.index)], axis=1)
rs.columns = list(data.columns) + ['聚类类别']
rs.to_excel('data/data_type.xls')

# 解决中文字体问题
plt.rcParams['font.sans-serif'] = [u'simHei']
plt.rcParams['axes.unicode_minus'] = False


def density_plot(data1):
    p = data1.plot(kind='kde', linewidth=2, subplots=True, sharex=False)
    [p[i].set_ylabel(u'密度') for i in range(3)]
    plt.legend()
    return plt


# 概率密度图文件名前缀
pic_output = './data/pd'
for i in range(k):
    density_plot(data[rs[u'聚类类别'] == i]).show()
    # density_plot(data[rs[u'聚类类别'] == i]).savefig(u'%s%s.png' %(pic_output, i))

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

5.python中主要的聚类分析算法

  scikit-learn库中实现的聚类主要有:K-Means聚类、层次聚类、FCM以及神经网络聚类。主要相关函数如下表:
在这里插入图片描述

三、关联规则

  关联规则分析是数据挖掘中最活跃的研究方法之一,目的是在一个数据集中找到各项之间的关联关系,而这种关系并没有在数据中直接体现出来。在餐饮行业中,菜品的推荐就用到了关联规则,比如某些菜品是相互关联的,有些菜品之间是竞争关系,在顾客下单时推荐相关联的产品就可以引导顾客消费。

1.常用的关联规则算法

在这里插入图片描述

2.Apriori算法

  Apriori算法的主要思想是找出存在于事务数据集中最大的频繁项集,再利用得到的最大频繁项集与预先设定的最小置信度阈值生成强关联规则。

2.1.Apriori的性质

  频繁项集的所有非空子集一定是频繁项集。根据这一性质可以得出:向不是频繁项集 I I I的项集中添加事务 A A A,新的项集 I ∪ A I∪A IA一定不是频繁项集。

2.2.Apriori算法实现过程

第一步:
找出所有频繁项集(支持度必须大于等于给定的最小支持度阈值),在这个过程中连接步与剪枝步相互融合,最终得到最大频繁项集 L k L_k Lk

  • 连接步
    连接步的目的是找到 K K K项集。对于给定的最小支持度阈值,分别对1项候选集 C 1 C_1 C1,剔除小于该阈值的项集得到1项频繁集 L 1 L_1 L1;下一步由 L 1 L_1 L1自身连接产生2项候选集 C 2 C_2 C2,剔除小于该阈值的项集得到2项频繁集 L 2 L_2 L2;再下一步由 L 2 和 L 1 L_2和L_1 L2L1连接产生3项候选集 C 3 C_3 C3,剔除小于该阈值的项集得到3项频繁集 L 3 L_3 L3,这样循环下去,直至由 L k − 1 和 L 1 L_{k-1}和L_1 Lk1L1连接产生 k k k项候选集 C k C_k Ck,剔除小于该阈值的项集得到最大频繁集 L k L_k Lk
  • 剪枝步
    剪枝步紧接着连接步,在产生候选项 C k C_k Ck的过程中起到了减小搜索空间的目的。根据Apriori的性质:频繁项集的所有非空子集也必须是频繁项集,所以不满足该性质的项集将不会存在于 C k C_k Ck中,该过程就是剪枝

第二步:
由频繁项集产生强关联规则。由第一步可知,未超过预定的最小支持阈值的项集已被剔除,如果剩下的这些项集又满足了预定的最小置信度阈值,那么就挖掘出了强关联规则。

2.3.Apriori算法实现过程实例

  以餐饮行业点餐数据为例,首先先将事务数据整理成关联规则模型所需的数据结构。设最小支持度为0.2,将菜品id编号
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.Apriori算法—python实现

数据集链接

import numpy as np
import pandas as pd


def connect_string(x, ms):
    """
    与1项频繁集连接生成新的项集
    :param x: 项集
    :param ms:
    :return: 新的项集
    """
    x = list(map(lambda i: sorted(i.split(ms)), x))
    l = len(x[0])
    r = []
    for i in range(len(x)):
        for j in range(i, len(x)):
            if x[i][:l - 1] == x[j][:l - 1] and x[i][l - 1] != x[j][l - 1]:
                r.append(x[i][:l - 1] + sorted([x[j][l - 1], x[i][l - 1]]))
    return r


def find_rule(d, support, confidence, ms=u'-'):
    """
    寻找关联规则
    :param d: 数据集
    :param support: 最小支持度
    :param confidence: 最小置信度
    :param ms: 项集之间连接符号
    :return: 强关联规则以及其支持度与置信度
    """
    # 存储输出结果
    result = pd.DataFrame(index=['support', 'confidence'])

    # 1项集的支持度序列
    support_series = 1.0 * d.sum(axis=0) / d.shape[0]
    # 基于给定的最小支持度进行筛选,得到1项频繁集
    column = list(support_series[support_series > support].index)

    # 当1项频繁集个数大于1时
    k = 0
    while len(column) > 1:
        k = k + 1
        print(u'\n正在进行第%s次搜索...' % k)
        column = connect_string(column, ms)
        print(u'数目:%s...' % len(column))
        # 乘积为1表示两个项集同时发生,乘积为0表示不同发生
        sf = lambda i: d[i].prod(axis=1, numeric_only=True)  # 新一批支持度的计算函数

        # 创建连接数据,这一步耗时、耗内存最严重。当数据集较大时,可以考虑并行运算优化。
        d_2 = pd.DataFrame(list(map(sf, column)), index=[ms.join(i) for i in column]).T

        # 计算连接后的支持度
        support_series_2 = 1.0 * d_2[[ms.join(i) for i in column]].sum() / len(d)
        column = list(support_series_2[support_series_2 > support].index)  # 新一轮支持度筛选
        support_series = support_series.append(support_series_2)

        column2 = []
        # 遍历可能的推理,如{A,B,C}究竟是A+B-->C还是B+C-->A还是C+A-->B?
        for i in column:
            i = i.split(ms)
            for j in range(len(i)):
                column2.append(i[:j] + i[j + 1:] + i[j:j + 1])

        # 定义置信度序列
        cofidence_series = pd.Series(index=[ms.join(i) for i in column2])
        # 计算置信度序列
        for i in column2:
            cofidence_series[ms.join(i)] = support_series[ms.join(sorted(i))] / support_series[ms.join(i[:len(i) - 1])]

        for i in cofidence_series[cofidence_series > confidence].index:  # 置信度筛选
            result[i] = 0.0
            result[i]['confidence'] = cofidence_series[i]
            result[i]['support'] = support_series[ms.join(sorted(i.split(ms)))]

    result = result.T.sort_values(['confidence', 'support'], ascending=False)  # 结果整理,输出
    print(u'\n结果为:')
    print(result)
    return result


if __name__ == '__main__':
    # 加载数据
    data = pd.read_excel('../data/menu_orders.xls', header=None)
    print('转换原数据到0-1矩阵')
    ct = lambda x: pd.Series(1, index=x[pd.notnull(x)])
    b = map(ct, data.values)
    data = pd.DataFrame(list(b)).fillna(0)
    # 删除中间变脸b
    del b

    support = 0.2  # 最小支持度
    confidence = 0.5  # 最小置信度

    find_rule(data, support, confidence)
转换原数据到0-1矩阵

正在进行第1次搜索...
数目:6...

正在进行第2次搜索...
数目:3...

正在进行第3次搜索...
数目:0...

结果为:
       support  confidence
e-a        0.3    1.000000
e-c        0.3    1.000000
c-e-a      0.3    1.000000
a-e-c      0.3    1.000000
c-a        0.5    0.714286
a-c        0.5    0.714286
a-b        0.5    0.714286
c-b        0.5    0.714286
b-a        0.5    0.625000
b-c        0.5    0.625000
a-c-e      0.3    0.600000
b-c-a      0.3    0.600000
a-c-b      0.3    0.600000
a-b-c      0.3    0.600000

其中,'e—a’表示e发生能够推出a发生,置信度为100%,支持度30%。搜索出的关联规则并不一定有实际意义,需要根据问题背景筛选适当的有意义的规则,并赋予合理的解释。

四、时间序列模式

见这个博客

五、离群点检测

  离群点检测是数据挖掘中重要的一部分,它的任务是发现与大部分其他对象显著不同的对象。大部分数据挖掘方法都将这种差异信息视为噪声而丢弃。同时,一些噪声数据中,罕见的数据可能蕴含着更大的研究价值。

1.离群点的成因及分类

  离群点的主要成因是:数据来源于不同的类、自然变异、数据测量和收集误差
在这里插入图片描述

2.离群点检测方法

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

3.基于聚类的离群点检测方法

  聚类分析用于发现局部强相关的对象组,而异常检测用于发现不与其他对象强相关的对象。因此聚类分析也可以用于离群点检测。下面介绍两种基于聚类的离群点检测方法。

3.1 丢弃远离其他簇的小簇

在这里插入图片描述

3.2 基于原型的聚类

在这里插入图片描述
下面使用第二种

import numpy as np
import pandas as pd

# 参数初始化
inputfile = '../data/consumption_data.xls'  # 销量及其他属性数据
k = 3  # 聚类的类别
threshold = 2  # 离散点阈值
iteration = 500  # 聚类最大循环次数
data = pd.read_excel(inputfile, index_col = 'Id')  # 读取数据
data_zs = 1.0*(data - data.mean())/data.std()  # 数据标准化

from sklearn.cluster import KMeans
model = KMeans(n_clusters = k, n_jobs = 4, max_iter = iteration)  # 分为k类,并发数4
model.fit(data_zs)  # 开始聚类

# 标准化数据及其类别
r = pd.concat([data_zs, pd.Series(model.labels_, index = data.index)], axis = 1)   # 每个样本对应的类别
r.columns = list(data.columns) + ['聚类类别']  # 重命名表头

norm = []
for i in range(k):  # 逐一处理
  norm_tmp = r[['R', 'F', 'M']][r['聚类类别'] == i]-model.cluster_centers_[i]
  norm_tmp = norm_tmp.apply(np.linalg.norm, axis = 1)  # 求出绝对距离
  norm.append(norm_tmp/norm_tmp.median())  # 求相对距离并添加

norm = pd.concat(norm)  # 合并

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
norm[norm <= threshold].plot(style = 'go')  # 正常点

discrete_points = norm[norm > threshold]  # 离群点
discrete_points.plot(style = 'ro')

for i in range(len(discrete_points)):  # 离群点做标记
  id = discrete_points.index[i]
  n = discrete_points.iloc[i]
  plt.annotate('(%s, %0.2f)'%(id, n), xy = (id, n), xytext = (id, n))

plt.xlabel('编号')
plt.ylabel('相对距离')
plt.show()

参考:

  • 《python分析与数据挖掘实战》

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


猜你喜欢

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