Kmeans算法来实现RFM指标计算步骤

        K-Means(K均值)是一种经典的无监督聚类算法,主要用于将数据集划分为 KKK 个不同的簇(Cluster)。

        它基于最小化簇内样本的平方误差,即最小化数据点与簇中心的距离之和。


1. K-Means 算法原理

(1) 主要步骤

  1. 初始化
    选择 KKK 个初始聚类中心(可以随机选取,也可以使用K-Means++优化选择)。

  2. 分配样本到最近的簇中心
    对于数据集中的每个点,将其分配给最近的聚类中心(使用欧几里得距离、曼哈顿距离等度量)。

  3. 更新簇中心
    计算每个簇中所有点的均值,并将该均值作为新的簇中心。

  4. 重复步骤 2 和 3
    直到聚类中心不再发生变化或者达到最大迭代次数。

(2) 目标函数

K-Means 试图最小化以下目标函数(平方误差):

                     


    2. K-Means 的特点

    (1) 优势

    • 计算速度快,时间复杂度接近 O(nKT)O(nKT)O(nKT)(其中 TTT 是迭代次数)。
    • 适用于大规模数据集,易于并行化(可以结合MapReduce/Spark实现)。
    • 聚类结果可解释性强,适用于数据分析、推荐系统、用户分群等场景。

    (2) 局限性

    • K值需要人为指定,如果选择不当,可能会导致聚类效果不佳。
    • 对初始簇中心敏感,可能陷入局部最优(K-Means++ 可以优化初始中心选择)。
    • 对异常点敏感,受离群点影响较大。
    • 适用于凸形簇,对非球形分布的数据表现较差。

    3. K-Means Demo示例

    # 使用机器学习算法实现rfm
    from utils.base import BasicTag
    from pyspark.sql import SparkSession,functions as F
    from pyspark.sql.types import *
    from pyspark.ml.feature import VectorAssembler
    from pyspark.ml.clustering import KMeansclass RFMTag(BasicTag):def make_tag(self):rule_dict = self.data_dict# 1-计算获取RFM的值# 消费周期计算recency = F.datediff(F.current_date(), F.from_unixtime(F.max('finishtime'))).alias('diff_dt').alias('recency')# 订单量frequency = F.countDistinct('ordersn').alias('frequency')# 订单金额monetary = F.sum('orderamount').alias('monetary')df_rfm = self.df_es.groupby('memberid').agg(recency,frequency,monetary)# 2-根据计算的结果,将数据划分5个等级进行打分
    # -----------------------------R数据打分----------------------------------------------------------------------------------# 2-1 特征工程将数据转为向量(只有转化为坐标向量(VectorAssembler),才能在坐标轴上计算方向及两点之间的距离,再求平均距离)v_r = VectorAssembler(inputCols=['recency'],outputCol='v_r')# 添加转化数据,将上面订单金额加入进行转化df_r_fit = v_r.transform(df_rfm)# 2-2 使用kmeas算法打分,#     k参数负责划分几个分数段;#     featuresCol负责传入向量值用于聚类的特征向量的列名;#     predictionCol 用于存储聚类结果的列名。KMeans算法会在训练数据上进行聚类分析,并将每个数据点分配到一个聚类。这个聚类结果会存储在predictionCol指定的列中。#+---+-----------------+                                    +---+-----------------------+#|id |        v_r      |                                    |id |        v_r      | k_r |#+---+-----------------+                                    +---+-----------------+-----+#| 1 | [1.0, 2.0, 3.0] |          执行KMeans聚类后:          | 1 | [1.0, 2.0, 3.0] |  0  |#| 2 | [4.0, 5.0, 6.0] |    ————————————————————————>       | 2 | [4.0, 5.0, 6.0] |  1  |#| 3 | [7.0, 8.0, 9.0] |                                    | 3 | [7.0, 8.0, 9.0] |  2  |#| 4 |[10.0, 11.0, 12.0]|                                   | 4 |[10.0, 11.0, 12.0]|  3 |kmeans = KMeans(k=5,featuresCol='v_r',predictionCol='k_r')# 添加数据----kmeans.fit( )用于训练模型,训练完生成一个KMeans模型对象k_r_fitk_r_fit = kmeans.fit(df_r_fit)# 转化数据,对训练结果进行预测,将预测结果添加到数据框:df_k_r中df_k_r = k_r_fit.transform(df_r_fit)df_k_r.show()# 计算k值中心判断k值的大小--clusterCenters()获取每个聚类的中心点(质心),存储在cluster变量中。cluster = k_r_fit.clusterCenters()# 遍历k值(质点)中心,计算k值的和# cluster_dict = {}:创建一个空字典,用于存储每个聚类中心点的索引和其特征值的和。# enumerate:是 Python 的一个内置函数,用于在遍历可迭代对象(如列表、元组、字符串等)时,同时获取每个元素的索引和值。它返回一个枚举对象,该对象生成一系列包含索引和值的元组。# 示例列表:#------------------------------------------+#   fruits = ['apple', 'banana', 'cherry'] |#   #使用 enumerate 进行遍历                 |#   for index, value in enumerate(fruits): |#   rint(index, value)                     |#--------输出------------------------------+#   0 apple                               |#   1 banana                              |#   2 cherry                              |#-----------------------------------------+cluster_dict = {}for i, v in enumerate(cluster):cluster_dict[i] = sum(v)print(cluster_dict)  # 输出结果:{0: 1445.0, 1: 1446.0, 2: 1447.0}# 中心点排序,对cluster_dict按特征值的和进行升序排序--并强制类型转化为字典格式cluster_dict_sort = dict(sorted(cluster_dict.items(), key=lambda x: x[1]))# 对k中心替换大小# count = 0:初始化计数器。# for k, v in cluster_dict_sort.items():遍历排序后的字典cluster_dict_sort。# cluster_dict_sort[k] = count:将排序后的中心点索引替换为从0开始的递增值。# count += 1:计数器递增。然后使用cluster_dict_sort[k] 进行值的替换count = 0for k, v in cluster_dict_sort.items():cluster_dict_sort[k] = countcount += 1# 替换原来df中的k值编号@F.udf(returnType=IntegerType())def repace_data(k):return cluster_dict_sort.get(k)df_replace_r = df_k_r.select(df_k_r.memberid,df_k_r.recency,df_k_r.frequency,df_k_r.monetary,repace_data('k_r').alias('k_r'))#-----------------------------F数据打分----------------------------------------------------------------------------------# 2-1 特征工程将数据转为向量f_r = VectorAssembler(inputCols=['frequency'], outputCol='f_r')# 添加转化数据df_f_fit = f_r.transform(df_replace_r)# 2-2 kmeas算法打分kmeans = KMeans(k=5, featuresCol='f_r', predictionCol='k_f')# 添加数据f_r_fit = kmeans.fit(df_f_fit)# 转化数据df_f_r = f_r_fit.transform(df_f_fit)# 计算k值中心判断k值的大小cluster = f_r_fit.clusterCenters()# 遍历k值中心,计算k值的和cluster_dict = {}for i, v in enumerate(cluster):cluster_dict[i] = sum(v)# 中心点排序cluster_dict_sort = dict(sorted(cluster_dict.items(), key=lambda x: x[1]))# 对k中心替换大小count = 0for k, v in cluster_dict_sort.items():cluster_dict_sort[k] = countcount += 1# 替换原来df中的k值编号@F.udf(returnType=IntegerType())def repace_data1(k):return cluster_dict_sort.get(k)df_replace_f = df_f_r.select(df_f_r.memberid, df_f_r.recency, df_f_r.frequency, df_f_r.monetary,df_f_r.k_r,repace_data1('k_f').alias('k_f'))print('F计算完成')
    # -----------------------------M数据打分----------------------------------------------------------------------------------# 2-1 特征工程将数据转为向量# TODO:inputColss输入字段修改  outputCol字段修改m_r = VectorAssembler(inputCols=['monetary'], outputCol='m_r')# 添加转化数据# TODO: 替换上一步的df数据df_f_fit = m_r.transform(df_replace_f)# 2-2 kmeas算法打分# TODO:inputColss输入字段修改  outputCol字段修改kmeans = KMeans(k=5, featuresCol='m_r', predictionCol='k_m')# 添加数据f_r_fit = kmeans.fit(df_f_fit)# 转化数据df_f_r = f_r_fit.transform(df_f_fit)df_f_r.show()print('M评分')# 计算k值中心判断k值的大小cluster = f_r_fit.clusterCenters()# 遍历k值中心,计算k值的和cluster_dict = {}for i, v in enumerate(cluster):cluster_dict[i] = sum(v)# 中心点排序cluster_dict_sort = dict(sorted(cluster_dict.items(), key=lambda x: x[1]))# 对k中心替换大小count = 0for k, v in cluster_dict_sort.items():cluster_dict_sort[k] = countcount += 1# 替换原来df中的k值编号@F.udf(returnType=IntegerType())def repace_data2(k):return cluster_dict_sort.get(k)# TODO:df_replace_m = df_f_r.select(df_f_r.memberid, df_f_r.recency, df_f_r.frequency, df_f_r.monetary, df_f_r.k_r, df_f_r.k_f,repace_data2('k_m').alias('k_m'))df_replace_m.show()print('M计算完成')# 3-计算所有用户的平均打分--结果为一行数据df_rfm_score_avg = df_replace_m.select(F.avg('k_r').alias('r_avg'),F.avg('k_f').alias('f_avg'),F.avg('k_m').alias('m_avg'))# +-----+-----+-----+# |r_avg|f_avg|m_avg|# +-----+-----+-----+# | 2.0 | 3.0 | 4.0 |# +-----+-----+-----+# 将平均分转为row对象可以获第一行取值(实际上只有一行)# row 是一个 Row 对象,它允许你像访问属性一样访问列值。row = df_rfm_score_avg.first()# 4-通过平均值判断rfm的高低df_rfm_num =  df_replace_m.select(df_replace_m.memberid,# 大于为1  否则为0F.when(df_replace_m.k_r >= row['r_avg'],1).otherwise(0).alias('rn'),F.when(df_replace_m.k_f > row['f_avg'],1).otherwise(0).alias('fn'),F.when(df_replace_m.k_m > row['m_avg'],1).otherwise(0).alias('mn'),)# 5-标签匹配# df_rfm_num 是一个包含 RFM 分数的 DataFrame。# select 方法选择了 memberid 列和通过 concat 方法连接的 RFM 分数(即 rn、fn、mn)。# F.concat 将 R、F、M 分数转化为字符串并连接成一个新的字符串。# 最后,alias('rfm') 为这个新字符串列命名为 rfmdf_rfm_str = (df_rfm_num.select(df_rfm_num.memberid,F.concat  # F.concat 将 R、F、M 分数转化为字符串并连接成一个新的字符串。并且alias('rfm') 为这个新字符串列命名为 rfm(df_rfm_num.rn.cast('string'),df_rfm_num.fn.cast('string'),df_rfm_num.mn.cast('string')).alias('rfm')))df_rfm_str.show()# 这是一个用户定义函数(UDF),用于根据 rule_dict 字典将 RFM 字符串映射到相应的标签。# @F.udf(returnType=StringType()) 装饰器用于将 Python 函数转化为 PySpark UDF,并指定返回类型为 StringType()。@F.udf(returnType=StringType())def match(data):return rule_dict.get(data)# 应用 match 函数并创建新 DataFrame:self.df_new_tag = (df_rfm_str.select(df_rfm_str.memberid.alias('userID'),match(df_rfm_str.rfm).alias('tagsID')))# 创建对象
    ss = SparkSession.builder.config('spark.sql.shuffle.partitions','6').getOrCreate()
    rfm = RFMTag()
    # 执行
    rfm.action('RFM', ss, 'tfec_tags', 'tbl_basic_tag')

    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/28245.html

    如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    C# .NET Core HttpClient 和 HttpWebRequest 使用

    HttpWebRequest 这是.NET创建者最初开发用于使用HTTP请求的标准类。HttpWebRequest是老版本.net下常用的,较为底层且复杂,访问速度及并发也不甚理想,但是使用HttpWebRequest可以让开发者控制请求/响应流程的各个方面,如 timeouts,…

    run方法执行过程分析

    文章目录 run方法核心流程SpringApplicationRunListener监听器监听器的配置与加载SpringApplicationRunListener源码解析实现类EventPublishingRunListener 初始化ApplicationArguments初始化ConfigurableEnvironment获取或创建环境配置环境 打印BannerSpring应用上下文的创建S…

    1.从0搭建前端Vue项目工程

    我们通过vue官方提供的脚手架Vue-cli来快速生成一个Vue的项目模板。 **注意:**需要先安装NodeJS,然后才能安装Vue-cli。 环境准备好了,接下来我们需要通过Vue-cli创建一个vue项目,然后再学习一下vue项目的目录结构。Vue-cli提供了…

    C语言学习笔记-初阶(27)操作符详解1:位操作

    1. 操作符的分类 上述的操作符,我们已经学过算术操作符、赋值操作符、逻辑操作符、条件操作符和部分的单目操作符,今天继续介绍⼀部分,操作符中有一些操作符和二进制有关系,我们先铺垫一下二进制的和进制转换的知识。 2. 二进制、…

    蓝桥杯备考:动态规划线性dp之传球游戏

    按照动态规划的做题顺序 step1&#xff1a;定义状态表示 f[i][j] 表示 第i次传递给了第j号时一共有多少种方案 step2: 推到状压公式 step3:初始化 step4:最终结果实际上就是f[m][1] #include <iostream> #include <cstring> using namespace std;const int N …

    FinRobot:一个使用大型语言模型进行金融分析的开源AI代理平台

    文章目录 前言一、生态系统1. 金融AI代理&#xff08;Financial AI Agents&#xff09;2. 金融大型语言模型&#xff08;Financial LLMs&#xff09;3. LLMOps4. 数据操作&#xff08;DataOps&#xff09;5. 多源LLM基础模型&#xff08;Multi-Source LLM Foundation Models&am…

    基于Windows11的RAGFlow安装方法简介

    基于Windows11的RAGFlow安装方法简介 一、下载安装Docker docker 下载地址 https://www.docker.com/ Download Docker Desktop 选择Download for Winodws AMD64下载Docker Desktop Installer.exe 双点击 Docker Desktop Installer.exe 进行安装 测试Docker安装是否成功&#…

    uniapp 常用 UI 组件库

    1. uView UI 特点&#xff1a; 组件丰富&#xff1a;提供覆盖按钮、表单、图标、表格、导航、图表等场景的内置组件。跨平台支持&#xff1a;兼容 App、H5、小程序等多端。高度可定制&#xff1a;支持主题定制&#xff0c;组件样式灵活。实用工具类&#xff1a;提供时间、数组操…

    【四.RAG技术与应用】【12.阿里云百炼应用(下):RAG的云端优化与扩展】

    在上一篇文章中,我们聊了如何通过阿里云百炼平台快速搭建一个RAG(检索增强生成)应用,实现文档智能问答、知识库管理等基础能力。今天咱们继续深入,聚焦两个核心问题:如何通过云端技术优化RAG的效果,以及如何扩展RAG的应用边界。文章会穿插实战案例,手把手带你踩坑避雷。…

    LabVIEW虚拟频谱分析仪

    在电子技术快速发展的今天&#xff0c;频谱分析已成为信号优化与故障诊断的核心手段。传统频谱分析仪虽功能强大&#xff0c;但价格高昂且体积笨重&#xff0c;难以满足现场调试或移动场景的需求。 基于LabVIEW开发的虚拟频谱分析仪通过软件替代硬件功能&#xff0c;显著降低成…

    解决各大浏览器中http地址无权限调用麦克风摄像头问题(包括谷歌,Edge,360,火狐)后续会陆续补充

    项目场景&#xff1a; 在各大浏览器中http地址调用电脑麦克风摄像头会没有权限&#xff0c;http协议无法使用多媒体设备 原因分析&#xff1a; 为了用户的隐私安全&#xff0c;http协议无法使用多媒体设备。因为像摄像头和麦克风属于可能涉及重大隐私问题的API&#xff0c;ge…

    知识图谱科研文献推荐系统vue+django+Neo4j的知识图谱

    文章结尾部分有CSDN官方提供的学长 联系方式名片 文章结尾部分有CSDN官方提供的学长 联系方式名片 关注B站&#xff0c;有好处&#xff01; &#x1f4d1; 编号&#xff1a;D030 &#x1f4d1; vuedjangoneo4jmysql 前后端分离架构、图数据库 &#x1f4d1; 文献知识图谱&#…

    NModbus 连接到Modbus服务器(Modbus TCP)

    1、在项目中通过NuGet添加NModbus&#xff0c;在界面中添加一个Button。 using NModbus.Device; using NModbus; using System.Net.Sockets; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Docu…

    Ubuntu问题 - 在ubuntu上使用 telnet 测试远程的IP:端口是否连通

    使用 telnet 测试端口连接 安装 telnet&#xff08;如果尚未安装&#xff09;&#xff1a; sudo apt update sudo apt install telnet使用 telnet 测试端口&#xff1a; 假设你要测试 example.com 的 80 端口&#xff08;HTTP&#xff09;&#xff0c;可以运行以下命令&#xf…

    全网最全!解决VirtualBox或VMware启动虚拟机时报错问题“不能为虚拟电脑打开一个新任务”和“Error In suplibOslnit”解决方案超全超详细

    我自己下载并配置完VritualBox和OpenEuler之后帮助了几个朋友和我的室友在她们的电脑上下载安装时出现了不同的问题&#xff0c;下面我将简单解释一下如何解决配置时出现的两个无法启动虚拟器的问题。 目录 问题&#xff1a;“不能为虚拟电脑XX打开一个新任务”和“Error In …

    SpringMVC(2)传递JSON、 从url中获取参数、上传文件、cookie 、session

    Spring 事务传播机制包含以下 7 种&#xff1a; Propagation.REQUIRED&#xff1a;默认的事务传播级别&#xff0c;它表示如果当前存在事务&#xff0c;则加入该事务&#xff1b;如果当前没有事务&#xff0c;则创建一个新的事务。Propagation.SUPPORTS&#xff1a;如果当前存…

    软考中级-数据库-3.4 数据结构-图

    图的定义 一个图G(Graph)是由两个集合:V和E所组成的&#xff0c;V是有限的非空顶点(Vertex)集合&#xff0c;E是用顶点表示的边(Edge)集合&#xff0c;图G的顶点集和边集分别记为V(G)和E(G)&#xff0c;而将图G记作G(V&#xff0c;E)。可以看出&#xff0c;一个顶点集合与连接这…

    开源表单、投票、测评平台部署教程

    填鸭表单联合宝塔面板深度定制,自宝塔面板 9.2 版本开始,在宝塔面板-软件商店中可以一键部署填鸭表单系统。 简单操作即可拥有属于自己的表单问卷系统,快速赋能业务。即使小白用户也能轻松上手。 社区版体验地址:https://demo.tduckapp.com/home 前端项目地址: tduck-fro…

    IDEA 接入 Deepseek

    在本篇文章中&#xff0c;我们将详细介绍如何在 JetBrains IDEA 中使用 Continue 插件接入 DeepSeek&#xff0c;让你的 AI 编程助手更智能&#xff0c;提高开发效率。 一、前置准备 在开始之前&#xff0c;请确保你已经具备以下条件&#xff1a; 安装了 JetBrains IDEA&…

    Metal学习笔记七:片元函数

    知道如何通过将顶点数据发送到 vertex 函数来渲染三角形、线条和点是一项非常巧妙的技能 — 尤其是因为您能够使用简单的单行片段函数为形状着色。但是&#xff0c;片段着色器能够执行更多操作。 ➤ 打开网站 https://shadertoy.com&#xff0c;在那里您会发现大量令人眼花缭乱…