PySpark关联规则及聚类模型简明教程

一、PySpark关联规则模型

  关联规则分析为的就是发现商品与商品之间的关联。通过计算商品之间的支持度、置信度与提升度,分析哪些商品有正向关系,顾客愿意同时购买它们。
  此处使用了pyspark自带的FPGrowth算法。它和APRIORI算法一样都是计算两两商品之间支持度置信度与提升度的算法,虽然算法流程不同,但是计算结果是一样的。

(1) Antecedent(前件)
  定义:在关联规则中,if部分称为前提(Antecedent),表示某些物品的组合。它是规则中用于推断或预测的条件部分。
  示例:在规则“购买牛奶 → 购买面包”中,“购买牛奶”是前件。
(2) Consequent(后件)
  定义:在关联规则中,then部分称为结果(Consequent),表示其他物品的组合。它是在前件满足时可能发生的结果。
  示例:在规则“购买牛奶 → 购买面包”中,“购买面包”是后件。
(3) Confidence(置信度)
  定义:置信度是关联规则的可信程度,表示在包含前件的事务中,同时也包含后件的事务所占的比例。
  示例:如果购买牛奶的顾客中有70%也购买了面包,则规则“购买牛奶 → 购买面包”的置信度为70%。
(4) Lift(提升度)
  定义:提升度表示在包含前件的事务中同时包含后件的比例,与仅包含后件的事务的比例之间的比值。它反映了前件对后件出现的提升作用。
  示例:如果购买牛奶的顾客中购买面包的比例是70%,而所有顾客中购买面包的比例是50%,则规则“购买牛奶 → 购买面包”的提升度为1.4(70% / 50%)。
(5) Support(支持度)
  定义:支持度是项集在数据集中出现的频率或概率,表示同时包含前件和后件的事务占所有事务的比例。
  示例:如果100个购物交易中,有30个交易同时包含了牛奶和面包,则规则“购买牛奶 → 购买面包”的支持度为30%。

二、关联规则模型应用

1. 数据集介绍

  数据集:简单关联规则分析.txt,为5张购物小票,每张购物小票上面是购买的商品名称,如下图所示。
在这里插入图片描述
  数据集的样本数很少,这里仅为演示PySpark关联规则的简单教程,方便读者理解。

2.数据导入及预处理

  配置Pyspark应用程序,导入数据集:简单关联规则分析.txt。
在这里插入图片描述

  PySpark关联规则模型仅需要一列数据,并且需将每行数据以逗号分隔,放在列表里。处理 后的数据集如下:
在这里插入图片描述
  代码如下:

from pyspark import SparkConf
from pyspark.ml.feature import StringIndexer
from pyspark.sql import SparkSession
from pyspark.sql.functions import *
from pyspark.ml.recommendation import ALS
from pyspark.ml.evaluation import RegressionEvaluator
from pyspark.ml.fpm import *

import matplotlib
# 设置一个支持GUI的后端,用于在IDEA绘图
matplotlib.use('TkAgg')  # 或者 'Qt5Agg', 'GTK3Agg' 等,用于在IDEA绘图
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 配置PySpark应用程序
conf = SparkConf().setAppName("简单关联规则分析").setMaster('spark://192.168.126.10:7077')
sc = SparkContext.getOrCreate(conf)
spark = SparkSession(sc)
# ------------1.加载数据--------------------
filename = "关联规则分析.txt"
data = spark.read.text('hdfs://192.168.126.10:9000/data/' + filename)
data.show()
#  --------2.数据处理---------
transactions = data.select(split('value', ',').alias('items'))  # 将每行数据按逗号分割,并将结果数组作为新的列items
transactions.show()

3.关联规则分析

  • 创建FPGrowth模型

  • 训练模型。设最小支持度minSupport=0.5, 最小置信度minConfidence=0.6

  • 获取频繁项集。频繁项集是指那些在数据集中频繁出现的项的集合。在购物篮分析中,一个频繁项集可能是一组经常被顾客一起购买的商品。频繁项集的识别是关联规则挖掘的第一步。通常使用支持度(Support)来量化一个项集的频繁程度,即数据集中包含该项集的交易数占总交易数的比例。
    在这里插入图片描述
    上图可知,“面包”在数据集中出现了4次,“面包”和“尿不湿”同时在数据集中出现3次。

  • 获取关联规则。关联规则是描述数据集中项之间关系的规则。它们通常以“如果…那么…”的形式出现,例如,“如果顾客购买了牛奶,那么他们也可能购买面包”。关联规则由两个主要部分组成:前项(Antecedent)和后项(Consequent),分别对应于“如果…”和“那么…”部分。
    在这里插入图片描述
      由上图可知,第一条关联规则为:啤酒–>尿不湿,置信度confidence=1.0,提升度lift=1.25,支持度support=0.6。这表明:

  • 置信度(Confidence) = 1.0:这意味着在所有包含“啤酒”的交易中,都同时也包含了“尿不湿”。换句话说,当顾客购买了啤酒时,他们100%的几率也会购买尿不湿。这是一个非常高的置信度,表明啤酒和尿不湿之间的购买行为几乎是同时发生的。

  • 提升度(Lift) = 1.25:提升度大于1表明“啤酒”和“尿不湿”之间存在正相关性,即它们不是独立出现的。具体来说,当“啤酒”出现时,“尿不湿”出现的频率是它在整个数据集中出现频率的1.25倍。这意味着,啤酒的购买增加了尿不湿被购买的可能性。

  • 支持度(Support) = 0.6:支持度表示同时包含“啤酒”和“尿不湿”的交易占所有交易的比例是60%。这是一个相对较高的支持度,表明这两种商品经常被一起购买。

  综合这些指标,我们可以得出以下结论:

  • 强关联性:由于置信度和提升度都很高,这条规则表明啤酒和尿不湿之间存在很强的关联性。商家可以利用这种关联性来优化商品布局、促销策略或推荐系统,以增加销售额。
  • 高购买频率:支持度较高表明这两种商品经常被顾客一起购买。这可能反映了某种生活习惯或购物模式,商家可以进一步分析这种模式的成因,以便更好地满足顾客需求。
  • 营销策略:基于这条规则,商家可以考虑将啤酒和尿不湿放在相邻的货架上,或者提供捆绑销售、满减优惠等促销活动,以吸引顾客购买这两种商品。

代码如下:

# ---------3.关联规则挖掘---------
fp = FPGrowth(minSupport=0.5, minConfidence=0.6, itemsCol='items')  # 创建FPGrowth模型
fpModel = fp.fit(transactions)  # 训练模型
fpModel.freqItemsets.show()  # 获取频繁项集
associations_rules = fpModel.associationRules.sort('lift', ascending=False)  # 获取 关联规则
associations_rules.show()

4. 关联规则数据处理,为可视化做准备

  只有提升度大于1,关联规则才有效,因此提取提升度大于1的关联规则,并转换为Pandas DataFrame。
在这里插入图片描述
  关联规则里面的前件antecedent和后件consequent的元素都是以集合形式存在,需通过遍历或用apply()函数将每个元素提取出来,组成:“啤酒–>尿不湿” 的字符串形式,用于绘制柱形图。
在这里插入图片描述

# ----4.关联规则处理,为可视化做准备-----
rules_pd = associations_rules.filter(col('lift') > 1).toPandas()
print(rules_pd)
ant_cons = []  # 前件antecedent-->后件consequent
confidence = []  # 置信度
lift = []  # 提升度
# 使用apply()函数对数据批量处理
def process_row(row):
    ant = row['antecedent']
    cons = row['consequent']
    conf = row['confidence']
    li = row['lift']
    ant_join = ','.join([item for item in ant])
    cons_join = ','.join([item for item in cons])
    a_c = ant_join + '→' + cons_join
    print(a_c + ",置信度:" + str(conf) + ",提升度:" + str(li))

    ant_cons.append(a_c)
    confidence.append(conf)
    lift.append(li)
rules_pd.apply(process_row, axis=1)  # 处理每一行
print(ant_cons)
print(confidence)
print(lift)

5.关联规则可视化

  将置信度和提升度绘制成柱形图。
在这里插入图片描述
  代码如下:

# -----5.关联规则可视化--------
size = len(ant_cons)
place = np.arange(size)  # 根据数据个数生成柱子的中点位置:0,1,2,3
plt.bar(place, confidence, width=0.4, label='置信度')  # 第1根柱子的中心位置为0,宽度0.4,第2根中心位置为1
plt.bar(place + 0.4, lift, width=0.4, label='提升度')  # 第2根柱子的中心位置为0+0.4,宽度为0.4
for i in place:
    plt.text(i, confidence[i] + 0.01, '%.2f' % confidence[i])  # 置信度 柱子的顶部数字
    plt.text(i + 0.4, lift[i] + 0.01, '%.2f' % lift[i])  # 提升度 柱子的顶部数字,数字保留2位小数,离顶部柱子距离0.01

plt.xticks(place+0.2, ant_cons)  # 替换x轴刻度标签
plt.legend()  # 显示图例
plt.show()

三、聚类模型应用:客户细分

1. PySpark聚类模型介绍

  在PySpark中,有LDA(Latent Dirichlet Allocation,潜在狄利克雷分配)、BisectingKMeans和KMeans三种不同的聚类或主题模型算法。

(1)LDA
  LDA:是一种文档主题生成模型,也是一种无监督学习算法。它主要用于发现文档集合中的潜在主题,并将每个文档表示为这些主题的混合体。LDA通过找到词、文档与主题三者之间的统计学关系进行推断,从而实现对文档的聚类或主题分析。
  应用场景:LDA特别适用于文本数据,如文章、书籍、网页等,可以帮助用户理解文档集合中的主题结构。
  LDA实现:在PySpark中,LDA模型通过pyspark.ml.clustering.LDA类实现。用户需要指定特征列(featuresCol)、迭代次数(maxIter)、随机种子(seed)、主题数(k)等参数来训练模型。训练完成后,可以使用模型的describeTopics方法来查看主题分布,或者使用logLikelihood和logPerplexity方法来评估模型性能。

(2)BisectingKMeans
  BisectingKMeans:是一种基于二分策略的K-means聚类算法,是一种层次型聚类算法。与传统的K-means算法不同,BisectingKMeans从包含所有点的单个簇开始,通过迭代地将簇一分为二,直到达到指定的簇数量或满足其他停止条件。
  应用场景:BisectingKMeans适用于需要快速收敛到指定簇数量的场景,特别是当数据集较大时,它可以比传统的K-means算法更快地找到解。
  BisectingKMeans实现:在PySpark中,BisectingKMeans通过pyspark.ml.clustering.BisectingKMeans类实现。用户需要指定特征列(featuresCol)、预测列(predictionCol)、最大迭代次数(maxIter)、随机种子(seed)、叶簇数(k)等参数来训练模型。训练完成后,可以使用模型的clusterCenters方法来查看聚类中心,或者使用computeCost方法来计算输入点与其对应的聚类中心之间的距离平方和。

(3)KMeans
  KMeans:是一种广泛使用的聚类算法,它将数据点划分到具有相似特征的K个簇中。KMeans通过迭代地更新簇中心和重新分配数据点到最近的簇中心来实现聚类。
  应用场景:KMeans适用于各种类型的数据集,特别是当数据集具有明显的簇结构时。它可以帮助用户发现数据中的潜在群组或模式。
  KMeans实现:在PySpark中,KMeans通过pyspark.ml.clustering.KMeans类实现。用户需要指定特征列(featuresCol)、聚类数(k)、随机种子(seed)、最大迭代次数(maxIter)等参数来训练模型。训练完成后,可以使用模型的transform方法来对新数据进行聚类预测,或者使用clusterCenters方法来查看聚类中心。

2.数据集介绍

聚类目标:将具有相似特征(如年龄、性别、年收入和消费习惯)的客户分组,了解不同客户群体的特征和需求,为后续的市场细分和个性化营销提供基础。数据集CustomersCluster.csv字段如下:
CustomerID : 每个客户的唯一ID。
Genre:用户的性别。
Age:用户当前的年龄。
Income: 用户的年收入 (千美元)。
Spending:(0-1),用户消费习惯(分数越高表示消费越多,反之亦然)。
数据集的部分数据如下:
在这里插入图片描述

3.初始化Spark环境

创建SparkSession对象,用于访问SparkContext和其他Spark功能。Spark集群主节点IP为192.168.126.10。代码如下:

from pyspark import SparkConf
from pyspark.ml.feature import StringIndexer, VectorAssembler, OneHotEncoder, MinMaxScaler
from pyspark.sql import SparkSession, Row
from pyspark.sql.functions import *
from pyspark.ml.classification import *
from pyspark.ml.evaluation import *
from pyspark.ml import Pipeline, tuning
from pyspark.ml.linalg import Vectors
from pyspark.ml.regression import *
from pyspark.ml.clustering import *
import pandas as pd
import matplotlib.pyplot as plt
from pyspark.ml.stat import Correlation

import matplotlib
# 设置一个支持GUI的后端,用于在IDEA绘图
matplotlib.use('TkAgg')  # 或者 'Qt5Agg', 'GTK3Agg' 等,用于在IDEA绘图
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体为SimHei显示中文
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像时负号'-'显示为方块的问题

conf = SparkConf().setAppName("聚类_客户").setMaster('spark://192.168.126.10:7077')
sc = SparkContext.getOrCreate(conf)
spark = SparkSession(sc)

4. 数据准备

  数据集CustomersCluster.csv存放在HDFS系统的/data/目录下,Spark从HDFS系统中读取数据,代码如下。

# -----------------1.数据获取-------------------
filename = "CustomersCluster.csv"
customers = spark.read.csv('hdfs://192.168.126.10:9000/data/' + filename, header=True,
                           inferSchema=True)  # 训练集包含标题行,inferSchema=True自动推断数据类型
customers.show(5)
customers.describe().show()  # 查看数据集的基本数据信息
customers.printSchema()  # 输出数据集的结构
print(f"训练数据集总的记录数:{customers.count()}, 总列数:{len(customers.columns)}")

程序运行结果如下:
在这里插入图片描述

5. 数据探索

  PySpark主要设计用于大数据的分布式处理,而不是数据可视化。然而,可以通过将PySpark DataFrame中的数据转换为Pandas DataFrame(如果数据量不是极端庞大), 然后使用Matplotlib或Seaborn等库来绘制图形。对于大数据集,将整个数据集转换为Pandas DataFrame可能会导致内存不足的问题。因此,请确保数据集大小适合在单个节点的内存中处理。
   首先分组统计男女的人数,并绘制柱形图。然后再将PySpark DataFrame转换为Pandas DataFrame,分别绘制收入、年龄、消费的分布图,以及收入-消费的散点图。代码如下:

gender_counts = customers.groupBy('Gender').agg(count('*').alias('人数')).toPandas()
print(gender_counts)
gender_counts.plot(x='Gender', y='人数', kind='bar')
plt.xticks(rotation=45)
plt.show()

customers_df = customers.toPandas()  # 将数据转换为Pandas DataFrame(这里仅为示例,对于大数据集不推荐)
print(customers_df)
customers_df['Income'].plot(kind='kde')  # 收入的核密度图
plt.title("收入分布图")
plt.show()

customers_df['Age'].hist(bins=10, alpha=0.7, color='skyblue')  # bins参数控制直方图的柱数
plt.title("年龄分布图")
plt.show()

customers_df['Spending'].plot(kind='kde')
plt.title("消费分布图")
plt.show()

customers_df.plot(x='Income', y='Spending', kind='scatter')
plt.title("收入-消费 散点图")
plt.xlabel("收入")
plt.ylabel("消费")
plt.show()

income_spending_corr = customers.corr('Income', 'Spending')
print('Income和Spending的相关系数为:', income_spending_corr)

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

6.特征工程

6.1 数值化字符串类型 数据

  gender字段是字符串类型,需数值化。

#  将字符串型数据列 数值化
labelIndex = StringIndexer(inputCol='Gender', outputCol='indexed_Gender')
model = labelIndex.fit(customers)  # 拟合数据,得到 字符型数据转换模型
customers = model.transform(customers)  # 将customers中的字符型数据数值化,并把转化后的列添加到原数据customers
print("数值化字符型列的数据集:")
customers.show(5)

数值化后的数据集部分 数据 如下。
在这里插入图片描述

6.2 选择、向量化特征

选择数值类型的特征"Age", “Income”, “Spending”, “indexed_Gender”,并向量化为一列:raw_features。

# 选择特征
features = ["Age", "Income", "Spending", "indexed_Gender"]

# 将选择的特征组合成一个向量
data_assembler = VectorAssembler(inputCols=features, outputCol='raw_features')  # 实例化向量转换器
customers_assembled = data_assembler.transform(customers)  # 向量化数据集中选定的数值型特征,将自动添加一列数据raw_features
customers_assembled.show(5)

  向量化后的数据集部分数据如下:
在这里插入图片描述

6.3 计算特征之间的相关性系数(Correlation()),绘制热力图

  特征"Age", “Income”, “Spending”, "indexed_Gender"之间的相关性稀疏如下:
在这里插入图片描述
  热力图如下:
在这里插入图片描述
  相关性系数的值范围从-1到1,其中1表示完全正相关,-1表示完全负相关,0表示没有线性相关。
  代码如下:

# -------计算相关性系数,绘制热力图------
print("\n\n-------计算相关性系数------")
corr = Correlation.corr(customers_assembled, 'raw_features').collect()[0][0]
corr_float = corr.toArray().astype(float)
print(corr_float)

# 将相关性系数矩阵转换为Pandas DataFrame,以便使用matplotlib显示
corr_df = pd.DataFrame(corr_float, columns=features, index=features)

# 显示相关性系数矩阵的热力图
plt.imshow(corr_df, cmap='coolwarm', interpolation='nearest')
plt.colorbar()
plt.xticks(range(len(features)), features, rotation=45)  # 设置横坐标标签
plt.yticks(range(len(features)), features)  # 设置纵坐标标签

# 在热力图上添加每个相关性系数的值
for i in range(len(features)):
    for j in range(len(features)):
        if i == j:
            # 不显示对角线上的值
            continue
        plt.text(j, i, np.round(corr_df.iloc[i, j], 2), ha='center', va='center', color='black')
plt.show()

6.4 构建聚类模型、评估聚类模型

  设聚类簇数k=3,将客户分为3类。

# -----------5.构建聚类模型--------
km = KMeans(featuresCol='raw_features', k=3)  # 构建聚类模型
# km = BisectingKMeans(featuresCol='raw_features', k=3)
kmModel = km.fit(customers_assembled)  # 拟合模型
km_pred = kmModel.transform(customers_assembled)  # 用模型聚类,得到聚类结果列:prediction
km_pred.show(10)

# 评估聚类模型
km_evaluator = ClusteringEvaluator(predictionCol='prediction', featuresCol='raw_features')
silhouette = km_evaluator.evaluate(km_pred)
print("轮廓系数为:", silhouette)

results = kmModel.clusterCenters()  # 聚类中心:"Age", "Income", "Spending", "indexed_Gender"
print("聚类中心:", results)
# -------打印3簇聚类中心------
for i in results:
    print(i)

在这里插入图片描述

6.5 数据可视化

  绘制各簇的的Income和Spending核密度图,以及散点图和簇中心。代码如下。

# --------6. 数据可视化-------
print("\n-----分别选取各簇数据------")
pred_0 = km_pred.where(km_pred['prediction'] == 0).toPandas()  # 选取 簇0 数据

pred_1 = km_pred.select('Age', 'Income', 'Spending', 'prediction') \
    .where(km_pred['prediction'] == 1) \
    .toPandas()  # 选取 簇1 数据

pred_2 = km_pred.select('Age', 'Income', 'Spending', 'prediction') \
    .where(km_pred['prediction'] == 2) \
    .toPandas()  # 选取 簇2 数据

#--- 绘制各簇 的Income和Spending核密度图--
plt.subplot(2, 1, 1)
pred_0['Income'].plot(kind='kde')
plt.title("簇0 Income、Spending概率密度图")
plt.subplot(2, 1, 2)
pred_0['Spending'].plot(kind='kde', c='orange')
plt.show()  # 簇0的概率密度图

plt.subplot(2, 1, 1)
pred_1['Income'].plot(kind='kde')
plt.title("簇1 Income、Spending概率密度图")
plt.subplot(2, 1, 2)
pred_1['Spending'].plot(kind='kde', c='orange')
plt.show()  # 簇1的概率密度图

plt.subplot(2, 1, 1)
pred_2['Income'].plot(kind='kde')
plt.title("簇2 Income、Spending概率密度图")
plt.subplot(2, 1, 2)
pred_2['Spending'].plot(kind='kde', c='orange')
plt.show()  # 簇2的概率密度图

# ---------------绘制各簇Income和Spending 散点图-----------------
plt.scatter(pred_0['Income'], pred_0['Spending'], c='red', label='Cluster 0')
plt.scatter(pred_1['Income'], pred_1['Spending'], c='blue', label='Cluster 1')
plt.scatter(pred_2['Income'], pred_2['Spending'], c='green', label='Cluster 2')

# 簇中心:"Age", "Income", "Spending", "indexed_Gender",
x_coords = [result[1] for result in results]  #提取所有聚类中心的第二个元素Income作为 x 坐标
y_coords = [result[2] for result in results]  # 提取所有聚类中心的第三个元素Spending作为 y 坐标
plt.scatter(x_coords, y_coords, c='pink', s=100, label='Centroids')  # 聚类中心

plt.xlabel('Income')
plt.ylabel('Spending')
plt.legend()
plt.show()

  各簇的Income和Spending概率密度图如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  各簇的Income和Spending散点图。
在这里插入图片描述
参考资料:

1.pyspark学生成绩分析与预测(上):https://blog.csdn.net/weixin_52563520/article/details/137675514
2.https://blog.csdn.net/weixin_52563520/article/details/139126270?spm=1001.2014.3001.5502
3.https://blog.csdn.net/weixin_52563520/article/details/135358767?spm=1001.2014.3001.5502
4.spark学习回归理论和实战房价预测:https://blog.csdn.net/qq_35394891/article/details/83184779
5.基于pyspark的波士顿房价预测案例:https://blog.csdn.net/weixin_46474921/article/details/121780705
6.戴刚,张良均. PySpark大数据分析与应用. 人民邮电出版社,2024.
7.汪明. PySpark实战. 清华大学出版社,2022
8.用 K-Means聚类算法(K-Means Clustering)分析客户:https://zhuanlan.zhihu.com/p/502192474
9.Python实现聚类(Kmeans)分析客户分组:https://blog.csdn.net/weixin_42163563/article/details/119829124
10.Pyspark+关联规则 Kaggle购物篮分析案例:https://blog.csdn.net/thorn_r/article/details/138351087
11.Spark 关联规则挖掘:https://blog.csdn.net/weixin_39709476/article/details/109223271
12.大数据–关联规则挖掘案例:https://blog.csdn.net/qq_51641196/article/details/128478588

  • 13
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

侧耳倾听童话

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值