188 lines
7.5 KiB
Markdown
188 lines
7.5 KiB
Markdown
---
|
|
name: stats_ml
|
|
description: 统计建模与机器学习(sklearn / statsmodels / PyMC 三库合一,场景导航选库)。✅ 触发:配方-性能建模、DoE 响应面、强度预测、特征重要性、假设检验、置信区间、贝叶斯小样本估计、聚类异常实验检测。⛔ 不触发:用户只问描述性统计(均值方差),pandas 一行搞定;深度学习场景(走单独的 torch / lightning skill,本仓库未集成)。
|
|
---
|
|
|
|
# stats_ml
|
|
|
|
服务建材院典型场景:**掺合料配比 → 性能(强度 / 流动度 / 凝结时间)** 的建模与推断。三库分工:
|
|
|
|
| 你要做 | 用 | 一句话理由 |
|
|
|---|---|---|
|
|
| 要 p-value、置信区间、假设检验 | **statsmodels** | OLS / ANOVA / 假设检验是 statsmodels 主场,sklearn 不给 p-value |
|
|
| 要预测精度高,可解释性次要 | **sklearn** | RandomForest / GBDT / XGBoost 是性能预测的现代基线 |
|
|
| 样本 < 30 且要不确定度估计 | **PyMC** | 贝叶斯给出参数后验分布,小样本下比频率派的置信区间更稳 |
|
|
| 要可解释的线性关系 | statsmodels OLS / sklearn LinearRegression | 都可以,统计推断走 statsmodels,纯预测走 sklearn |
|
|
| 要 DoE 响应面拟合 | statsmodels(二次回归 + ANOVA) | 主流做法,系数显著性能直接读 |
|
|
| 要聚类找异常配方 | sklearn (KMeans / DBSCAN) | 标准工具 |
|
|
| 要降维可视化(配方空间) | sklearn (PCA / t-SNE) | 标准工具 |
|
|
|
|
## 何时用 / 何时不用
|
|
|
|
✅ 用:
|
|
- 用户给一张配方-性能表(N 行配方 + 性能列),要建模 / 预测 / 推断
|
|
- 要回答"哪个因素影响最大"(特征重要性 / 系数显著性)
|
|
- 要回答"这个新配方预测强度多少 + 置信区间多大"
|
|
- 要找异常实验点 / 配方聚类
|
|
|
|
⛔ 不用:
|
|
- 用户只要看均值方差直方图 → pandas + matplotlib 直接搞,杀鸡不用牛刀
|
|
- 用户给的"数据"只有 3-5 个点 → 任何 ML / 统计都不可靠,告诉用户先补数据
|
|
- 深度学习需求(CNN / Transformer)→ 不在本 skill 范围
|
|
|
|
## 准备
|
|
|
|
```python
|
|
# 按需 import,不要全 import
|
|
import numpy as np
|
|
import pandas as pd
|
|
|
|
# sklearn
|
|
from sklearn.model_selection import train_test_split, KFold, StratifiedKFold, GridSearchCV
|
|
from sklearn.preprocessing import StandardScaler
|
|
from sklearn.pipeline import Pipeline
|
|
from sklearn.metrics import r2_score, mean_squared_error
|
|
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
|
|
|
|
# statsmodels
|
|
import statsmodels.api as sm
|
|
import statsmodels.formula.api as smf
|
|
|
|
# PyMC(重,按需 import)
|
|
# import pymc as pm
|
|
# import arviz as az
|
|
```
|
|
|
|
## 典型工作流
|
|
|
|
### A. 配方-性能回归(sklearn,要预测精度)
|
|
|
|
```python
|
|
# 数据:每行一个配方,X 是组分比例,y 是 28d 抗压强度
|
|
X = df[["cement", "fly_ash", "slag", "water", "sand", "stone"]].values
|
|
y = df["strength_28d"].values
|
|
|
|
# Pipeline 把预处理和模型绑死 —— 反模式见末尾
|
|
pipe = Pipeline([
|
|
("scaler", StandardScaler()), # 线性 / 距离类模型必须;树模型可省
|
|
("model", RandomForestRegressor(n_estimators=300, random_state=42)),
|
|
])
|
|
|
|
# 数据小(< 200)用 5-fold CV,不要单次 train/test
|
|
from sklearn.model_selection import cross_val_score
|
|
scores = cross_val_score(pipe, X, y, cv=5, scoring="r2")
|
|
print(f"R2 mean={scores.mean():.3f} std={scores.std():.3f}")
|
|
|
|
# 训完看特征重要性
|
|
pipe.fit(X, y)
|
|
imp = pipe.named_steps["model"].feature_importances_
|
|
for name, val in sorted(zip(df.columns, imp), key=lambda t: -t[1]):
|
|
print(f"{name}: {val:.3f}")
|
|
```
|
|
|
|
### B. 显著性分析(statsmodels,要 p-value)
|
|
|
|
```python
|
|
import statsmodels.formula.api as smf
|
|
|
|
# formula API 让模型 spec 看起来跟 R 一样
|
|
model = smf.ols(
|
|
formula="strength_28d ~ cement + fly_ash + slag + water + water:cement", # 含交互
|
|
data=df,
|
|
).fit()
|
|
print(model.summary()) # 系数、std err、t、p>|t|、95% CI 全在这
|
|
|
|
# ANOVA 比较两个嵌套模型
|
|
m1 = smf.ols("strength_28d ~ cement + fly_ash", data=df).fit()
|
|
m2 = smf.ols("strength_28d ~ cement + fly_ash + slag", data=df).fit()
|
|
from statsmodels.stats.anova import anova_lm
|
|
print(anova_lm(m1, m2)) # slag 加进去显著吗
|
|
```
|
|
|
|
### C. DoE 响应面(statsmodels 二次回归)
|
|
|
|
```python
|
|
# 中心复合设计后,做二阶模型
|
|
model = smf.ols(
|
|
formula="strength ~ x1 + x2 + x3 + I(x1**2) + I(x2**2) + I(x3**2) + x1:x2 + x1:x3 + x2:x3",
|
|
data=df,
|
|
).fit()
|
|
print(model.summary())
|
|
# 看哪些二阶项 / 交互项显著,定优化方向
|
|
```
|
|
|
|
### D. 小样本贝叶斯(PyMC,N<30 要不确定度)
|
|
|
|
```python
|
|
import pymc as pm
|
|
import arviz as az
|
|
|
|
with pm.Model() as model:
|
|
# 系数先验:弱信息正态
|
|
intercept = pm.Normal("intercept", mu=0, sigma=10)
|
|
beta = pm.Normal("beta", mu=0, sigma=5, shape=X.shape[1])
|
|
sigma = pm.HalfNormal("sigma", sigma=10)
|
|
|
|
mu = intercept + pm.math.dot(X, beta)
|
|
y_obs = pm.Normal("y_obs", mu=mu, sigma=sigma, observed=y)
|
|
|
|
trace = pm.sample(2000, tune=1000, chains=4, target_accept=0.95)
|
|
|
|
az.summary(trace) # 后验均值 / std / 94% HDI
|
|
az.plot_posterior(trace) # 后验分布图
|
|
```
|
|
|
|
### E. 配方聚类找异常实验(sklearn KMeans / DBSCAN)
|
|
|
|
```python
|
|
from sklearn.cluster import DBSCAN
|
|
from sklearn.preprocessing import StandardScaler
|
|
|
|
Xs = StandardScaler().fit_transform(X)
|
|
labels = DBSCAN(eps=0.5, min_samples=5).fit_predict(Xs)
|
|
# labels == -1 的点 = 离群,可能是录入错或工艺异常,人工核实
|
|
```
|
|
|
|
## 反模式
|
|
|
|
### sklearn
|
|
|
|
1. **预处理在 pipeline 外** —— 交叉验证会数据泄漏(test fold 的统计量被 train 看到)
|
|
2. **scaler 在 test 上 fit** —— 一律 `fit(train)` / `transform(test)`,Pipeline 自动保证
|
|
3. **分类任务忘 stratified split** —— 类别不平衡时 `train_test_split(..., stratify=y)`
|
|
4. **不必要地 scale 树模型** —— RF / GBDT / XGBoost 不受单调变换影响
|
|
5. **忽略 convergence warning** —— LogisticRegression / SVM 不收敛要加 `max_iter` 或 scale 特征
|
|
6. **小数据集还 80/20 切** —— N<200 用 5-fold CV,N<50 用 LOOCV
|
|
|
|
### statsmodels
|
|
|
|
7. **直接读系数不看 condition number** —— `summary()` 末尾的 condition number > 30 = 严重共线性,系数解读无效
|
|
8. **多重比较忘修正** —— 同时检验多个系数显著性时,用 Bonferroni / FDR(`statsmodels.stats.multitest`)
|
|
9. **OLS 残差不检验** —— `model.resid` 不正态 / 异方差时,OLS 推断不可靠,改 robust SE(`fit(cov_type="HC3")`)
|
|
|
|
### PyMC
|
|
|
|
10. **不看 R-hat / ESS** —— `az.summary(trace)` 的 `r_hat` > 1.01 或 `ess_bulk` < 400 = 没收敛,加 tune / 调 target_accept,不能用
|
|
11. **强先验当数据用** —— 先验定太窄会主导后验,先用弱信息先验试
|
|
12. **PyMC 装包巨大** —— 仅小样本需要时才用,大样本(N>500)频率派结果一样可信且快 100 倍
|
|
|
|
### 通用
|
|
|
|
13. **没看数据分布就建模** —— 先 `df.describe()` + `df.hist()` 扫一遍,有 NaN / 量纲极差 / 长尾分布要先处理
|
|
14. **R2 > 0.95 就开香槟** —— 大概率是数据泄漏 / 过拟合 / 训练集等于测试集,先查
|
|
15. **预测新配方不报置信区间** —— 工程决策不能只给点估计,sklearn 用 `RandomForestRegressor` 的 tree-level prediction std,statsmodels / PyMC 直接给 CI / HDI
|
|
16. **数据点不到 10 还硬上 ML** —— 告诉用户先做 DoE 扩样本,再建模
|
|
|
|
## 依赖
|
|
|
|
`requirements.txt` 加:
|
|
```
|
|
scikit-learn>=1.4.0
|
|
statsmodels>=0.14.0
|
|
pymc>=5.10.0 # 重,装包带 pytensor,可选
|
|
arviz>=0.17.0 # PyMC 后验诊断
|
|
```
|
|
|
|
装:`.venv/Scripts/pip install scikit-learn statsmodels`
|
|
PyMC 单独装:`.venv/Scripts/pip install pymc arviz`(确认要做贝叶斯再装,首次装包 5 分钟起)
|