给数据科学家的算法实战手册。聚类 / 关联 / LR / 决策树四个最常用的商业分析算法,基于 2024-2026 GitHub 高 star 真实项目 + 公开 benchmark,每个算法配真实数据集 + 调优代码 + 上线避坑清单。
核心问题 · "客户/商品/店铺自然分成几类?" · 无监督,无标签
| 场景 | 聚类用法 | 真实项目参考 |
|---|---|---|
| 客户分群 | RFM 模型替代品 | pramodkondur/Customer-Segmentation-RFM-CLV |
| 商品聚类 | 电商 SKU 归一 | Shopee / Pinterest 内部实现 |
| 异常检测 | hdbscan -1 标签 = 噪声 | PayPal 反欺诈 |
| 门店分层 | 连锁店 A/B/C 店型识别 | 优衣库 / 星巴克选址 |
| NLP 主题 | 评论/工单主题发现 | BERTopic (★7.8k) |
数据集: 2009-2011 英国在线零售,1M 笔交易,541K 客户。基于 RFM + HDBSCAN 做客户分群。
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
import hdbscan
from umap import UMAP
# 1. 加载 + RFM 构造
df = pd.read_csv("online_retail_II.csv", encoding="latin-1")
df = df[~df["InvoiceNo"].astype(str).str.startswith("C")] # 去掉退货
df = df.dropna(subset=["CustomerID"])
snapshot = df["InvoiceDate"].max() + pd.Timedelta(days=1)
rfm = df.groupby("CustomerID").agg({
"InvoiceDate": lambda x: (snapshot - x.max()).days, # Recency
"InvoiceNo": "nunique", # Frequency
"Quantity": lambda x: (x * df.loc[x.index, "UnitPrice"]).sum() # Monetary
}).rename(columns={"InvoiceDate": "Recency", "InvoiceNo": "Frequency", "Quantity": "Monetary"})
# 2. IQR 过滤异常值 (聚类对极端值敏感)
for col in ["Recency", "Frequency", "Monetary"]:
q1, q3 = rfm[col].quantile([0.05, 0.95])
rfm = rfm[(rfm[col] >= q1) & (rfm[col] <= q3)]
# 3. 标准化 (K-Means/HDBSCAN 必备)
X = StandardScaler().fit_transform(rfm)
# 4. UMAP 降维 (3 维 → 2-3 维)
X_umap = UMAP(n_components=2, n_neighbors=30, random_state=42).fit_transform(X)
# 5. HDBSCAN 聚类
clusterer = hdbscan.HDBSCAN(min_cluster_size=100, min_samples=10)
labels = clusterer.fit_predict(X_umap)
# 6. 评估
print(f"簇数: {len(set(labels)) - (1 if -1 in labels else 0)}")
print(f"噪声比例: {(labels == -1).mean():.2%}")
print(f"Silhouette: {silhouette_score(X_umap, labels):.3f}")
# >0.5 为佳
# 7. 业务解读
rfm["cluster"] = labels
cluster_profile = rfm.groupby("cluster").agg({
"Recency": "mean", "Frequency": "mean", "Monetary": "mean"
}).round(0)
print(cluster_profile)
在 UCI Online Retail II 数据集上的真实 RFM+HDBSCAN 分群结果 (摘自 pramodkondur 项目,1.06x ROI):
| 簇 | Recency (天) | Frequency | Monetary (£) | 占比 | 营销动作 |
|---|---|---|---|---|---|
| 0 高价值 | 14 | 12 | 4,580 | 8% | VIP 专属优惠 + 提前上新 |
| 1 中活跃 | 45 | 5 | 1,200 | 22% | 常规 EDM 推送 |
| 2 低频 | 120 | 2 | 340 | 35% | 召回邮件 + 折扣券 |
| 3 沉睡 | 280 | 1 | 80 | 28% | 放弃,只发系统通知 |
| -1 噪声 | — | — | — | 7% | 人工审核 (可能是羊毛党/异常) |
避坑: K-Means 必须先标准化 + UMAP 降维;HDBSCAN 直接跑高维数据会失败。商业落地后必须做 PSI 监控(每月),保证线上分群稳定。
核心问题 · "A 和 B 经常一起买吗?" · 无监督,找共现规律
| 场景 | 真实案例 | 业务提升 |
|---|---|---|
| 捆绑销售 | 啤酒+尿布 (沃尔玛经典) | 客单价 +15-30% |
| 交叉推荐 | "买了 X 的人也买了 Y" | CTR +20-40% |
| 促销组合 | 设计套餐 / 满减门槛 | 毛利率 +5-10% |
| 商品陈列 | 实体店货架摆放 | 连带率 +8-15% |
| 库存联动 | A 缺货预警 → B 也快缺 | 缺货损失 -20% |
| 算法 | 时间复杂度 | 速度 | GitHub 标杆 |
|---|---|---|---|
| Apriori | O(2ⁿ) 候选 | 慢 | asaini/Apriori (★785) |
| FP-Growth ⭐ | O(n·freq) | 比 Apriori 快 8x | rasbt/mlxtend (★5.1k) |
| ECLAT | O(n·tids) | 密集小 item 时更快 | jeffrichardchemistry/pyECLAT |
| PyAerial (2025) | 神经符号 | 大规模 100-1000x | DiTEC-project/pyaerial (★36) |
关键事实: 对同一支持度/置信度阈值,三算法产出的频繁项集是数学等价,差异主要在性能,非结果差异。PyAerial 是学习型,准确率 = 数据重建精度 + 规则覆盖率。
数据集: Instacart 200万订单 × 134 个商品类别。基于 FP-Growth 找高频捆绑。
import pandas as pd
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import fpgrowth, association_rules
# 1. 加载 + 转 one-hot (稀疏矩阵加速 10x)
orders = pd.read_csv("instacart_order_products__prior.csv")
products = pd.read_csv("instacart_products.csv")
df = orders.merge(products[["product_id", "product_name"]], on="product_id")
transactions = df.groupby("order_id")["product_name"].apply(list).tolist()
te = TransactionEncoder()
oht = te.fit_transform(transactions, sparse=True) # 关键:sparse=True
df_encoded = pd.DataFrame.sparse.from_spmatrix(oht, columns=te.columns_)
# 2. FP-Growth (比 Apriori 快 8 倍)
print("FP-Growth running...")
fi = fpgrowth(df_encoded, min_support=0.02, use_colnames=True)
print(f"频繁项集数: {len(fi)}")
# 3. 关联规则 (三层筛选)
rules = association_rules(fi, metric="lift", min_threshold=1.5)
rules = rules[(rules["confidence"] > 0.5) & (rules["support"] > 0.05)]
# 4. 上线标准: Lift > 3 AND Confidence > 0.5 AND Support > 0.05
high_value = rules[(rules["lift"] > 3) & (rules["confidence"] > 0.5)]
print(f"高价值规则数: {len(high_value)}")
# 5. Top 10 规则
top10 = high_value.sort_values("lift", ascending=False).head(10)
print(top10[["antecedents", "consequents", "support", "confidence", "lift"]])
摘自 AmirhosseinHonardoust/Market-Basket-Analysis 真实运行数据:
| Antecedents | Consequents | Support | Confidence | Lift |
|---|---|---|---|---|
| Keyboard, Laptop Bag, USB-C Hub | Laptop, Mouse | 0.024 | 0.684 | 5.095 |
| Laptop, Mouse | Keyboard | 0.036 | 0.58 | 2.41 |
| Organic Milk, Greek Yogurt | Banana, Avocado | 0.029 | 0.61 | 2.18 |
商业解读: Lift=5.095 意味着买 "Keyboard+Laptop Bag+USB-C Hub" 的客户比随机客户买 "Laptop+Mouse" 的概率高 5 倍。可以直接做成 "办公全套套餐"。
核心问题 · "这个客户会不会违约/流失/购买?" · 有监督,可解释
| 场景 | 真实项目 | 典型 AUC |
|---|---|---|
| 信用评分 (A卡) | ShichenXie/scorecardpy (★801) | 0.78-0.82 |
| 客户流失 (Telco) | Pradnya1208/Telecom-Customer-Churn | 0.83-0.85 |
| 营销响应 (Uplift) | maks-sh/scikit-uplift (★813) | Qini 0.30 |
| 欺诈检测 baseline | georgymh/ml-fraud-detection | AUPRC 0.72 |
| 工业级 Pipeline | itlubber/scorecardpipeline (PMML 导出) | 同上 |
为什么金融场景仍是 LR 黄金标准: 可解释 (p-value/系数) + 合规 (Basel 银监) + 可转 PMML 上线。2024-2025 在 A 卡/B 卡/C 卡仍占 70%+ 生产模型。
| 维度 | 逻辑回归 | XGBoost |
|---|---|---|
| 可解释性 | ⭐⭐⭐⭐⭐ 极强 | ⭐⭐⭐⭐ + SHAP |
| AUC 上限 | 0.78-0.85 | 0.85-0.92 |
| 合规友好 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 特征工程要求 | 高 (WOE 分箱) | 低 (自动) |
| 训练速度 | 极快 | 中 |
| 非线性能 | 弱 (需交叉特征) | 强 |
经验法则: 监管严格场景 (信贷/医保) → LR;追求精度上限 (反欺诈/流失) → XGBoost;折中 → XGBoost + SHAP 解释。
数据集 1: UCI German Credit (1000 笔贷款申请,好坏客户 7:3)
数据集 2: IBM Telco Customer Churn (7043 客户,26.5% 流失率)
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score, roc_curve
import scorecardpy as sc
# ========================================
# 场景 A: 信用评分 (WOE 分箱 + 评分卡)
# ========================================
# 1. 加载 + 切分
dat = sc.germancredit()
train, test = sc.split_df(dat, "creditability", ratio=0.7, seed=42).values()
# 2. IV 筛选 + WOE 分箱 (金融场景标配)
dt_s = sc.var_filter(dat, y="creditability")
bins = sc.woebin(dt_s, y="creditability")
train_woe = sc.woebin_ply(train, bins)
test_woe = sc.woebin_ply(test, bins)
# 3. L1 正则化 LR (防止过拟合 + 自动特征选择)
lr = LogisticRegression(penalty="l1", C=0.5, solver="saga", n_jobs=-1, max_iter=1000)
lr.fit(train_woe.drop("creditability", axis=1), train_woe["creditability"])
# 4. 评估: AUC + KS (银行标准 KS > 0.3 才上线)
y_prob = lr.predict_proba(test_woe.iloc[:, 1:])[:, 1]
auc = roc_auc_score(test_woe["creditability"], y_prob)
fpr, tpr, _ = roc_curve(test_woe["creditability"], y_prob)
ks = max(tpr - fpr)
print(f"AUC: {auc:.3f} | KS: {ks:.3f}")
# 典型输出: AUC 0.78-0.82 | KS 0.40-0.45
# 5. 评分卡导出 (给业务方看)
card = sc.scorecard(bins, lr, train_woe.columns[1:])
score = sc.scorecard_ply(test, card)
print(score.head())
# ========================================
# 场景 B: 流失预测 (LR 不分箱,直接跑)
# ========================================
from sklearn.preprocessing import StandardScaler
telco = pd.read_csv("telco_churn.csv")
telco["Churn"] = (telco["Churn"] == "Yes").astype(int)
# 类别变量 one-hot
telco_encoded = pd.get_dummies(telco.drop("customerID", axis=1), drop_first=True)
X_train, X_test, y_train, y_test = train_test_split(
telco_encoded.drop("Churn", axis=1), telco_encoded["Churn"],
test_size=0.3, random_state=42, stratify=telco_encoded["Churn"]
)
# 标准化
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)
# 不平衡处理 (Telco 流失率 26.5%, 不算极端)
lr2 = LogisticRegression(class_weight="balanced", max_iter=1000, C=0.5)
lr2.fit(X_train_s, y_train)
y_prob2 = lr2.predict_proba(X_test_s)[:, 1]
print(f"Telco AUC: {roc_auc_score(y_test, y_prob2):.3f}")
# 典型: 0.83-0.85
普通响应模型: "谁会转化?" — 但营销只对"被营销打动"的人有效。Uplift 模型回答: "谁会被营销打动?"
from sklift.models import TwoModels
from sklearn.linear_model import LogisticRegression
# 双模型: 一个预测 treatment,一个预测 control
estimator = TwoModels(
estimator_trmnt=LogisticRegression(C=0.5, class_weight="balanced"),
estimator_ctrl=LogisticRegression(C=0.5, class_weight="balanced"),
method="vanilla"
)
estimator.fit(X_train, y_train, treat_train)
# 预测增量: P(转化|营销) - P(转化|不营销)
uplift = estimator.predict(X_test)
# 排序后 Top 20% 通常能捕获 60-80% 增量转化
top20_idx = np.argsort(uplift)[-int(0.2 * len(uplift)):]
print(f"Top 20% 客户数: {len(top20_idx)} | 平均 uplift: {uplift[top20_idx].mean():.3f}")
| 模型 | German Credit AUC | Telco Churn AUC | 信贷合规 |
|---|---|---|---|
| LR (L1 + WOE) | 0.78-0.82 | 0.83-0.85 | ⭐⭐⭐⭐⭐ |
| Random Forest | 0.80-0.85 | 0.84-0.87 | ⭐⭐⭐ |
| XGBoost | 0.85-0.90 | 0.86-0.92 | ⭐⭐ |
| LightGBM | 0.85-0.92 | 0.87-0.92 | ⭐⭐ |
核心问题 · "什么规则决定结果?" · 有监督,冲精度上限
| 算法 | 速度 | 类别特征 | 推荐场景 |
|---|---|---|---|
| XGBoost | ⚡⚡⚡ | 需编码 | 通用首选 · 欺诈/流失/营销 |
| LightGBM | ⚡⚡⚡⚡ | 需编码 | 大数据量 / 工业首选 |
| CatBoost | ⚡⚡ | 原生支持 | 类别特征多 (用户画像) |
GitHub 标杆: catboost/catboost (★8k+ 业内标杆库),2026 仍在 commit。
数据集: 284,807 笔交易,492 笔欺诈 (1:578 极端不平衡)。核心洞察: 欺诈场景不要看 accuracy (99.9% 是假象,全部预测 "正常" 就有 99.83%),要看 AUPRC + Recall。
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import average_precision_score, roc_auc_score
from xgboost import XGBClassifier
import shap
# 1. 加载 + 切分
df = pd.read_csv("creditcard.csv")
X = df.drop(["Class", "Time"], axis=1)
y = df["Class"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
# 2. scale_pos_weight 处理极端不平衡
ratio = (y_train == 0).sum() / (y_train == 1).sum()
print(f"不平衡比: 1:{ratio:.0f}")
# 3. XGBoost (欺诈检测 AUC-ROC 第一)
xgb = XGBClassifier(
n_estimators=300, max_depth=6, learning_rate=0.05,
scale_pos_weight=ratio, # 类别权重 = 反欺诈关键
eval_metric="aucpr", # 用 PR-AUC,不是 ROC-AUC
early_stopping_rounds=20,
use_label_encoder=False, random_state=42
)
xgb.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=100)
# 4. 评估 (不要看 accuracy!)
y_prob = xgb.predict_proba(X_test)[:, 1]
ap = average_precision_score(y_test, y_prob) # PR-AUC
print(f"XGBoost AUPRC: {ap:.3f}") # 典型: 0.83
# 5. SHAP 可解释 (商业落地必备!)
explainer = shap.TreeExplainer(xgb)
shap_values = explainer.shap_values(X_test.iloc[:1000])
shap.summary_plot(shap_values, X_test.iloc[:1000]) # 全局特征重要性
# 典型 Top 3: V14, V17, V12 (PCA 变换特征)
摘自 itsaryanchauhan/credit-card-fraud-detection 真实实验:
| 模型 | ROC-AUC | 排名 |
|---|---|---|
| XGBoost | 0.9771 | 🥇 第一 |
| LightGBM (CV) | 0.9584 | 🥈 生产级 |
| LightGBM | 0.9499 | 🥉 |
| Random Forest | 0.8529 | 第四 |
| CatBoost | 0.8578 | 第五 |
| AdaBoost | 0.8135 | 第六 |
PMC 论文 (2025) 中 CatBoost 在另一组实验 AUPRC=0.9820,XGBoost=0.9783,两者非常接近。结论: 树模型在欺诈检测上远胜 LR (AUPRC 0.72),因为 LR 抓不住非线性特征组合。
树模型 + SHAP 是 2024-2026 商业分析的事实标准。摘自 SamamaKarim092/End-to-End-Explainable-AI 项目:
import shap
# 全局特征重要性
explainer = shap.TreeExplainer(xgb)
shap_values = explainer.shap_values(X_test)
# 1. 蜂群图 - 看整体特征影响
shap.summary_plot(shap_values, X_test, plot_type="dot")
# 2. 条形图 - 看平均重要性
shap.summary_plot(shap_values, X_test, plot_type="bar")
# 3. 单客户解释 - 业务方必看
shap.waterfall_plot(shap.TreeExplainer(xgb).expected_value,
shap_values[0], X_test.iloc[0])
# 4. 依赖图 - 看特征交互
shap.dependence_plot("V14", shap_values, X_test)
import optuna
from sklearn.model_selection import cross_val_score
def objective(trial):
params = {
"n_estimators": trial.suggest_int("n_estimators", 100, 1000),
"max_depth": trial.suggest_int("max_depth", 4, 10),
"learning_rate": trial.suggest_float("learning_rate", 0.01, 0.3, log=True),
"subsample": trial.suggest_float("subsample", 0.6, 1.0),
"colsample_bytree": trial.suggest_float("colsample_bytree", 0.6, 1.0),
"scale_pos_weight": ratio,
}
model = XGBClassifier(**params, eval_metric="aucpr", random_state=42)
return cross_val_score(model, X_train, y_train, cv=5, scoring="average_precision").mean()
study = optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=50, show_progress_bar=True)
print(f"Best AUPRC: {study.best_value:.3f}")
# 典型提升: 0.83 → 0.86 (调参后 +3-5%)
一图速查 · 业务问题对应算法推荐
| 业务问题 | 第一选择 | 第二选择 | 不推荐 |
|---|---|---|---|
| 客户自然分几群 | HDBSCAN | K-Means + UMAP | LR |
| 异常客户 / 风控 | HDBSCAN (-1 噪声) | IsolationForest | K-Means |
| 捆绑销售 / 购物篮 | FP-Growth | Apriori | 任何监督模型 |
| 交叉推荐 | FP-Growth | 协同过滤 | LR |
| 信用评分 | LR + WOE | XGBoost + SHAP | K-Means |
| 客户流失 | XGBoost + SHAP | LR | 聚类 |
| 欺诈检测 | XGBoost + scale_pos_weight | CatBoost | LR (AUPRC 低) |
| 营销响应增量 | LightGBM S-Learner | causallift 双 LR | 普通分类 |
| RFM + CLV | RFM + K-Means + BG/NBD | XGBoost CLV | LR |
| 销量预测 | LightGBM | XGBoost | LR / 聚类 |
聚类找群体、关联找组合、LR 给可解释、树模型冲精度。商业分析 80% 项目是 "树模型 + SHAP" 组合拳;如果合规要求严,退回 "LR + WOE"。无监督的聚类和关联解决 20% 的探索性场景。
| 数据集 | 规模 | 适用算法 | 来源 |
|---|---|---|---|
| UCI Online Retail II | 1M 笔 / 541K 客户 | 聚类 (RFM + HDBSCAN) | archive.ics.uci.edu/ml |
| Instacart Market Basket | 200万订单 / 134 商品 | 关联 (FP-Growth) | kaggle.com/c/instacart-market-basket-analysis |
| UCI German Credit | 1000 笔贷款 | LR (WOE 评分卡) | archive.ics.uci.edu/ml |
| IBM Telco Customer Churn | 7043 客户 | LR + XGBoost (流失) | kaggle.com/blastchar/telco-customer-churn |
| Kaggle Credit Card Fraud | 284,807 交易 (1:578 不平衡) | XGBoost + SHAP | kaggle.com/mlg-ulb/creditcardfraud |
| Criteo Uplift v2.1 | 1398 万条 / 3GB | Uplift (LightGBM S-Learner) | ailab.criteo.com/criteo-uplift-prediction-dataset |
| 算法 | 项目 | Star | 用途 |
|---|---|---|---|
| 聚类 | MaartenGr/BERTopic | ⭐7.8k | NLP 主题聚类一站式 |
| 聚类 | scikit-learn-contrib/hdbscan | ⭐3.1k | 变密度聚类 (风控首选) |
| 聚类 | facebookresearch/faiss | ⭐40k | 工业级向量聚类 |
| 聚类 | rapidsai/cuml | ⭐5.3k | GPU 加速 / 亿级数据 |
| 关联 | rasbt/mlxtend | ⭐5.1k | FP-Growth 工业事实标准 |
| 关联 | asaini/Apriori | ⭐785 | 论文级 + Streamlit |
| 关联 | DiTEC-project/pyaerial | ⭐36 (2025) | 大规模场景新方案 |
| LR | maks-sh/scikit-uplift | ⭐813 | Uplift 营销响应 |
| LR | ShichenXie/scorecardpy | ⭐801 | 银行 A 卡评分 |
| LR | amphibian-dev/toad | ⭐528 | 工业级中文风控 |
| LR | guillermo-navas-palencia/optbinning | ⭐531 | 最优约束分箱 |
| 树模型 | catboost/catboost | ⭐8k+ | 类别特征首选 |
| 树模型 | Fraud-Detection-Handbook | ⭐723 | 反欺诈教科书 |
| 树模型 | ahmedshahriar/Customer-Churn-Prediction | ⭐100+ | Stacking 集成 + Optuna |
最后一句: 算法只是工具,业务理解才是壁垒。这 4 个算法覆盖了商业分析 80% 的场景,剩下的 20% 用深度学习 / 图算法 / 强化学习处理。先跑起来,再迭代,不要追求 "完美方案"。
完 · 2026-08-24 · Chase's Personal Page