ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

数据分析全流程实战:关联规则、聚类、分类与回归如何配合

数据分析全流程实战:关联规则、聚类、分类与回归如何配合 做数据分析这些年我最大的感受是很多人学了一堆算法但真到项目里就懵了——不知道先做哪一步也不知道这几个模型之间到底怎么配合。其实关联规则、分类、回归、聚类这四类方法不是孤立的技术点而是可以串成一条完整分析流水线的。今天我就拿一个典型的电商用户分析场景把这套全流程从头到尾捋一遍包括数据怎么准备、每类算法选什么、参数怎么定、结果怎么解读以及那些文档里不会写的坑。1. 全流程设计思路四种算法如何搭配成一套分析闭环1.1 关联规则、聚类、分类、回归各解决什么问题先说清楚这四类算法各自的定位不然你可能会在同一个数据集上把它们用混。关联规则解决的是“什么东西经常一起出现”的问题。最经典的场景就是购物篮分析用户买了啤酒是不是大概率也买尿布它输出的是形如A - B的规则附带支持度、置信度、提升度等指标。这个东西的价值在于发现数据里的“共现模式”是一种描述性的分析适合放在流程最前面帮你建立对业务组合关系的直觉。聚类解决的是“这批样本天然分成几堆”的问题。它不需要标签属于无监督学习。比如把用户按行为特征分成几个群组每个群组内部的用户行为高度相似群组之间差异明显。聚类通常用来做用户画像、商品分层、异常检测它和关联规则一样属于探索性分析但关注的点从“共现”变成了“分组”。分类解决的是“这个新样本属于哪个已知类别”的问题。它是监督学习需要提前有标签。比如判断一笔交易是不是欺诈、一封邮件是不是垃圾邮件。在电商场景里可以根据聚类得到的用户分群结果训练一个分类器让新用户一进来就能被自动归入某个群组这就是聚类和分类最常见的配合方式。回归解决的是“这个连续值是多少”的问题。它同样是有监督的但预测的不是类别而是数值。比如预测用户未来30天的消费金额、预测商品的销量、预测库存周转天数。回归模型输出的是一段数值区间或一个点估计可以用来做资源调配、预算规划。把这四件事串起来就是一条从“描述”到“预测”的完整链路先用关联规则和聚类去理解数据里有什么结构再用分类和回归把这种结构变成可自动化的预测能力。1.2 全流程的典型落地场景与算法选型拿电商用户分析举个例子这个例子我会在后面反复用到。假设我们手上有一张用户订单流水表字段包括用户ID、购买时间、购买商品ID、商品类目、订单金额、支付方式、用户注册时长等。我们要做的分析任务包括四个关联规则找出哪些商品类目经常被一起购买用于交叉销售和货架摆放。聚类根据用户的购买频次、客单价、活跃度等行为指标把用户分成高价值、中价值、低价值等几个群。分类基于聚类打好的标签训练一个模型新用户进来后自动判断他属于哪一类用户。回归预测用户未来一段时间的消费金额用于运营预算分配。算法选型上我的习惯是“先简单后复杂”。关联规则基本就是 Apriori 或 FP-Growth数据量不大用 Apriori 就够了聚类先用 K-Means 跑一遍再看数据形态决定要不要上 DBSCAN 或层次聚类分类和回归则是在逻辑回归/线性回归这类可解释模型和随机森林/XGBoost 这类高性能模型之间做权衡。可解释性要求高的场景比如风控优先逻辑回归和决策树追求精度的场景比如销量预测直接上 XGBoost。这套选型思路的好处是每一步都有清晰的产出且前一步的产出可以直接作为后一步的输入。聚类结果变成分类标签分类概率可以作为回归模型的特征关联规则发现的组合关系也可以作为特征工程的一部分。整个流程跑下来数据被反复利用分析深度是单模型无法比的。2. 数据准备建模前必须处理的四件事2.1 数据清洗与缺失值处理不管你用什么高级算法数据不干净结果全是扯淡。我在实际项目中第一步永远是做数据体检主要看这几项缺失值占比对每个字段统计缺失率。缺失率超过50%的字段除非业务上特别重要否则我一般直接删除缺失率在5%到50%之间的根据字段类型决定填充策略。异常值检测用箱线图或者3倍标准差方法找出极端值。比如订单金额字段出现负值、用户年龄出现200岁这些要单独处理。注意异常值不一定都是错误有时候是真实的高价值用户需要结合业务判断不能一刀切删掉。重复值排查同一个订单ID出现多次可能是数据采集时重复记录要去重。缺失值填充这件事数值型字段我一般用中位数而不是均值。为什么因为均值对异常值敏感一个超大值能把均值拉得很高中位数则稳健得多。类别型字段用众数填充或者单独填一个“未知”类别。还有一个小技巧可以加一列“是否缺失”作为特征有时候缺失本身也是一种信息。2.2 特征工程与数值化处理数据清洗完就要把原始字段变成模型能吃的数值特征。这里有几个高频操作类别特征编码。像商品类目这种字符串字段如果类别数不多比如几十个以内直接用 One-Hot 编码如果类别数非常多比如几千个商品One-Hot 会让特征维度爆炸可以用目标编码Target Encoding或者频次编码。目标编码就是用该类别的目标变量均值替代原始类别但要注意做交叉验证内的编码否则会引入数据泄漏。连续特征标准化。逻辑回归、K-Means 这些基于距离或梯度的算法对特征的尺度非常敏感。比如“消费金额”的取值范围是几十到几万“购买频次”的取值范围是1到20如果直接丢进 K-Means距离计算会被金额字段完全主导。所以要做标准化常见的是 Z-Score 标准化减去均值除以标准差或 Min-Max 归一化缩放到0到1之间。树模型随机森林、XGBoost不受尺度影响可以不做。连续特征分箱。有时候把连续值变成离散的分箱值反而更有效。比如把“用户注册时长”分成“新用户30天”“成长期30-90天”“成熟期90天”这样既降低了异常值的影响又让特征具有业务含义。分箱后可以做 One-Hot也可以直接用分箱序号。特征衍生。这是最能体现功力的部分。比如从订单时间中提取“是否周末”“是否夜间下单”从商品信息中提取“客单价”从用户历史行为中聚合出“30天购买次数”“平均购买间隔”。好的特征工程往往比选什么模型更重要。2.3 数据集划分与防数据泄漏数据准备好了接下来要划分训练集和测试集。大多数场景直接用train_test_split按 7:3 或 8:2 划分就行但有两个细节要注意。一是时间序列数据不能随机打乱划分。比如预测未来30天销量如果你随机抽样训练集里混入了未来数据模型会“偷看”答案上线后表现崩盘。时间序列必须按时间先后划分用前70%的时间段训练后30%的时间段验证。二是预处理必须在训练集上拟合再应用到测试集。比如计算均值、标准差做标准化这个均值和标准差只能用训练集的数据计算然后把同样的参数应用在测试集上。很多新手先对全量数据做标准化再划分数据集这就会造成数据泄漏评估结果虚高。正确的做法是先划分再在训练集上fit在训练集和测试集上分别transform。我在实际项目里踩过这个坑当时用全量数据标准化后模型在测试集上 AUC 有0.95上线后实际效果只有0.8不到后来排查才发现是数据泄漏。从那以后我所有预处理都严格放进 Pipeline 里跟着交叉验证一起跑避免手工操作带来的泄漏风险。3. 关联规则挖掘先发现业务中的“共现关系”3.1 Apriori 算法原理与支持度、置信度、提升度关联规则这部分虽然工具调用很简单但背后的三个指标必须理解透否则你根本不知道怎么设置阈值。支持度Support表示某个项集在全部订单中出现的概率。支持度(A) 包含A的订单数 / 总订单数。支持度用来衡量规则的普遍性太低的规则没有商业意义。置信度Confidence表示在包含A的订单中同时包含B的概率。置信度(A-B) 支持度(A∪B) / 支持度(A)。置信度衡量的是规则的可靠性越高说明A出现时B很可能也出现。提升度Lift表示“包含A时B出现的概率”与“B整体出现概率”的比值。提升度(A-B) 置信度(A-B) / 支持度(B)。提升度大于1说明A对B有正向促进作用等于1说明A和B相互独立小于1说明A反而抑制B的出现。提升度是判断规则价值最核心的指标很多新手只看置信度结果找出一堆“买了A就买A”的废话规则。Apriori 算法的核心思想是如果一个项集是频繁的那么它的所有子集也是频繁的反之如果一个项集不是频繁的那么它的所有超集也不可能频繁。算法从单个商品开始逐层生成候选项集用最小支持度剪枝最终得到所有频繁项集再从中提取满足最小置信度和提升度的规则。3.2 mlxtend 实现关联规则挖掘的完整代码Python 里最方便的工具是mlxtend.frequent_patterns。先把订单数据转换成“购物篮”格式的矩阵行是订单列是商品类目单元格是0或1。import pandas as pd from mlxtend.frequent_patterns import apriori, association_rules # 原始数据order_id, category df pd.read_csv(orders.csv) print(df.head()) # 转换成购物篮矩阵 basket df.groupby([order_id, category])[category].count() \ .unstack().fillna(0) basket basket.applymap(lambda x: 1 if x 0 else 0) # 挖掘频繁项集最小支持度设为0.02 frequent_itemsets apriori(basket, min_support0.02, use_colnamesTrue) frequent_itemsets[itemset_len] frequent_itemsets[itemsets].apply(len) print(frequent_itemsets.sort_values(support, ascendingFalse).head(10)) # 提取关联规则最小置信度0.3最小提升度1.1 rules association_rules(frequent_itemsets, metricconfidence, min_threshold0.3) rules rules[(rules[lift] 1.1) (rules[confidence] 0.3)] rules rules.sort_values(lift, ascendingFalse) print(rules[[antecedents, consequents, support, confidence, lift]].head(20))这段代码跑完之后你会看到一个规则表。比如(婴儿奶粉) - (纸尿裤)支持度0.03置信度0.42提升度2.3。说明买了婴儿奶粉的订单里有42%会同时买纸尿裤而纸尿裤在全部订单中的占比只有18%提升度2.3意味着奶粉对纸尿裤的带动作用非常明显。3.3 最小阈值设置与结果解读阈值怎么设没有标准答案取决于你的数据量级和业务目标。我一般这么操作先设一个比较低的min_support比如0.01看生成的规则总量然后根据“规则数量不能太多也不能太少”的原则调整。如果规则量在几千条以上就调高支持度如果只有几十条就调低支持度。置信度我习惯设在0.3到0.5之间提升度一定要大于1.1才会留下来看。这里还有一个容易被忽视的问题支持度高的规则不一定有价值。比如“手机 - 手机壳”这种规则支持度可能很高但谁都知道价值有限。真正有价值的是那些提升度高、业务上又说得通的规则比如“露营帐篷 - 便携气罐”这类规则才是交叉销售的机会点。另外关联规则分析的结果要结合业务验证。我遇到过一条规则“口红 - 卸妆水”提升度很高但后来业务同事说这两个商品本来就经常以套装形式售卖属于捆绑销售不是用户自发关联。所以关联规则是“发现线索”不是“证明因果”最终判断还是要靠业务经验。4. 分类模型判断样本属于哪一类4.1 常见分类器对比逻辑回归、决策树、随机森林、XGBoost分类型任务里我常用的四个模型各有脾气。逻辑回归是最经典的线性分类器虽然名字里带“回归”但它做的是分类。它输出的是一个概率值通过 Sigmoid 函数把线性组合的结果映射到0到1之间。好处是可解释性极强每个特征的系数直接告诉你“这个特征每增加一个单位风险概率提升多少”。坏处是只能捕捉线性关系特征交互需要手动构造。决策树则是用一系列“if-then”规则对样本进行划分。它的优点是天然处理非线性关系可解释性也不错能画出一棵直观的树。缺点是容易过拟合单棵树的泛化能力通常不够。随机森林是对决策树的集成通过 Bootstrap 抽样训练多棵树再对结果投票或取平均。它显著降低了单棵树的过拟合风险是“默认先跑一个”的好选择。缺点是模型容量大解释性下降。XGBoost 是梯度提升树的代表通过不断训练“残差的残差”来逼近真实值。它在结构化数据上的精度通常是最高的训练速度快还自带正则化防止过拟合。缺点是超参数多调参有门槛而且如果你追求极致解释性用它就不太合适。这四者的选择逻辑很简单业务要求解释清楚用逻辑回归或决策树只求精度用 XGBoost想快速拿到一个还不错的基线用随机森林。4.2 分类模型评估准确率、精确率、召回率与AUC模型训完怎么判断好坏这是很多人的知识盲区。我见过有人直接用 accuracy 评估所有分类任务这在样本不均衡时是致命的。先说混淆矩阵它把预测结果分成四类真正例TP、假正例FP、真负例TN、假负例FN。基于这四个数可以算出一堆指标准确率Accuracy(TPTN) / (TPFPFNTN)所有样本中预测正确的比例。样本均衡时可以用不均衡时参考价值很低。精确率PrecisionTP / (TPFP)预测为正类的样本中有多少是真的正类。它关注的是“预测准不准”适用于垃圾邮件识别这种“误报代价高”的场景。召回率RecallTP / (TPFN)真实正类中有多少被找出来了。它关注的是“漏报多不多”适用于疾病筛查这种“漏掉一个代价高”的场景。F1 Score精确率和召回率的调和平均2*P*R / (PR)是两者的综合指标。AUC 则是另一个维度它衡量的是模型把正样本排在负样本前面的能力数值越大越好范围在0.5到1之间。AUC 的一个好处是它不依赖具体的分类阈值适合评估模型整体的排序能力。我之前做过一个用户流失预警项目流失用户只占5%。如果只看准确率一个“永远预测不流失”的模型也能拿到95%的准确率但显然毫无用处。后来我用召回率和AUC来评估才真正把流失用户找出来。所以你评估分类模型一定要先看正负样本比例再决定用哪些指标。4.3 Python 实现分类建模与调参分类建模这步我会用 scikit-learn 先搭一个基线再用 XGBoost 做精度提升。假设数据集是user_features.csv标签列是user_group用随机森林做基线import pandas as pd from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report, roc_auc_score from sklearn.preprocessing import StandardScaler df pd.read_csv(user_features.csv) X df.drop(user_group, axis1) y df[user_group] # 划分数据集 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) # 随机森林基线模型 rf RandomForestClassifier(n_estimators300, max_depth8, random_state42) rf.fit(X_train, y_train) y_pred rf.predict(X_test) y_prob rf.predict_proba(X_test)[:, 1] print(classification_report(y_test, y_pred)) print(AUC:, roc_auc_score(y_test, y_prob))stratifyy这个参数很重要它保证划分后训练集和测试集里各类别比例和原始数据一致防止因为随机划分导致某些小类别在训练集里消失。跑完基线后我会再上 XGBoost 调一轮。XGBoost 有几组关键参数eta学习率一般设0.01到0.1之间越小越稳但越慢、max_depth树深默认6数据量不大时3到6就够、subsample和colsample_bytree行采样和列采样防止过拟合。我习惯先固定eta0.05然后用网格搜索调max_depth和min_child_weight确定树的复杂度再调subsample。import xgboost as xgb from sklearn.model_selection import GridSearchCV xgb_model xgb.XGBClassifier( learning_rate0.05, n_estimators500, random_state42 ) params { max_depth: [3, 5, 7], min_child_weight: [1, 3, 5], subsample: [0.7, 0.8, 0.9] } grid GridSearchCV( xgb_model, params, cv5, scoringroc_auc, n_jobs-1 ) grid.fit(X_train, y_train) print(best params:, grid.best_params_) print(best AUC:, grid.best_score_)调参有一个我屡试不爽的经验优先调max_depth和min_child_weight这两个决定了模型的复杂度确定之后再调subsample和colsample_bytree最后如果时间充裕可以把eta降到0.01并等比例增加n_estimators通常还能再涨一小截精度。5. 回归模型预测连续数值5.1 回归算法家族线性回归、岭回归、树模型回归回归任务和分类任务最大的区别在于目标变量是连续值。在电商场景里我们经常要预测“未来30天消费金额”“商品日销量”这类数值。回归算法里我也按从简单到复杂的顺序来说。线性回归是最基础的方法假设目标值和特征之间是线性关系。模型简单、解释性强但要求数据基本满足线性假设且对异常值非常敏感。实际业务数据很少是纯线性关系所以线性回归通常是作为基线出现。岭回归是线性回归的改进版在损失函数中加入 L2 正则化项惩罚过大的系数。这样做的效果是当特征之间存在多重共线性或者特征数多于样本数时岭回归依然能得到稳定的解。它的超参数alpha控制正则化强度值越大系数被压缩得越厉害。决策树回归和随机森林回归原理与分类时类似区别在于叶节点的输出是落入该节点的样本均值而不是类别。树模型能够捕捉特征之间的非线性交互对异常值也相对鲁棒。随机森林回归通过多棵树平均来降低方差是回归任务里非常稳的选择。XGBoost 回归则是目前结构化数据回归任务的“精度天花板”之一。它通过加法模型迭代优化目标函数每一轮学习的是之前所有树的残差。与分类任务一样它也支持 L1/L2 正则化抗过拟合能力强。5.2 回归评估指标RMSE、MAE、R² 怎么解读回归模型的评估核心是看“预测值和真实值的差距有多大”。指标不同关注的误差类型也不同。MAE平均绝对误差是|预测值 - 真实值|的平均值。它的解释最直观“平均差多少钱”。但它对大误差不敏感因为用的是绝对值。RMSE均方根误差是(预测值 - 真实值)^2平均后开根号。由于误差被平方了所以大误差会被放大。如果你特别不能容忍“偶尔预测得离谱”那就用 RMSE 作为主要指标。但 RMSE 对异常值很敏感一个离群点就可能让它暴涨。R²决定系数则是“模型解释了目标变量多少方差”。取值范围小于等于1数值越接近1说明模型拟合越好。R² 0.8可以理解为模型解释了80%的变异。但要注意R² 会随着特征数量增加而上升所以比较不同特征数量的模型时要看调整后的 R²Adjusted R²。不同业务场景要选不同侧重点。比如预测库存需求RMSE 更重要因为少量高估影响不大但低估会造成断货预测用户消费金额MAE 更重要因为你要做预算分配不允许某些用户被严重高估。5.3 XGBoost 回归实战与特征重要度分析XGBoost 回归的代码和分类非常相似只是目标函数和评估指标不同。还是用电商用户数据目标列是amount_30d未来30天消费金额import xgboost as xgb from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np X df.drop([amount_30d, user_id], axis1) y df[amount_30d] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42 ) model xgb.XGBRegressor( learning_rate0.05, max_depth5, subsample0.8, colsample_bytree0.8, n_estimators800, random_state42 ) model.fit(X_train, y_train) y_pred model.predict(X_test) print(MAE:, mean_absolute_error(y_test, y_pred)) print(RMSE:, np.sqrt(mean_squared_error(y_test, y_pred))) print(R2:, r2_score(y_test, y_pred)) # 特征重要度 importance pd.Series(model.feature_importances_, indexX.columns) print(importance.sort_values(ascendingFalse).head(10))跑完之后我会重点关注两件事。一是 MAE 和 RMSE 的差距如果 RMSE 明显大于 MAE说明预测误差的分布存在长尾可能有个别样本预测得很差要考虑是不是需要单独处理这些样本。二是特征重要度排序。XGBoost 自带的feature_importances_是基于分裂次数和增益的统计它告诉你哪些特征在模型中起了关键作用。如果你发现某个业务上不太合理的特征排名很高比如“用户ID”这种唯一标识字段排第一那极有可能发生了数据泄漏需要回头检查特征工程。特征重要度还能指导运营如果“近30天登录次数”是最重要的特征那运营就该把精力放在提升用户登录频率上而不是盲目发优惠券。6. 聚类分析无监督挖掘数据天然分组6.1 K-Means、层次聚类、DBSCAN 的适用场景聚类是四类方法里“主观性最强”的一块因为它的产出是“把数据分成几堆”但“分成几堆才算合理”没有标准答案。我常用的三种算法各有特点。K-Means 是最主流的原型聚类算法。它的思路是随机初始化 K 个中心点然后把每个样本分配到最近的中心点再重新计算中心点位置迭代直到中心点不再移动。特点是快、简单、适合大数据量。缺点是需要预先指定 K 值而且对初始中心点敏感对球形分布假设较强遇到形状不规则的数据会分得很差。层次聚类比如 AGNES不直接指定 K而是自底向上逐步合并距离最近的类最后生成一棵层次树你可以从树的任意高度“切一刀”得到想要的类别数。它的优点是无需提前设定 K还能通过树状图直观看到聚类过程。缺点是时间复杂度高一般不适合超过几万条的数据。DBSCAN 是基于密度的聚类算法它把数据分成“核心点”“边界点”“噪声点”从核心点出发不断扩展密度相连的样本。它的最大优势是能自动发现任意形状的簇并且在聚类的同时识别异常点。参数上只需要设定eps邻域半径和min_samples核心点的最少邻居数。缺点是eps对结果影响很大且数据量特征维度较高时距离计算会变得不稳定。我的选型经验是先用 K-Means 快速跑一版看结果是否有业务意义如果数据有明显的密度差异或形状不规则再试 DBSCAN如果只是想看看数据怎么分层的用层次聚类画个树状图最直观。6.2 聚类数 K 怎么选肘部法则与轮廓系数K-Means 的第一步是确定 K 值。最常用的是肘部法则把 K 从2开始递增分别计算每个 K 值下的 SSE样本到所属中心点的距离平方和。随着 K 增大SSE 一定下降但下降幅度会越来越小。SSE 下降速率剧变的那个点就是“肘部”对应的 K 就是最佳聚类数。轮廓系数是另一个常用指标取值范围从-1到1。某个样本的轮廓系数越接近1说明它离自己所在的簇越近、离其他簇越远。整体轮廓系数是所有样本的平均值选 K 时可以让 K 在2到10之间扫一遍取轮廓系数最大的 K。不过轮廓系数喜欢紧凑、分离的簇在真实数据里往往和业务判断有出入。我自己在项目里从来不是单纯看指标选 K而是把指标和业务诉求结合。比如用户分群业务上希望得到3到5个可以差异化运营的群组如果肘部法则给出 K4轮廓系数在 K4 也确实不错那就选4。如果指标和业务冲突我会优先考虑业务因为聚类的终极目标是可落地不是数学最优。还有一个细节做 K-Means 之前一定要标准化否则那个取值大的特征会主导距离计算。我在第二节已经提过一次这里再强调一下因为聚类对特征尺度比回归更敏感。6.3 子空间聚类与 Python 聚类完整实现有时候数据维度很高直接对全特征做距离计算结果会被大量无关特征干扰这就是“维度灾难”。子空间聚类就是用来解决这个问题的它不在全特征空间上聚类而是在不同的特征子集上分别聚类或者为不同簇自动选择其最有区分度的特征子集。经典的做法包括基于投影的聚类比如 PROCLUS和基于子空间密度的聚类。在 Python 里实现子空间聚类并不复杂有一种思路是对特征先做分组在每个特征子集上分别跑 K-Means 或 DBSCAN再把聚类结果拼接起来做交叉验证。我见过一个做法是多视图聚类每种特征视图比如行为特征、交易特征、偏好特征各聚一次然后为每个样本综合多个视图的结果得到最终分群。这样做的好处是每个视图的聚类结果都有明确业务含义不会因为把所有特征一锅烩而失去解释性。下面给一个完整的 Python 聚类代码示例覆盖 K-Means、层次聚类和 DBSCAN 三种方法import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering from sklearn.metrics import silhouette_score import matplotlib.pyplot as plt # 数据读入与标准化 df pd.read_csv(user_behavior.csv) features [purchase_freq, avg_order_value, active_days, total_amount] X StandardScaler().fit_transform(df[features]) # 1. 肘部法则找K sse [] for k in range(2, 11): km KMeans(n_clustersk, random_state42, n_init10) km.fit(X) sse.append(km.inertia_) plt.plot(range(2, 11), sse, markero) plt.xlabel(K) plt.ylabel(SSE) plt.show() # 2. 确定K后跑K-Means并输出轮廓系数 best_k 4 km KMeans(n_clustersbest_k, random_state42, n_init10) df[kmeans_label] km.fit_predict(X) print(K-Means silhouette:, silhouette_score(X, df[kmeans_label])) # 3. DBSCAN 聚类 db DBSCAN(eps0.8, min_samples10) df[dbscan_label] db.fit_predict(X) print(DBSCAN number of clusters:, df[dbscan_label].nunique()) # 4. 层次聚类Ward 方法 hier AgglomerativeClustering(n_clustersbest_k, linkageward) df[hier_label] hier.fit_predict(X) # 5. 查看每类用户的特征均值做业务解读 print(df.groupby(kmeans_label)[features].mean())跑完之后最重要的工作不是看图形而是看每个簇的特征均值给每个簇一个业务定义。比如簇0的购买频次和总金额都最高那就是高价值用户簇1的平均订单金额高但活跃天数低可能是“低频大额”用户簇2什么都低就是低价值用户。这一步叫“聚类结果业务化”做得好聚类分析才算真正落地。子空间聚类如果要用现成库可以试试pyclustering里的相关算法或者在 sklearn 基础上自己实现多视图聚类。我给一个简单的多视图思路把特征分成两个视图分别标准化后各跑一次 K-Means然后把两个标签拼接成一个二位数编码当作新的“聚类标签”。这个方法不完全是严格的子空间聚类但在实践中经常能收到不错的效果。7. 全流程常见问题与避坑实录7.1 数据泄漏最常见也最隐蔽的错误全流程跑下来我在项目里遇到最多次的问题不是模型太弱而是数据泄漏。所谓数据泄漏就是模型在训练时“偷看”了测试集的信息。常见的形式有几种对全量数据做标准化或缺失值填充再划分训练测试集。特征里包含了目标变量的信息。比如预测用户未来30天消费金额特征里却放入了“当天消费金额”这个特征本身就是目标的一部分。在特征工程使用了未来信息。比如用整个时间窗口的聚合值作为特征但这个窗口包含了预测期内的数据。交叉验证里预处理拟合在全量数据上。数据泄漏的典型表现是离线指标特别高线上效果断崖式下跌。我现在的做法是所有预处理步骤全部封装在 sklearn Pipeline 里交叉验证用cross_val_score自动在每个折内完成预处理从机制上杜绝泄漏。还有一个容易忽视的点重复样本。如果你的数据里有重复的用户记录同一用户既出现在训练集又出现在测试集模型相当于“背过答案”。应该在建模前检查并去除重复样本或者在划分时按user_id分组。7.2 类别不平衡与过拟合处理分类任务里样本不平衡是家常便饭。处理手段从两个方向发力数据层面和算法层面。数据层面最简单的做法是下采样把多数类样本抽到和少数类一样多或者过采样把少数类复制多份。更高级一点是用 SMOTE 生成合成样本但要注意 SMOTE 可能会生成不真实的样本业务上解释性会变差。算法层面可以在模型里设置类别权重。比如 sklearn 里的RandomForestClassifier(class_weightbalanced)XGBoost 里的scale_pos_weight让模型在训练时对少数类的错误预测给予更大的惩罚。这样比简单改变样本分布更稳。过拟合则是另一个极端模型在训练集上表现完美在测试集上一塌糊涂。我常用的控制手段包括增加正则化参数比如 XGBoost 的reg_lambda、reg_alpha、降低树的深度、增加subsample的随机性、通过早停法early_stopping_rounds在验证集指标不再下降时停止训练。早停法我强烈推荐它几乎是防止梯度提升树过拟合最有效的手段。7.3 参数调优的一点个人经验最后分享几个调参的个人习惯这些都是靠时间堆出来的经验。第一调参要有顺序不要乱试。XGBoost 我先调max_depth和min_child_weight锁定树的形状再调subsample和colsample_bytree控制随机程度接着调gamma增加分裂门槛最后调learning_rate同时等比例增加n_estimators。这样每一轮调参都有明确的业务含义不至于像无头苍蝇。第二网格搜索不要一上来就用很大的范围。先粗调锁定一个区域再细调。比如max_depth我先在 [3, 5, 7] 里试如果5最好就再试 [4, 5, 6]。别一开始就用全部参数组合会浪费大量算力。第三聚类和分类的参数是联动的。K-Means 里选的 K 值会影响后续分类任务的标签分布分类模型表现不好不一定全是分类器的锅也可能是聚类分群本身就不合理。所以全流程调参时要随时回看前一步的产出而不是一味在后一步调模型。第四模板代码能省很多事。我会把自己常用的数据清洗、特征工程、模型训练、评估可视化代码整理成模板函数新项目直接套用把精力花在理解数据和业务上而不是重复写标准代码。这套“关联规则 分类 回归 聚类”的全流程表面上看是四种算法的拼接本质上是一个从探索到预测的完整闭环。数据进来之后先用关联规则和聚类摸清结构再用分类和回归把结构变成可复用的模型能力。每一步的产出都在为下一步服务最终给业务输出一个既有洞察又能预测的分析体系。每次跑完一遍这套流程我都会对数据多一分理解这也是做数据分析最有意思的地方。
返回列表