航空公司客户价值分析:LRFMC特征与K-means聚类实战指南

发布时间:2026/10/15 7:33:18

航空公司客户价值分析:LRFMC特征与K-means聚类实战指南 简介这是一份面向航空公司客户价值分析场景的数据挖掘课程设计完整资料包适合数据挖掘初学者、高校相关专业学生及需要完成同类项目的开发者。内容围绕客户价值分析全流程展开涵盖数据预处理、数据探索、客户细分、预测模型构建、关联规则学习及模型评估优化等关键知识点可帮助读者系统理解从原始数据到业务决策的完整链路。压缩包共23个文件大小约20.78MB主要包含7个Python源代码脚本、Excel及CSV格式的多维数据集、课程设计文档和考试要求说明代码与数据配套完善便于直接运行复现聚类、标准化、清洗等实验。目前已有1254人学习。资源中提供了KMeans聚类、z-score标准化、数据探索等核心实现并附有中间结果文件和详细设计文档读者可对照学习每一步分析技巧与业务落地方案也可作为课程报告或项目申报的参考模板。1. 航空公司客户价值分析数据挖掘最常见的翻车点特征没算对航空公司客户价值分析数据挖掘最常见的翻车点不是模型选得不够新而是特征没算对。比如沿用传统RFM模型刚入会但近期频繁飞的会员会因消费金额不高被划到低价值组优惠券发错对象运营一边骂模型不准一边继续拍脑袋决策。这套设计弃用单一维度的RFM改用LRFMC五维特征——入会时长、最近飞行间隔、飞行次数、总里程和平均折扣把它们放进同一套聚类流程最终把客户分成五类人群。它适合正在做数据挖掘课程设计或毕业设计的学生也适合想快速搭建客户分层方案的从业者把会员表加乘机记录导入按后面的预处理、聚类、解读三步走几十分钟就能得到一份能写进报告的结果。2. 数据规范与特征构造LRFMC模型下从原始表到标准化特征的落地步骤2.1 原始数据长什么样字段与表关系这份数据挖掘设计配套的源码里演示数据通常是一张会员汇总表已经按照会员编号把乘机记录聚合过而不是让你从明细流水开始做。这样做的好处是降低入门难度也让评审能一眼看懂每个特征的含义。典型的表结构至少包含这几列会员编号、入会日期、最近一次乘机日期、飞行次数、累计飞行里程、平均折扣系数。有些数据源还会给舱位等级、积分余额但核心建模用不到那么多建议先做瘦身。如果用的是SQL数据源表结构可以按下面的方式设计CREATE TABLE member_summary ( member_id VARCHAR(32) COMMENT 会员编号, join_date DATE COMMENT 首次入会日期, last_flight_date DATE COMMENT 最近一次乘机日期, flight_count INT COMMENT 观察期内飞行次数, total_mileage FLOAT COMMENT 累计飞行里程, avg_discount FLOAT COMMENT 平均折扣系数 );之所以把“最近一次乘机日期”单独拎出来是因为它直接决定R特征的计算。很多原始表里只有“乘机日期列表”这种长表需要先用group by取最大值。源码里用pandas完成这一步你只要保证列名能被代码识别。我在实际项目里常碰到列名不一样的情况通常会先做一个列名映射而不是硬改数据文件。2.2 LRFMC特征的计算口径进入模型前要把原始字段转换成五个业务特征。下表给出常用口径特征计算方式业务含义L观察窗口截止日期 - 入会日期取天数再除以365客户在册时长R观察窗口截止日期 - 最近乘机日期取天数最近一次飞行的间隔F观察期内总飞行次数消费频次M观察期内总飞行里程总消费量C平均折扣系数消费偏好与客单价注意R和L都依赖一个“观察窗口截止日期”。经典案例的做法是取数据源里最大的日期比如2014年12月31日也有按季度固定窗口的做法。不要用当前系统日期否则评审按同一份数据复现时会得到完全不同的结果。我习惯先把窗口截止日期写成常量放在脚本开头后面所有特征都引用它这样复现和调参都方便。2.3 数据清洗与异常值处理原始数据最常出现的三类脏数据重复会员编号、空值、不合理折扣。重复记录的来源通常是多期汇总表拼起来没去重直接全表删除会影响后面对客户群的统计空值如果只发生在非关键列可以用中位数填充平均折扣系数大于1.2的记录基本是退改签或数据录入错误按比例小、不影响整体直接剔除。下面是源码里对应的处理片段import pandas as pd from datetime import datetime df pd.read_csv(member.csv, encodinggbk) df df.drop_duplicates(subset[member_id]) df df[(df[avg_discount] 0) (df[avg_discount] 1.2)] df.loc[df[flight_count].isna(), flight_count] df[flight_count].median()第四行的中位数填充属于“软化处理”如果飞行次数缺失直接用0会把客户身份判成低价值用中位数则保留该客户原有画像。这个取舍答辩时经常被问到你可以正面解释。接下来把日期列转成时间类型并做保质期检查df[join_date] pd.to_datetime(df[join_date]) df[last_flight_date] pd.to_datetime(df[last_flight_date]) assert df[last_flight_date].max() observation_end断言的作用是防止数据里混进观察窗口之外的记录一旦触发马上中止而不是带着脏数据往下跑。2.4 特征构造与标准化实现五个特征可以一次性构造。这里要先把observation_end定义为固定常量放在脚本开头observation_end datetime(2014, 12, 31) df[L] (observation_end - df[join_date]).dt.days / 365 df[R] (observation_end - df[last_flight_date]).dt.days df[F] df[flight_count] df[M] df[total_mileage] df[C] df[avg_discount]这里L和R单位不同L是年R是天。进入K-means之前必须标准化。标准化的主要目的是消除量纲不是说原始值不能用而是欧氏距离会被M这种几千上万的值带偏最后分群只看里程飞行频次和折扣完全不起作用。我一般会在标准化前先看分布里程通常是长尾存在少数总里程几十万公里的常旅客。遇到这类数据先把M做log1p压缩再标准化比直接Z-score更稳import numpy as np from sklearn.preprocessing import StandardScaler df[M_log] np.log1p(df[M]) features df[[L, R, F, M_log, C]] scaler StandardScaler() X scaler.fit_transform(features)源码里默认做了这一步注释也写清楚了。直接跑出来轮廓系数会优于不做log的方案。建议你在课程报告里把这步写成“特征偏态修正”比只写“标准化”更容易拿分。3. 聚类建模与结果解读基于K-means的五类客户分群流程3.1 手肘法确定K值选K值时先跑一段循环把聚类模型的inertia画出来。inertia即簇内误差平方和K越大簇内越紧凑但超过合理值后下降变慢。对这份会员数据K5附近出现明显拐点所以后续用五类。from sklearn.cluster import KMeans import matplotlib.pyplot as plt sse [] for k in range(2, 9): model KMeans(n_clustersk, random_state42, max_iter500, n_init10) model.fit(X) sse.append(model.inertia_) plt.plot(range(2, 9), sse, markero) plt.xlabel(K) plt.ylabel(SSE) plt.title(Elbow Method) plt.savefig(elbow.png)max_iter500是K-means迭代上限一般不会跑满n_init10表示用10个不同的随机初始化跑并取最好结果避免落入局部最优。这两个参数在答辩时可以直接回答“为什么这样设”。观察拐点时要看整条曲线的下降趋势不要只盯最小K。如果K6和5差不多优先选5因为五类客户在业务上更好命名。3.2 训练模型并回写标签确定K后重新训练一次并保存模型import joblib model KMeans(n_clusters5, random_state42, max_iter500, n_init10) labels model.fit_predict(X) df[cluster] labels joblib.dump(model, kmeans_model.pkl) joblib.dump(scaler, scaler.pkl)保存模型和scaler的意义在于以后来了新会员可以调用同一套标准流程做预测而不用把历史数据重新聚类一遍。代码里用joblib是为了和sklearn版本兼容。紧接着做分群统计group_stats df.groupby(cluster)[[L, R, F, M, C]].mean()这个groupby输出的表格就是客户画像的依据。3.3 聚类结果分析与业务命名典型结果下五个聚类中心大体呈现这样的特征用相对高低描述不作为固定数值客户类型LRFMC运营建议重要保持客户高低高高高权益优先、专属服务重要发展客户中低中中中促销刺激提升里程重要挽留客户高高低高低定向召回、唤醒一般客户低中中低低常规运营低价值客户低高低低低减少营销成本注意R字段越高代表距离上次飞行越久所以高R对业务是危险信号。给簇命名时最常用的是“重要保持/重要发展/重要挽留/一般/低价值”这是经典案例最常见的分法。在实际数据里重要保持客户的人数占比通常在15%到25%之间如果超过30%要么K选小了要么特征构造有问题需要倒回去查。3.4 客户画像可视化和结果保存雷达图很适合放在报告里用来展示五个簇在五维特征上的差异。画每一簇时要先把中心点坐标取出再闭合折线import numpy as np import matplotlib.pyplot as plt labels_list [L, R, F, M_log, C] centers model.cluster_centers_ for i, center in enumerate(centers): values center.tolist() values values[:1] angles np.linspace(0, 2 * np.pi, len(labels_list), endpointFalse).tolist() angles angles[:1] plt.polar(angles, values, labelfCluster {i}) break # 演示代码只画第一簇完整源码循环绘制五条雷达线雷达图里的坐标轴是标准化后的值所以M_log代替M解释时要说清楚“这是取对数后的相对水平”。如果给业务方看建议把R列取相反数让“越高越好”的方向与直觉一致否则高R的簇会被误读成优质客户。所有图表保存到result目录报告引用这些图片评审看着不会空对空。4. 避坑指南建模中最容易翻车的五类问题这一章不是额外附加题而是项目里容易让“评审一眼看出没做过真实项目”的地方。下面五类坑是我按频率排的你可以直接对照自查。4.1 量纲干扰分群结果只围绕里程展开现象聚类结束后重要保持客户和低价值客户之间只差总里程数飞行次数、折扣系数几乎没差别五个簇的业务画像读起来像同一个模板复制出来的。原因K-means默认使用欧氏距离而总里程M的量级常常是几万飞行次数F可能只有十几平均折扣C在0到1之间距离计算几乎被M主导。如果不做任何压缩聚类等价于把客户按里程从高到低切五段这不是客户价值分析是排序题。解决进入模型前先把M取对数再进行标准化。取log1p是为了把偏态分布拉回接近正态同时保证零值不报错。然后对标准化后的特征做一次方差检查哪个特征方差远大于其他特征说明压缩不够。源码里这段处理是df[M_log] np.log1p(df[M]) features df[[L, R, F, M_log, C]]注意R特征也不能掉以轻心有的样本最近乘机时间是三年前R高达一千多会形成第二根“大柱子”。对R我习惯用分位数封顶把超过95分位数的值压到95分位数的值而不是直接删除因为这类客户可能恰恰是流失用户删掉反而丢了商业信号。4.2 离群样本制造“一人一簇”现象跑完分类后发现某个簇只有两三个样本雷达图画出来是一个尖锐的三角中心点和所有其他簇离得很远业务上说不出这批人是谁。原因原始表里混入了内部员工测试账号或者一个会员编号被多次重复汇总累计里程叠加到几十万公里。这类离群点和主体人群在欧氏距离下天然分家K-means会专门为它们分配一个簇。解决训练之前用IQR法做一轮筛查。以M为例计算第一四分位数Q1和第三四分位数Q3超过Q33倍IQR的记录暂时剔除。如果整体数据只有几千行不要直接删改用封顶策略把超限值设为阈值。代码放在清洗阶段Q1 df[M].quantile(0.25) Q3 df[M].quantile(0.75) IQR Q3 - Q1 df[M_cap] df[M].clip(upperQ3 3 * IQR)封顶之后再做log1p离群点的影响会大幅减弱。你可以在报告里写一句“本次剔除异常样本X条”这个数量也是答辩时会被问到的细节。4.3 K值照搬经典五类导致簇大小严重失衡现象网上看到的航空公司客户价值分析案例都是五类直接设K5结果第一类占了70%剩下四类加一起30%。评审看一眼占比就开始质疑。原因案例的数据分布和课堂的演示数据不一样手肘图的实际拐点可能出现在K3或K4。强行设5就会把一个本应连贯的客户群硬拆成几块最大簇被随机切分。解决每次建模先跑K从2到8的SSE同时计算轮廓系数画在一张图上对比。如果K4的轮廓系数是0.36K5只有0.32果断取4。反过来说如果两者差不多取大数K因为业务解释可以更细化。判断标准归纳成一句话在轮廓系数不显著下降的前提下优先选择能让每个簇都给出运营动作的K值。from sklearn.metrics import silhouette_score for k in range(2, 8): labels_k KMeans(n_clustersk, random_state42).fit_predict(X) score silhouette_score(X, labels_k) print(k, score)这个代码直接放在选K流程里给评审看的是两条曲线而不是一句话“我选的5”。4.4 用标准化后的数字直接汇报运营看不懂现象答辩PPT里写着某簇L均值-0.31R均值0.82台下运营负责人问“这是几年还是几个月为什么是负数”场面瞬间冷场。原因聚类的特征值是标准化后的相对数只能用于比较本身没有业务含义。写在报告里没有还原就等于把公式丢给别人不解释。解决聚完类立刻用原始列做聚合输出业务口径的表格。我一般会给两套表一套是建模用的标准化均值让评审确认分群依据另一套是原始量纲均值用于业务解读。第二套用下面这种方式生成report df.groupby(cluster).agg( avg_L(L, lambda x: round(x.mean(), 2)), avg_R(R, lambda x: round(x.mean(), 1)), avg_F(F, lambda x: round(x.mean(), 1)), avg_M(M, lambda x: round(x.mean(), 0)), avg_C(C, lambda x: round(x.mean(), 2)) )汇报时写“平均入会时长4.1年最近14天未乘机年飞行12次平均折扣0.78”评审不用在脑子里做减法。4.5 观察窗口不统一R特征变成随机数现象修改一次数据源后聚类结果全部变了簇排序和之前完全不一样检查代码流程都没改。原因计算R时用了系统当前日期或者用了每条会员自己的最大乘机日期。今天是这个月下个月又变了R的基数每天都在漂移标准化后的分布自然跟着变。解决把观察窗口截止日期固定成一个常量放在脚本顶部例如observation_end datetime(2014, 12, 31)。所有L、R计算都引用它这样任何人复现都会得到同样的结果。如果拿到的数据范围是2012到2014年就取2014年底如果数据只到某个月就以数据里最后一天为准并在报告里写明。5. 验收与答辩用轮廓系数和客户画像说服评审内部验收时先跑两个硬指标轮廓系数一般要大于0.3这套方案在演示数据上能到0.38左右以及每个簇的样本占比最大簇不应超过35%。先过这两个再看业务解释能否闭环能不能给每个簇一句运营建议如果能方案基本站得住。答辩准备一张“特征均值-五类客户对照表”从报告里截出来放在PPT第一页。评审最常问的三个问题为什么用K-means答案是数据无标签、样本量大、特征空间为凸簇且需要快速分群K值怎么定的答案是SSE拐点加轮廓系数并且业务可解释性优先怎么确认结果有效答轮廓系数之外更应该强调“复跑一次结果稳定”因为你固定了random_state。如果评审追问稳定性可以补一句在源码里换random_state跑三遍簇中心平移不超过0.05说明不是随机初始化碰出来的。这是我做完项目之后养成的习惯所有聚类项目强制走一遍“原始数据清洗—特征修正—标准化—选K—分簇—业务命名”的流程缺任何一步都不出报告。尤其是业务命名这步看似只是贴标签实际上是在逼自己把聚类结果翻译成运营能落地的话这也是答辩最容易拿分的亮点。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/15 7:33:18

Diagram Design:从绘图到可执行系统骨架的工程化实践

1. 项目概述:这不是画图,是构建可执行的系统逻辑骨架“diagram-design”这个词组乍看像一个普通的设计任务,但在我过去十年带过的二十多个跨领域项目里,它几乎从不指代“用PPT拖几个方框配点箭头”的表面工作。真正有价值的diagra…

2026/10/15 7:33:18

可控缺陷隔离:订单系统故障注入实战指南

1. 先说“下蛊”这回事1.1 为什么我坚持在测试里做“下蛊”我第一次给线上订单系统做故障注入时,组里同事第一反应是“你疯了”。线上稳定的服务非要往里面丢异常,这不是没事找事吗?后来我解释清楚,他们才算明白:我不是…

2026/10/15 7:28:17

基于Spring Boot的社区养老管理系统设计与实现全解析

社区养老和传统养老院的管理逻辑差得很远,工作人员要面对的是分散在社区里的大爷大妈、志愿者、第三方服务商,还要把上门护理、健康档案、服务预约、工单派发这些又琐碎又必须闭环的事管起来。拿Spring Boot做一套社区养老服务管理系统,确实是…

2026/10/15 9:24:17

断裂力学基础与工程应用解析

1. 断裂力学基础概念解析断裂力学是研究含裂纹材料在外载荷作用下裂纹扩展规律的一门学科。与传统材料力学不同,它关注的是存在缺陷的材料行为。我在工程实践中发现,90%以上的结构失效都起源于微裂纹的扩展,这正是断裂力学研究的核心价值所在…

2026/10/15 9:24:17

CDP鲲鹏版数据安全方案:AI时代的企业知识防护实践

1. 项目背景与核心挑战在当下AI语言大模型技术爆发的环境中,企业知识资产保护正面临前所未有的挑战。最近帮某金融机构做数据平台升级时,他们的CTO提了个尖锐问题:"我们花十年积累的信贷风控模型和客户数据,如果被大模型无意…

2026/10/15 9:24:17

通用Makefile模板:解决C/C++项目编译自动化与跨平台构建痛点

1. 为什么一个Makefile模板能让我少熬三次夜“通用Makefile模板与编译Linux的脚本”——这标题看着平平无奇,但在我带过的十几个嵌入式项目、高校课程实验和某公司内部工具链迁移中,它实际解决的是开发者每天都在默默承受却极少被系统性讨论的底层摩擦成…

2026/10/15 9:24:17

毕业论文AI工具怎么选?9款实测对比与选型指南

先说我观察到的一个现象:前几年毕业季,大家讨论的是“怎么把文献看完”“怎么憋出三千字”。今年开始,讨论的话题变成了“哪个AI工具能不跑偏”“润色完会不会被导师看出来”。这个变化很正常,我大概从去年年初开始密集接触各种AI…

2026/10/15 9:24:17

数字化采购系统SRM架构与实施全解析

1. 采购数字化变革的行业痛点在传统采购管理中,业务人员最头疼的莫过于"三难"问题:流程透明度难保证、合规风险难把控、供应商管理难规范。纸质审批单在各个部门间流转时经常出现丢失或延误,供应商资质审核依赖人工查验效率低下&am…

2026/10/15 9:19:12

Django CMS后台仪表盘开发实战:从admin到真正的Dashboard

1. 从“能跑”到“好用”:CMS后台仪表盘的真实需求拆解做过Django全栈项目的人大概都有这种体会:后台管理页面用Django自带的admin确实能快速跑起来,增删改查几分钟就能搞定。但一旦项目交付给非技术用户使用,问题就来了——他们打…

2026/10/14 11:31:03

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/14 17:41:07

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/14 2:32:55

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/15 0:02:22

防关联浏览器哪个好?三款产品实测差异解析

新手做多店铺,最纠结的就是防关联浏览器选哪个。飞跨、网易、站斧这三款被问得最多,先给结论:要一体化省心、长期便宜,选站斧;要网易招牌和稳,选网易;预算紧做东南亚 Lazada,选飞跨。…

2026/10/15 0:02:22

影刀RPA深度实战:大模型Fine-tuning定制RPA专用Prompt与指令生成

影刀RPA深度实战:大模型Fine-tuning定制RPA专用Prompt与指令生成 一、技术背景 大模型(LLM)在通用场景下表现强大,但当我们将 GPT-4 或 Qwen 直接用于生成影刀RPA操作指令和 XPath 定位时,准确率通常只有 40%-60%。原因…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑