news 2026/10/12 14:49:06

数据挖掘十大算法Python源代码:复现、调参与实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数据挖掘十大算法Python源代码:复现、调参与实战

简介:十大经典算法的Python实现,被浓缩为15个轻量文件。这份源码包面向数据挖掘初学者与进阶开发者,覆盖Apriori、C4.5、CART、EM、K-means、KNN、PageRank等核心算法,便于对照算法原理快速上手。压缩包容量仅14KB,内含7个.py脚本、4个xml配置、2个testset测试数据及md说明文档,可直接运行并观察输出结果。目前已有1149人学习,是轻量但完整的算法练习包。通过阅读源码并结合测试集,可清晰理解频繁项集挖掘、决策树分裂、聚类迭代、图排序等关键步骤;每个脚本结构独立,适合按需摘取、二次改造或嵌入自身数据挖掘流程,对掌握Python实现细节和调参思路很有帮助。

1. 数据挖掘十大算法源代码(Python)讲的是什么:一套能复现、能改、能答辩的经典实现

数据挖掘十大算法源代码(Python)这个标题,对应的是数据挖掘领域最经典的一套入门全家桶:2006 年 ICDM 评选出的十个算法,覆盖分类、聚类、关联规则、图算法和集成学习。常见面试场合,算法工程师会被要求不仅能说出这些算法的名字,还能当场写出能跑的 Python 实现。这篇文章把这十个算法按用途分组,给出手写核心逻辑和 scikit-learn 组合写法,并记录了我复现过程中踩过的大部分坑。适合准备面试的算法工程师、开题阶段的研究生,以及想在公司内部快速搭一个基线模型做验证的从业者。照着复制就能跑,读完还能知道每个参数在控制什么。

2. 把十大算法在本地跑通:环境准备与十个脚本的统一骨架

2.1 先用 pip 把依赖装齐:numpy、pandas、scikit-learn 一个都不能少

我的习惯是先用虚拟环境把项目隔离起来,避免把系统的 Python 弄乱,尤其是机器上还跑着别的深度学习框架时。python 安装教程里最容易被忽略的一步是 pip 源切换,不换源的话在国内网络环境下装 scikit-learn 能等上好几分钟,还经常超时。下面是完整的环境初始化命令:

python -m venv dm_env source dm_env/bin/activate pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy pandas scikit-learn matplotlib

说明:python -m venv dm_env创建名为 dm_env 的虚拟环境,Windows 下激活命令是dm_env\Scripts\activate,Linux 和 macOS 用source dm_env/bin/activate。-i参数指定清华源,只影响下载速度,不影响代码运行结果。numpy 提供数组运算,pandas 负责读表和清洗,scikit-learn 提供 SVM、KNN、决策树、AdaBoost、高斯混合模型这些成熟实现,matplotlib 在最后画聚类散点图和收敛曲线用。

装完先验证版本,确认环境没问题再往下走:

python -c "import numpy, pandas, sklearn; print(numpy.__version__, pandas.__version__, sklearn.__version__)"

能把三个版本号打出来,就说明环境这一步过关了。常见的翻车点不是算法本身,而是 pip 版本太旧导致装包失败,执行pip install --upgrade pip能解决九成安装问题。另外不要图省事把依赖装到系统 Python 里,后面你换项目、换 Python 小版本时,会有数不清的隐藏冲突。

2.2 十个脚本怎么组织:输入数据、模型逻辑和评估指标分开

十大算法里五个是分类,两个是聚类,一个是关联规则,一个是图算法,一个是集成学习。如果全部堆在一个文件里,调试时找函数都是一场灾难。我采用下面这种目录结构,每个算法独立成文件,评估入口单独放:

dm-algorithms/ ├── data/ # 存放数据集 │ ├── iris.csv │ └── market_basket.csv ├── algorithms/ │ ├── c45.py │ ├── cart.py │ ├── svm.py │ ├── knn.py │ ├── naive_bayes.py │ ├── kmeans.py │ ├── em.py │ ├── apriori.py │ ├── pagerank.py │ └── adaboost.py ├── evaluate.py # 统一评估入口 └── README.md

这个结构的第一个好处是出问题时不用翻整个项目,哪个算法报错就改哪个文件;第二个好处是面试或答辩时你可以顺着文件名逐个讲,逻辑非常清晰。评估指标统一放在 evaluate.py 里:分类算法看准确率、精确率和召回率,聚类看轮廓系数,关联规则看支持度和置信度,PageRank 看迭代收敛曲线。数据集默认用鸢尾花 iris,只有 150 条样本、4 个特征、3 个类别,除了 Apriori 要换成购物篮数据,其他九个算法可以直接复用。

下面这张表是我把十个算法分好组的对照表,后面几章就按这个分组展开:

算法类型核心实现本文对应章节
C4.5分类决策树手写信息增益比 + sklearn 决策树3.1
CART分类/回归树sklearn DecisionTreeRegressor3.2
SVM分类/回归sklearn SVC + 标准化管道3.3
KNN分类sklearn KNeighborsClassifier3.4
Naive Bayes分类sklearn GaussianNB3.4
K-Means聚类手写 numpy 实现4.1
Apriori关联规则手写频繁项集扫描4.2
EM聚类sklearn GaussianMixture4.3
PageRank图算法手写迭代求解4.4
AdaBoost集成学习sklearn AdaBoostClassifier4.4

最后再强调一点:所有分类算法都暴露fit(X_train, y_train)和predict(X_test)两个方法,这个约定让 evaluate.py 能写出非常短且通用的一键验证脚本。后面章节的所有实现都服从这个接口。

3. 分类与回归家族:C4.5、CART、SVM、KNN、朴素贝叶斯的 Python 实现

3.1 C4.5 核心是信息增益比:手写分裂点选择

C4.5 和 ID3 的最大区别是用信息增益比代替信息增益。ID3 用信息增益选特征时,天然偏爱取值很多的属性,“客户ID”这种每个值只有一个样本的特征会拿到最大增益,但完全没有泛化能力。C4.5 把增益除以分裂信息做惩罚,照顾了这类情况。手写核心只需要三步:算熵、算条件熵、算增益比。

import numpy as np def entropy(y): _, counts = np.unique(y, return_counts=True) probs = counts / counts.sum() return -np.sum(probs * np.log2(probs)) def info_gain_ratio(X_feature, y): base_entropy = entropy(y) values, counts = np.unique(X_feature, return_counts=True) total = counts.sum() weighted_entropy = 0.0 split_info = 0.0 for v, cnt in zip(values, counts): subset = y[X_feature == v] weighted_entropy += (cnt / total) * entropy(subset) if cnt > 0: split_info += - (cnt / total) * np.log2(cnt / total) gain = base_entropy - weighted_entropy # split_info 为 0 说明该特征只有一个取值,没有分裂价值 return gain / split_info if split_info > 0 else 0.0 def best_split(X, y): best_gain = 0.0 best_feature = None for i in range(X.shape[1]): gain = info_gain_ratio(X[:, i], y) if gain > best_gain: best_gain = gain best_feature = i return best_feature, best_gain

逻辑说明:entropy用类别频率算香农熵;info_gain_ratio先按特征取值把数据集切块,算加权熵,再用分裂信息归一化;best_split遍历所有特征,选出增益比最大的那个。这是决策树生长最耗时的部分,也是面试官最喜欢追问的部分。

后面接完整的 sklearn 决策树时,只需把数据喂给DecisionTreeClassifier(criterion="entropy")。criterion可以选 "entropy" 或 "gini",C4.5 风格对应前者,CART 默认用 gini。max_depth默认 None 会让树长到所有叶子纯净为止,实战里限制到 5~8 层泛化更好;min_samples_split默认 2,数据噪声大时调到 5 或 10。需要说明的是 sklearn 没有直接提供 C4.5 实现,所以手写核心、用库跑全流程是业界最常见的做法。

3.2 CART 回归与剪枝:用决策树做房价预测的参考代码

CART 和 C4.5 最大的不同是它生成严格的二叉树,每个节点只做一次“特征 <= 阈值”的二分,既能分类又能回归。GDP 预测、量化策略里的价格序列预测这类任务,CART 回归是最常用的基线之一。这里直接用 sklearn 的DecisionTreeRegressor,重点看剪枝参数怎么设。

from sklearn.tree import DecisionTreeRegressor from sklearn.model_selection import train_test_split import pandas as pd df = pd.read_csv("data/house_sales.csv") X = df[["sqft_living", "bedrooms", "bathrooms", "floors"]] y = df["price"] # random_state 固定,结果才可复现 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) model = DecisionTreeRegressor(max_depth=5, min_samples_leaf=10, random_state=42) model.fit(X_train, y_train) print("R^2:", model.score(X_test, y_test))

逻辑说明:max_depth限制树的高度,min_samples_leaf要求叶子节点至少 10 个样本,这两者合起来相当于做了后剪枝。如果不设限制,CART 会把训练集切到每个叶子只有一个样本,训练集表现近乎满分,测试集一塌糊涂,这是决策树最常见的翻车场景。

参数说明:max_depth从 3 开始往上加,每加一层看测试集 R^2 的变化,涨不动就停。min_samples_leaf官方默认是 1,回归任务建议设成样本总数的 1% 左右。判断是否过拟合,直接比较训练集和测试集 R^2 的差值,差值超过 0.1 就该加大min_samples_leaf或减小max_depth。另外,random_state=42这种写法不是玄学,它保证你反复运行得到同一棵结构相同的树,方便和同事对齐结果。

3.3 SVM 的核函数不是玄学:RBF 的两个参数到底在干什么

SVM 在分类任务里出场率极高,但我见过太多实现失败案例,原因不是算法复杂度,而是忘了特征标准化。SVM 的距离计算高度依赖特征尺度,一个人的身高和体重数值范围不一致时,距离会被大数值的分量主导,模型等于只看到了体重。所以正确姿势是把StandardScaler和SVC一起放进管道。

from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline X = [[170, 70], [160, 50], [180, 80], [155, 45]] y = [0, 1, 0, 1] # 示意标签,实际请替换成真实数据 model = make_pipeline(StandardScaler(), SVC(C=1.0, gamma="scale", kernel="rbf", random_state=42)) model.fit(X, y)

逻辑说明:make_pipeline会保证 fit 时先标准化再训练,predict 时对测试数据也做同样的标准化,避免你忘了在预测前再次处理。kernel="rbf"是默认核函数,适合特征和标签呈非线性关系的场景。

参数说明:C是误分类惩罚系数,C 越大,模型对错分样本的容忍度越低,决策边界越复杂,容易过拟合;C 越小,边界越平滑,但可能欠拟合。gamma默认 "scale",表示按特征数量自动计算为1 / (n_features * X.var());如果用固定值如gamma=0.1,值越小每个样本的影响范围越大、边界越平滑,值越大边界越弯曲。调参顺序建议固定 gamma,先把 C 从 0.1 到 100 按对数网格扫一遍,再回头微调 gamma。很多人把 SVM 当作黑匣子,其实这两个参数的含义就完全解释了它在做什么。

3.4 KNN 和朴素贝叶斯:两个最“懒”却完全不同的模型

KNN 是实例型学习,训练阶段不学任何参数,只是把样本存下来,预测时逐条算距离;朴素贝叶斯走概率路线,假设特征间相互独立,用贝叶斯公式算后验概率。两个模型都适合小样本冷启动,但在高维稀疏特征上表现迥异:KNN 超过几十维后距离度量基本失效,而朴素贝叶斯在文本分类里依然是强基线。这是选型时最该记住的边界。

from sklearn.neighbors import KNeighborsClassifier from sklearn.naive_bayes import GaussianNB from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split X, y = load_iris(return_X_y=True) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=7) # KNN: n_neighbors 是最核心参数 knn = KNeighborsClassifier(n_neighbors=5, weights="distance", p=2) knn.fit(X_train, y_train) print("KNN acc:", knn.score(X_test, y_test)) # 高斯朴素贝叶斯:适合连续特征 nb = GaussianNB() nb.fit(X_train, y_train) print("NB acc:", nb.score(X_test, y_test))

逻辑说明:KNN 的n_neighbors=5表示用 5 个最近邻居投票决定分类,weights="distance"表示按距离倒数加权,避免大类别样本淹没少数类别。p=2是欧氏距离,p=1是曼哈顿距离。高斯朴素贝叶斯假设每个特征服从高斯分布,所以直接适配 iris 这类连续数值特征;如果换成文本 TF-IDF 特征,需要改用MultinomialNB。

参数说明:n_neighbors选奇数是为了避免平票,iris 这种干净数据集上 5 到 15 差异不大,真实噪声数据里 K 值要结合交叉验证调。朴素贝叶斯几乎没有可调参数,它更依赖“特征独立”这个假设,业务特征之间强相关时会系统性偏差,这也决定了它适合做基线而不是最终模型。

4. 聚类、关联规则与图算法:K-Means、Apriori、EM、PageRank、AdaBoost 的实现要点

4.1 手写 K-Means:从初始化到收敛的三十行代码

K-Means 流程一句话就能说清:随机选 K 个中心,交替做“分配样本到最近中心”和“重算中心”,直到中心不再移动。手写一遍能让你真正理解为什么初始化和 K 的选择那么关键。

import numpy as np def kmeans(X, k, max_iter=100, tol=1e-4): # 随机选 k 个样本作为初始中心 centers = X[np.random.choice(len(X), k, replace=False)] for _ in range(max_iter): # 分配:每个样本归到距离最近的中心 dists = np.linalg.norm(X[:, None, :] - centers[None, :, :], axis=2) labels = np.argmin(dists, axis=1) # 更新:按簇均值重算中心,空簇保留旧中心 new_centers = np.zeros_like(centers) for j in range(k): if np.any(labels == j): new_centers[j] = X[labels == j].mean(axis=0) else: new_centers[j] = centers[j] if np.linalg.norm(new_centers - centers) < tol: break centers = new_centers return centers, labels

逻辑说明:np.linalg.norm一次算出所有样本和所有中心的距离矩阵,形状是(n_samples, k),argmin得到每个样本最近的簇中心。更新中心时最常见的翻车点是某个簇一个样本都没有,X[labels == j].mean会直接产生 NaN,所以我在这里单独加了空簇判断,保留上一轮中心。

参数说明:max_iter默认 100,实际数据往往在 30 轮内收敛。tol=1e-4表示中心移动距离小于该值就停止,越小越精确但跑得越久。随机初始化导致结果不稳定,正式实验里你应该改用 sklearn 的KMeans(init="k-means++", random_state=42),k-means++ 让初始中心尽量分散,能从根源上减少“第一次跑好、第二次跑差”的血泪经验。

4.2 Apriori 关联规则:支持度、置信度与购物篮分析

Apriori 是十大算法里唯一围绕事务型数据设计的。它先找频繁项集,再生成关联规则,核心思想是“频繁项集的子集也频繁”,用这个性质剪掉大量候选。手写时需要注意的是,输入数据必须是一行一个购物篮,里面是商品集合或编码。

from collections import defaultdict def apriori(transactions, min_sup=0.01): n = len(transactions) # 第一轮:统计单个商品的支持度 cnt = defaultdict(int) for trans in transactions: for item in trans: cnt[frozenset([item])] += 1 freq = {itemset for itemset, c in cnt.items() if c >= min_sup * n} all_itemsets = [] k = 2 while freq: all_itemsets.extend(freq) # 由长度为 k-1 的频繁项集连接生成长度为 k 的候选 freq_list = list(freq) candidates = set() for i in range(len(freq_list)): for j in range(i + 1, len(freq_list)): merged = freq_list[i] | freq_list[j] if len(merged) == k: candidates.add(merged) # 扫描事务,统计候选支持度 cnt = defaultdict(int) for trans in transactions: trans_set = frozenset(trans) for cand in candidates: if cand.issubset(trans_set): cnt[cand] += 1 freq = {itemset for itemset, c in cnt.items() if c >= min_sup * n} k += 1 return all_itemsets

逻辑说明:代码里用frozenset作为项集的数据结构,是因为 set 不能作为 dict 的键。连接步骤只合并长度相同的频繁项集,合并后元素个数恰好为 k 才作为候选,这保证了候选集不会无限膨胀。内层循环用issubset判断候选是否出现在事务里,完整模拟了 Apriori 的逐轮扫描过程。

参数说明:min_sup是最重要的参数,表示商品至少出现在多少比例的订单里才保留。购物篮数据有大量长尾商品,min_sup设到 0.001 级别可能输出几十万个频繁项集,内存直接撑爆。我的血泪经验是从 0.05 开始试,看频繁项集数量是否在可接受范围,再逐步下调。关联规则阶段还有第二个阈值min_conf控制“买了 X 的人有多大比例买 Y”,一般设在 0.5 左右,太低会产生大量无意义规则。

4.3 EM 算法用高斯混合模型来理解:Expectation 在算什么

EM 是十大算法里最抽象的一个,只讲公式很难建立体感。实际操作里 EM 最常见的形态是高斯混合模型 GMM。E 步计算每个样本属于每个高斯分布的后验概率,M 步用这些概率加权重新估计均值和协方差,循环交替就是“猜归属 → 按归属更新参数 → 再猜”的过程。手写一维核心逻辑能把这个循环看清楚:

import numpy as np def em_step(X, mu1, mu2, sigma1, sigma2, w1): # E 步:算每个点来自分布 1 的后验概率 g1 = w1 * np.exp(-(X - mu1)**2 / (2 * sigma1**2)) g2 = (1 - w1) * np.exp(-(X - mu2)**2 / (2 * sigma2**2)) gamma = g1 / (g1 + g2) # M 步:按后验概率加权更新均值和权重,方差更新从简 mu1_new = np.sum(gamma * X) / np.sum(gamma) w1_new = np.mean(gamma) return mu1_new, w1_new

逻辑说明:E 步输出的gamma是一个 0 到 1 之间的软标签,表示样本属于第 1 个分布的概率;M 步用这个软标签加权更新均值和权重。为了保留可读性,上面的方差更新被省略了,完整实现里 sigma 也要按同样的加权方式一起更新。

实际项目里不需要手写完整 GMM,用 sklearn 一行接入即可:

from sklearn.mixture import GaussianMixture X = np.concatenate([ np.random.normal(0, 1, (300, 2)), np.random.normal(5, 1.5, (300, 2)) ]) gmm = GaussianMixture(n_components=2, covariance_type="full", random_state=42) gmm.fit(X) print("均值:", gmm.means_) print("权重:", gmm.weights_) labels = gmm.predict(X)

参数说明:n_components对应假设的高斯分布个数,可以用 BIC 或 AIC 曲线取拐点确定。covariance_type有 full、tied、diag、spherical 四种:full 允许每个簇有自己的完整协方差矩阵,拟合能力最强;样本量小时用 diag 或 spherical 更稳,不容易过拟合。random_state同样要固定,否则每次跑出的聚类结果会有细微差异,这在做论文实验时很致命。

4.4 PageRank 与 AdaBoost:两个“迭代”思想,一个在图网络,一个在集成学习

PageRank 通过反复迭代让每个节点的权重收敛到稳定值,K-Means、EM 也都是迭代式算法,但 PageRank 的迭代对象是图结构。AdaBoost 则是另一种迭代:每一轮把被错分的样本权重调高,下一个弱分类器重点学习这些样本,最后按错误率加权组合。两者都值得手写核心,面试追问频率很高。

import numpy as np def pagerank(adj, damping=0.85, max_iter=100, tol=1e-6): n = adj.shape[0] out_deg = adj.sum(axis=1).reshape(-1, 1) # 悬挂节点出度为 0,除零前先置为 1 out_deg[out_deg == 0] = 1 pr = np.ones(n) / n for _ in range(max_iter): new_pr = (1 - damping) / n + damping * ((adj / out_deg).T @ pr) if np.linalg.norm(new_pr - pr, ord=1) < tol: break pr = new_pr return pr
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.ensemble import AdaBoostClassifier from sklearn.tree import DecisionTreeClassifier X, y = load_iris(return_X_y=True) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) model = AdaBoostClassifier( estimator=DecisionTreeClassifier(max_depth=1), n_estimators=50, learning_rate=1.0, random_state=42 ) model.fit(X_train, y_train) print("AdaBoost acc:", model.score(X_test, y_test))

逻辑说明:PageRank 的damping=0.85是 Page 论文里的经典取值,表示用户按链接跳转的概率,剩下 0.15 随机跳转到任意节点。悬挂节点一旦出现,out_deg为 0,转移矩阵出现除零,结果直接 NaN,这是复现时最容易忽略的细节。AdaBoost 的基学习器用max_depth=1的决策树桩,因为弱分类器简单,Boosting 的提升空间才大,一上来就换强学习器,第二轮基本就过拟合了。

参数说明:AdaBoost 的n_estimators控制弱分类器数量,50 在 iris 上足够;如果你发现训练误差还在下降,可以加到 200,但要注意观察测试集是否开始变差。learning_rate与n_estimators成反比关系,官方建议“减小学习率的同时增大估计器数量”。如果你的场景是对抗样本较多或标签噪声大,AdaBoost 对噪声敏感的问题会暴露出来,那种情况下换成梯度提升树更稳。

5. 复现十大算法源代码时最常遇到的 5 个坑:现象、原因与解决

5.1 中文数据和路径引发的编码错误

现象:用 pandas 读 CSV 报UnicodeDecodeError,或者在 Windows 控制台打印决策树文字时出现乱码。

原因:Windows 下 Excel 导出的 CSV 默认是 GBK 编码,而 Python 3 默认按 UTF-8 读文件。这是环境相关而非算法本身的问题,却最容易卡住刚配好环境的人。

解决:读文件时显式指定编码,最常见做法是pd.read_csv("data/iris.csv", encoding="utf-8-sig"),utf-8-sig会自动去掉 BOM 头;如果明确知道文件是 GBK,就换成encoding="gbk"。代码文件本身统一用 UTF-8 保存,并在文件头部加一行# -*- coding: utf-8 -*-作为保险,这样在旧编辑器里也不会乱。

5.2 numpy 版本迭代导致的废弃接口报错

现象:运行老代码报AttributeError: module 'numpy' has no attribute 'float',或者出现np.matrix相关警告。

原因:numpy 1.20 之后移除了np.float、np.int、np.bool这些别名,很多十年前博客里的代码直接搬过来就会踩中。

解决:全局搜索代码中的np.float、np.bool、np.int,统一替换成内置类型float、bool、int。另一个做法是把 numpy 固定到 1.19.5,但新版本 scikit-learn 会强制要求更高版本的 numpy,所以最稳的还是改代码而不是降版本。这也是“数据挖掘十大算法源代码”项目里最常见的复现失败点,和算法本身毫无关系。

5.3 Apriori 的候选集爆炸把内存撑爆

现象:跑 Apriori 时程序卡死,或者内存占用一路飙升到几十 GB,风扇狂转。

原因:min_sup设置过低导致频繁项集数量指数增长,逐轮扫描全量事务又进一步拖慢速度。

解决:先把min_sup调到 0.02,确认频繁项集条数在可控范围,再逐步下降。如果业务确实需要挖掘大量长尾规则,改用 FP-Growth,它只需扫描两遍事务数据库,结构上规避了候选集爆炸问题。这是实现层面的取舍,不是 Apriori 本身的缺陷,面试时讲清楚这一点反而加分。

5.4 K-Means 每次运行结果都不一样

现象:同样的数据、同样的 K,跑两次聚类结果不同,簇中心顺序也变了,评估指标跟着波动。

原因:随机初始化中心不同,加上 sklearn 默认n_init=10,即使会在多次尝试里取最优,随机种子没固定,结果依然不可复现。

解决:在 KMeans 里显式设置random_state,并把n_init从默认的 10 提高到 20,用更多初始点弥补 k-means++ 选中心的随机性。论文实验和工程验证都必须固定随机种子,否则同事或评审复现不了你的结果,这属于文档里不会写但实战里永远存在的坑。

5.5 PageRank 迭代不收敛或出现 NaN

现象:PageRank 跑了几百轮都不收敛,或者结果里出现 NaN,导致后续排序结果全部无效。

原因:图里有悬挂节点(出度为 0 的节点);阻尼因子被调成 1,导致转移矩阵没有随机跳转项,迭代永远在子图之间循环。

解决:把出度为零的节点度数设为 1,这是上一章代码里已经处理过的地方。damping保持在 0.85 上下。迭代终止条件用一阶范数差sum(|new_pr - pr|),比二阶范数更直观。调阻尼因子时先画一条收敛曲线,看每轮差值是否稳定下降,如果振荡说明图结构本身有问题,优先回头检查悬挂节点和邻接矩阵归一化。

6. 把十段代码串成一个能交付的脚本:统一接口、一键验证

十段代码如果各自各的写法,验证时就是一场灾难。我让所有分类算法实现同样的fit(X, y)、predict(X)、score(X, y)接口,这样 evaluate.py 就能把它们排成一列直接跑:

# evaluate.py from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from algorithms import c45, cart, svm, knn, naive_bayes, adaboost X, y = load_iris(return_X_y=True) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) benchmarks = { "C4.5": c45.C45Classifier(), "CART": cart.CARTClassifier(), "SVM": svm.SVMClassifier(), "KNN": knn.KNNClassifier(), "NaiveBayes": naive_bayes.NBClassifier(), "AdaBoost": adaboost.AdaBoostClassifier(), } for name, model in benchmarks.items(): model.fit(X_train, y_train) acc = model.score(X_test, y_test) print(f"{name:12s} {acc:.4f}")

逻辑说明:这段代码只依赖每个模型统一的score方法,具体算法封装在各自的文件里。K-Means 和 GMM 是聚类,不走这个脚本,用轮廓系数单独验证;Apriori 要换数据集;PageRank 看收敛曲线。这样就形成了两个验证通道,互不干扰。

验证聚类算法时,我习惯加上时间统计和轮廓系数两项,避免只看一个数字:

import time from sklearn.metrics import silhouette_score start = time.perf_counter() labels = kmeans_predict(X_scaled, k=3) elapsed = time.perf_counter() - start score = silhouette_score(X_scaled, labels) print(f"KMeans silhouette={score:.4f}, time={elapsed:.3f}s")

说明:X_scaled先做标准化再送进 K-Means,否则轮廓系数会被大数值特征带偏。time.perf_counter比time.time精度更高,适合这种毫秒级调用。

我的个人习惯是每个算法备两份代码:一份纯手写版,长度控制在 50 行以内,用来面试讲原理;一份基于 scikit-learn 的精简版,用来快速出结果和跟同事对齐。手写版里绝不依赖黑匣子,每一行都能说清在算什么;精简版里所有random_state都显式写上,方便别人复现。很多时候算法本身没问题,最后翻车都翻在版本、种子和编码这些小事上,提前把这些固定下来,等于给自己留了后悔药,希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/12 14:45:52

TRIZ矛盾矩阵Word版活化指南:从查表到设计落地的四步工程法

简介&#xff1a;本资源为TRIZ理论核心工具——阿奇舒勒矛盾矩阵表的标准化Word版本&#xff0c;面向工程师、创新方法学习者及高校工科师生&#xff0c;专用于快速定位技术矛盾对应的40条发明原理&#xff0c;解决产品设计中常见的参数冲突&#xff08;如提升强度导致重量增加…

作者头像 李华
网站建设 2026/10/12 14:45:39

从澳龙案例看AI Agent如何落地供应链自动化

1. 从一条“游出澳龙”的消息说起&#xff1a;这个项目到底在做什么第一次看到“杭港科技大厦‘游出’澳龙&#xff01;智谱 AutoClaw 上线”这个标题&#xff0c;我脑子里冒出来的第一个念头是&#xff1a;这又是什么营销噱头&#xff1f;澳龙和科技大厦、和 AutoClaw 能扯上什…

作者头像 李华
网站建设 2026/10/12 14:41:26

51单片机驱动步进电机:从选型到稳定运行的完整实践

1. 为什么现在还有人用51单片机驱动步进电机很多人第一次接触步进电机控制&#xff0c;脑子里蹦出来的方案要么是STM32加驱动器&#xff0c;要么直接上PLC。但如果你去翻一些小型自动化设备、教学实验平台或者老式仪表的电控部分&#xff0c;会发现51单片机出现的频率依然很高。…

作者头像 李华
网站建设 2026/10/12 14:40:38

JAVA_HOME配置详解:Linux/macOS环境变量设置与排错指南

每次帮同事排查Java环境问题&#xff0c;十次有八次最后都会绕到同一个点上&#xff1a;JAVA_HOME没配对。这个变量看起来只是一个普通的环境变量&#xff0c;指向JDK安装目录&#xff0c;但它牵一发而动全身。构建工具、IDE内置终端、自动化脚本、应用服务器&#xff0c;几乎凡…

作者头像 李华
网站建设 2026/10/12 14:36:54

旋转圆盘上的摆动模拟:非惯性系下的动力学建模与数值实现

“旋转圆盘上的摆动模拟”听起来像个物理课建模题&#xff0c;但真正落地做的时候&#xff0c;你会发现它兼顾了刚体动力学、非惯性系分析和数值稳定性这几件麻烦事。我最早是因为一个同学在某个平台团建展示了一个演示&#xff1a;圆盘转起来&#xff0c;摆锤没有老老实实顺着…

作者头像 李华