本节摘要:MLlib 的算法按执行形态分四类——逐样本预测的线性模型、按特征分裂的树集成、迭代靠近中心的聚类、按用户物品分组的协同过滤。本节各取代表算法做最小可跑示例,从引擎视角讲它们的 Shuffle 形态与并行特征,给出选型对照。
线性模型每轮迭代对每个分区独立算梯度局部和,再一次 Shuffle 归约——梯度向量不大,Shuffle 成本可控。执行形态:迭代次数 × 每轮一次窄依赖流水 + 一次小 Shuffle。
from pyspark.ml.classification import RandomForestClassifier rf = RandomForestClassifier(numTrees=50, maxDepth=8, labelCol="label") model = rf.fit(train_df) pred = model.transform(test_df) # 逐样本打分:纯窄依赖,无 Shuffle,可无限并行
树集成是"宽一行"的反例:单棵树逐层分裂、层内要找最优切分点,涉及按特征分箱统计的聚合。好在各棵树之间彼此独立——引擎把树间并行吃满,单树内的层间同步由库内部处理。
KMeans 每轮把每个点归到最近中心(窄依赖),再把各分区的类内求和归约(一次 Shuffle)算新中心。中心数多、特征维数高时,这个 Shuffle 是性能瓶颈所在。
from pyspark.ml.clustering import KMeans km = KMeans(k=8, seed=7, featuresCol="features") centers = km.fit(vec_df).clusterCenters() # 每轮迭代中心点向真实位置收敛一步
ALS 把评分表按用户列和物品列交替求解最小二乘,每轮交替各触发一次按用户、按物品的分组聚合——两次 Shuffle。评分数据倾斜(热门物品、重度用户)时,按第 2 章的倾斜手法处理。
from pyspark.ml.recommendation import ALS als = ALS(userCol="user", itemCol="item", ratingCol="rating", rank=16, coldStartStrategy="drop") rec_model = als.fit(ratings) user_top = rec_model.recommendForAllUsers(10) # 每用户取前 10 推荐
| 类别 | 代表 | 每轮 Shuffle | 并行主体 | 调优焦点 |
|---|---|---|---|---|
| 分类回归 | 逻辑回归、随机森林 | 小向量归约 | 样本级 | 迭代数、正则 |
| 聚类 | KMeans | 中心聚合 | 点级 | k 值、初始中心 |
| 协同过滤 | ALS | 用户与物品两次分组 | 用户物品对 | 秩、倾斜 |
| 频繁模式 | FP-Growth | 事务聚合 | 事务级 | 支持度阈值 |
💡 关键直觉:选算法先看数据形态再看精度。亿级样本逐条打分选线性模型或树集成(预测路径零 Shuffle);交互数据选 ALS;无标签探索选聚类。分布式场景下,"每条记录的执行代价"比单机基准分数更能预测线上体验。
背景:内容平台要做"千人千面"首页推荐,评分行为两亿条,团队最初选 KMeans 先给内容聚成 40 簇再按簇推送。操作一:KMeans 跑在 400 万条内容向量上,k=40、维 128。结果:每轮中心聚合的 Shuffle 量等于"分区内每簇向量和"的 128 维 × 40 簇 × 分区数,迭代 20 轮耗时 48 分钟;更糟的是业务效果——同簇推送同质化,点击率一周内下滑。操作二:换 ALS 直接吃用户—内容交互。结果:训练 35 分钟(两次分组 Shuffle 交替,配合对热门内容按第 2 章倾斜手法加盐),离线召回命中率提升两成。解读:换型的真正依据不是精度榜单而是数据形态——有显式或隐式交互就该让模型直接学交互结构,聚类只在"冷内容无行为"时补位。变式:内容侧新入库无行为的条目,用 KMeans 按内容向量聚簇找相似邻居做冷启动兜底,两套模型各就其位——执行形态知识在这里直接变成了架构决策。
# 冷启动兜底:无行为内容按向量近邻找相似内容借推荐 from pyspark.ml.feature import VectorAssembler from pyspark.sql import functions as F nearest = (spark.sql(""" SELECT c.content_id, s.sim_id, s.cosine AS sim FROM content_vec c JOIN LATERAL ( SELECT content_id AS sim_id, sum(x*y) AS cosine -- 向量点积近似近邻 FROM content_vec ) s ON true ORDER BY sim DESC LIMIT 20""")) # ALS 主链路 + 近邻兜底,两段在调度上互不干扰
k 的选法本节只给工程判据:先用采样数据跑肘部法粗定区间,再拿线上真实分布验证稳定性。Shuffle 成本可以按公式心算——每轮每分区传出 k 个"簇内和向量",总量约等于分区数 × k × 维数 × 8 字节,迭代前先算这一笔,超预算就先降维或减 k,别等作业跑一半才 OOM。
树的成本主要在深度而不是棵数——各棵树互不依赖,引擎会把树间并行吃满,50 棵浅树的训练常常比 1 棵深树还快,预测路径更是零 Shuffle 的窄依赖。真正的慢点通常在特征分箱统计的聚合上,减 maxBins 比减树数见效更快。