news 2026/9/23 14:40:28

Python常用机器学习算法源码解析:从环境配置到参数调优

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python常用机器学习算法源码解析:从环境配置到参数调优

简介:一份面向机器学习入门与进阶学习者的 Python 算法实现资料包,涵盖概率统计基础、常用模型原理讲解与可运行代码,适合正在学习《统计学习方法》或想动手理解经典算法的人。资料系统总结了总体均值、总体方差、样本均值、样本方差、无偏估计、有偏估计、样本标准差、样本协方差与协方差矩阵等统计概念;算法部分覆盖 Apriori、决策树、HMM 的 Viterbi 算法、朴素贝叶斯、逻辑回归,以及标准线性回归、局部加权线性回归和岭回归,并配有对应 Python 实现与学习笔记。同时提供带图解的可视化图片和 PDF 文档,便于对照理解理论推导与代码细节,还有基于 TensorFlow、Keras、sklearn 等框架的工程化示例,帮助读者从公式走向实际应用。资源包共 38 个文件,以图片、Markdown 笔记、Python 脚本、TXT 说明和 PDF 文档为主,压缩包大小 29.26MB,已有 289 人学习浏览,目录划分清晰,适合按主题逐步查阅。

1. 这份源码不是给你直接跑的:先把"常用算法"拆清楚

拿到一个名为“基于Python的一些常用的机器学习算法实现代码源码.zip”的压缩包,第一反应往往是解压、找requirements.txtpip install然后直接运行 demo。如果你按这个顺序来,大概率会在第二个文件就卡住,因为这类源码集的价值不在“一键跑通”,而在让你看清每个算法是怎么用 Python 一步步实现的。它通常覆盖线性回归、逻辑回归、KNN、决策树、朴素贝叶斯、SVM、K-Means 等经典算法,代码风格一半是手写 for 循环,一半是 scikit-learn 调包,正好对应原理和工程两条线。适合刚学完 Python 语法、想把手推公式变成可运行代码的人,也适合做课程设计或算法汇报前临时补代码的人。这篇笔记会从源码结构、环境配置、最小复现讲到参数调优和避坑,让你拿到 zip 之后不是对着报错发呆。

2. 源码包里到底装了什么:常用机器学习算法清单与代码组织

2.1 覆盖哪些算法?为什么是这十来个

这类源码包常见的覆盖范围是:线性回归、逻辑回归、K近邻(KNN)、朴素贝叶斯、决策树、随机森林、SVM、K-Means、PCA主成分分析,偶尔还会带一个感知机或 AdaBoost。它们被称为“常用”不是因为每个都能在业务里直接当主力,而是因为它们是理解后面一切复杂模型的骨架。你把 KNN 的 KD 树搞明白,后面看向量检索和高维索引就不慌;你把逻辑回归的梯度下降写顺,后面看神经网络的 backprop 就是同一套思路。

拿到压缩包,我先做的不是逐个点开,而是先列一个算法清单,标出哪些需要看、哪些只需要跑通。很多初学者容易陷入“每个文件都要读懂每一行”的误区,结果在 SVM 的核函数推导上耗了两天,最后还是一头雾水。我一般只要求自己做到三件事:能说清这个算法的输入输出、能画出它的训练流程、能指出它最重要的一个超参数。做到这三条,再去看别人的实现代码,效率会高很多。

另一个判断方法是看文件名。如果压缩包里有knn.pylogistic_regression.py这种命名,通常很好办;如果是一堆demo1.pytest2.py,那就得靠 README 或代码头部注释来识别。没有 README 的时候,我会直接在项目根目录用一条命令把所有.py文件的头部 20 行打印出来,快速判断哪个是入口,而不是鼠标准一个点一个。

2.2 从目录结构开始,别让文件堆成黑匣子

我见过的多数同类源码包会遵循一套约定俗成的结构,你可以按这个预期去定位文件,但不用照搬。它一般是:

src/ linear_regression.py logistic_regression.py knn.py naive_bayes.py decision_tree.py svm.py kmeans.py pca.py data/ sample.csv iris.csv output/ plots/ requirements.txt README.md

这个结构里src放算法脚本,data放数据集,output放图表和结果,根目录放环境文件和说明。如果你解压后发现算法脚本全堆在根目录,连 README 都没有,那就要做好自己摸索接口的准备。这时候不要慌,先看代码里有没有if __name__ == "__main__",有就说明作者预留了入口,没有就需要自己写调用。

定位文件时,我习惯用一条 Python 命令把所有.py文件打上标签:

import os for root, dirs, files in os.walk('.'): for f in files: if f.endswith('.py'): print(os.path.join(root, f))

逻辑说明:os.walk递归遍历目录树,把每个.py文件的相对路径打印出来。这样即使没有 README,你也能一眼看出这个包的结构,而不是在文件管理器里一个个点开。root是当前目录,f是文件名,os.path.join把它们拼成完整路径。

然后看requirements.txt,这是环境的起点。我一般会在项目根目录执行:

python -m venv venv source venv/bin/activate # Windows 上换成 venv\Scripts\activate pip install -U pip pip install -r requirements.txt

参数说明:python -m venv venv用当前 Python 解释器创建虚拟环境,后面的venv是环境目录名,可以改成任意名字;激活命令在 Windows 和 Linux/macOS 下不一样,激活后终端前缀会出现(venv),说明当前操作已经进入虚拟环境。如果项目没有requirements.txt,就手动装最小依赖:numpy pandas scikit-learn matplotlib jupyter

注意,numpy 不要装最新的,先看看 README 写的 Python 版本。很多教学源码还是基于np.floatnp.bool这种老写法写的,numpy 2.0 里已经移除。装完依赖后立刻确认版本,不是玄学,是这类源码最常见的坑:

import numpy print(numpy.__version__)

如果版本号是 2.x,就降到 1.26.4。这个动作能帮你避开后面一整类报错。

2.3 手写实现与调包实现:分别有什么用

以 KNN 为例。KNN 是最容易手写的算法,原理就是“找最近的 K 个点投票”。手写版核心代码通常长这样:

import numpy as np def knn_predict(X_train, y_train, point, k=3): # 计算 point 到每个训练样本的欧氏距离 distances = [((point - x) ** 2).sum() ** 0.5 for x in X_train] idx = np.argsort(distances)[:k] # 距离最近的前 k 个下标 labels = y_train[idx] values, counts = np.unique(labels, return_counts=True) return values[np.argmax(counts)]

逻辑说明:((point - x) ** 2).sum() ** 0.5是欧氏距离的代码翻译,argsort返回从小到大排序后的索引,截前k个就是在找最近邻。np.unique配合return_counts=True统计每个类别出现次数,argmax选票数最高的类别。这里一个隐含要求是pointx的长度一致,否则减号触发 numpy 广播时直接报错。

参数说明:k是近邻数,一般取奇数防止平票。k 越小决策边界越碎、越容易过拟合;k 越大整体越平滑,但可能把不同类别揉在一起。在鸢尾花这种小数据集上,3 到 11 之间的奇数都值得试。

调包版则是:

from sklearn.neighbors import KNeighborsClassifier model = KNeighborsClassifier(n_neighbors=3) model.fit(X_train, y_train) pred = model.predict([point])

对比这两段,你会发现手写版的价值是让你看见算法的“肉”,调包版的价值是让你快速进入业务流。所以我在看源码时会把它们分开归类:需要改的是手写版,需要跑实验的是调包版。这样后面做参数扫描时,也不会因为改错文件导致结果混乱。

2.4 阅读顺序:先找入口,再追数据流

打开任何一个算法文件,别从第一行看到最后一行,效率太低。我一般按下面顺序:

  1. if __name__ == "__main__"里的调用代码,确定这个文件怎么运行。
  2. 找数据加载代码,看它读的是哪个 csv,字段顺序是什么。
  3. 看预处理部分,有没有标准化、白化或其他变换。
  4. 最后才是算法主体。

这样做的原因是很多教学源码把数据预处理写得很隐蔽,可能在load_data()函数里,也可能在算法类构造时顺带做了。你只盯着核心算法,忽略了前几步,后面调参就会像在黑匣子里找变量。以前我复现一个逻辑回归,怎么调学习率都很慢,最后发现作者在load_data()里做了 z-score 归一化,而我用自己的代码加载原始数据,自然结果对不上。所以先追数据流是血泪换来的习惯。

如果压缩包里带 Jupyter notebook,优先打开 notebook 版本,因为它通常保留了单元格的执行顺序,比纯 py 脚本更容易拼出完整流程。这一条对刚开始接触源码包的读者尤其有用。

3. 跑通第一个算法:环境配置与最小复现代码

3.1 环境准备:Python 3.8+ 与 VS Code 配置

新机器上跑这类源码,第一步永远是装 Python。用官方安装包就行,注意在安装界面勾选“Add Python to PATH”,否则后面pip会报“不是内部命令”。装完检查:

python --version pip --version

如果pip不是内部命令,多半是 PATH 没勾上。处理方式是把 Python 安装目录和它的Scripts子目录手动加到环境变量里。虽然这个操作基础,但它确实是源码复现阶段最大的卡点之一。我看过不少人卡在环境上,连算法代码长什么样都没看到,就放弃了。

接下来我推荐用 VS Code 而不是直接开一个终端死磕,因为看源码需要跳转定义、打断点,以及观察变量。需要装两个扩展:Python 和 Jupyter。然后创建虚拟环境并安装依赖:

python -m venv venv venv\Scripts\activate python -m pip install --upgrade pip pip install numpy==1.26.4 pandas scikit-learn matplotlib jupyter

参数说明:python -m venv venv创建一个叫venv的虚拟环境,后面所有包都装在里面,不影响系统 Python。Windows 下激活命令是venv\Scripts\activate,Linux/macOS 是source venv/bin/activatenumpy==1.26.4这里必须固定版本,因为 numpy 2.x 移除了np.float这类旧别名,而许多教学源码还在用。

然后新建一个run_demo.py或 notebook,先导入测试:

import numpy as np import pandas as pd import sklearn print(np.__version__, sklearn.__version__)

如果这行不报错,环境就稳了。我还会顺手执行import numpy as np; print(np.__file__),确认用的是虚拟环境的解释器,不是全局或者另一个 conda 环境。这样可以避免报错之后找不到包到底装在了哪里。

3.2 纯 Python 实现 KNN:从手写代码开始

数据我选 sklearn 自带的鸢尾花,因为不需要下载外网文件,稳定可复现。

from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split import numpy as np data = load_iris() X = data.data y = data.target # 先做 z-score 归一化,去掉量纲影响 X_mean = X.mean(axis=0) X_std = X.std(axis=0) X = (X - X_mean) / X_std X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y )

逻辑说明:归一化部分直接用了 numpy 的meanstd,没有用 sklearn,因为我们要配合手写实现,后面才能完全掌控每步。random_state=42让划分结果稳定,stratify=y让训练集和测试集中三类鸢尾花的比例一致。

参数说明:test_size取 0.2 表示留出 20% 样本做测试;如果你手里的数据集只有几十条,建议改成 0.3 或 0.4,否则测试集样本太少,评估结果波动很大。random_state可以是任意整数,只要固定就行。

然后写手写预测函数:

def knn_predict_all(X_train, y_train, X_test, k=3): predictions = [] for point in X_test: # 当前测试点到所有训练点的欧氏距离 dist = np.linalg.norm(X_train - point, axis=1) # 取最近的 k 个 k_idx = np.argsort(dist)[:k] labels = y_train[k_idx] values, counts = np.unique(labels, return_counts=True) predictions.append(values[np.argmax(counts)]) return np.array(predictions) y_pred = knn_predict_all(X_train, y_train, X_test, k=3) print("准确率:", (y_pred == y_test).mean())

逻辑说明:np.linalg.norm(..., axis=1)一次算出当前点与所有训练样本的欧氏距离,axis=1是按行计算;如果不写,numpy 会默认对矩阵做全局向量范数,得到完全错误的结果。后面argsort取前 k 个索引,再用np.unique做投票。最后(y_pred == y_test).mean()计算的是预测正确的样本占比。

参数说明:k=3是最常见的默认值,在鸢尾花上准确率通常超过 95%。你可以在循环里换 k,观察准确率怎么变,这是理解“过拟合/欠拟合”最快的方法。

3.3 用 scikit-learn 做对照:结果应该一致

from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score model = KNeighborsClassifier(n_neighbors=3, metric='minkowski', p=2) model.fit(X_train, y_train) y_pred_sk = model.predict(X_test) print("sklearn准确率:", accuracy_score(y_test, y_pred_sk))

参数说明:metric='minkowski'是闵可夫斯基距离,p=2时就是欧氏距离,和手写版一致;p=1是曼哈顿距离。n_neighbors就是手写版的k

这个对照的意义在于:如果你后面发现手写版和调包版结果对不上,问题多半出在数据预处理,而不是算法本身。sklearn 的 KNN 不会自动归一化,但你如果忘了缩放,结果可能差好几点。这也是源码复现时最值得注意的一点。

3.4 把多个算法串起来跑:一个统一的入口脚本

源码包里算法很多,一个个运行效率太低,我会写一个run_all.py,把常用分类器统一跑一遍:

from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.svm import SVC from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score models = { "KNN": KNeighborsClassifier(n_neighbors=3), "Logistic": LogisticRegression(max_iter=200), "DecisionTree": DecisionTreeClassifier(max_depth=3), "SVM": SVC(C=1.0, kernel='rbf'), } for name, clf in models.items(): clf.fit(X_train, y_train) pred = clf.predict(X_test) print(f"{name}: {accuracy_score(y_test, pred):.4f}")

逻辑说明:把模型放进字典,循环训练和评估,同一份数据上对比不同算法的准确率。这样你就能看出在鸢尾花这种简单数据集上,线性模型和树模型的差距并不会太大。源码包里的算法再多,本质都是fitpredict两个动作,统一封装后排查也方便。

参数说明:LogisticRegression(max_iter=200)里的max_iter表示梯度下降的最大迭代次数,如果没收敛就调大,或者先归一化数据。SVC(C=1.0, kernel='rbf')里的C是正则化强度的倒数,kernel选非线性核。这些参数后面调优章节会展开。

4. 让算法真正可用:参数调优与模型评估的四个关键点

4.1 数据划分:随机种子与分层的意义

很多源码复现的翻车不是算法错,而是数据划分没统一。你拿到的源码如果已经划分好,就不要自己改;如果没有,就固定一套标准。我强烈建议在分类任务中用分层划分:

from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=2024, stratify=y )

参数说明:stratify=y保证训练和测试集中各类别占比与原始数据一致,特别适合类别不平衡场景。random_state给一个固定整数,结果可以复现。你不用纠结具体用什么数字,只要每次实验用同一个就行。

这里有个反直觉的点:同样的算法,换一个 random_state,准确率可能波动 3 到 5 个百分点。如果只跑单次划分,这种波动无法准确评价算法好坏。所以我在调参之前,会先用交叉验证把波动消掉,这也是 4.3 的内容。

4.2 特征缩放:为什么 KNN 和 SVM 对量纲敏感

KNN 计算距离、SVM 寻找最大间隔、PCA 计算方差,这三个算法对量纲极其敏感。假设一个特征在 0~1 之间,另一个在 0~10000 之间,那距离计算几乎被第二个特征主导,第一个特征等于白给。源码包里的从零实现不一定自动做归一化,这环节往往要你自己处理。

from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)

逻辑说明:fit_transform在训练集上计算每个特征的均值和标准差,然后做标准化;transform在测试集上只使用训练集算好的均值和标准差,不重新计算。如果在测试集上也调用fit_transform,那测试集的信息提前进入了模型,会造成数据泄漏,评估结果虚高。

参数说明:StandardScaler是 sklearn 里最常用的缩放器,输出均值为 0、标准差为 1。如果数据本身是稀疏矩阵,可以用MaxAbsScaler或者不做缩放,这属于特殊情况。

4.3 交叉验证找 K 值:从默认参数到最优参数

源码包里的默认参数通常只是让代码能跑,不一定让效果最好。拿 KNN 举例,k 选多少合适,我会扫一遍然后用交叉验证评估:

from sklearn.model_selection import cross_val_score from sklearn.neighbors import KNeighborsClassifier for k in range(1, 20, 2): model = KNeighborsClassifier(n_neighbors=k) scores = cross_val_score(model, X_train_scaled, y_train, cv=5) print(f"k={k}, mean={scores.mean():.4f}, std={scores.std():.4f}")

逻辑说明:cross_val_score会把传入的训练集再切成 5 份,轮流做验证集,得到 5 个分数。scores.mean()是平均表现,scores.std()是稳定性。k 太小时模型过于复杂,容易抓住噪声;k 太大时模型过于平滑,容易欠拟合。选均值高且标准差小的 k。

参数说明:cv=5是交叉验证折数,数据量大可以取 10,数据少建议取 3。cross_val_score默认按分类问题用准确率评估,如果做回归,要传scoring='r2'scoring='neg_mean_absolute_error'

4.4 评估指标:分类看 F1,回归看 R²

很多源码包只输出准确率,那是为了让 demo 好看。实际做选型,我从不只看准确率,尤其类别不平衡时。比如 99 个正样本 1 个负样本,全部预测为正类,准确率 99%,但模型毫无用处。这时要用精确率、召回率和 F1。

from sklearn.metrics import classification_report print(classification_report(y_test, y_pred, target_names=data.target_names))

逻辑说明:classification_report一次输出每个类别的精确率、召回率、F1 以及支持度。target_names把 0/1/2 的标签换成可读的类别名。对于多分类问题,这个报告比只看准确率直观得多。

回归问题则用 R² 和 MAE:

from sklearn.linear_model import LinearRegression from sklearn.metrics import r2_score, mean_absolute_error lr = LinearRegression() lr.fit(X_train_scaled, y_train) pred = lr.predict(X_test_scaled) print("R²:", r2_score(y_test, pred)) print("MAE:", mean_absolute_error(y_test, pred))

逻辑说明:R² 表示模型解释了目标变量多少比例的方差,最大为 1 但可能为负(模型比直接取均值还差);MAE 是预测值与真实值的平均绝对误差,单位与目标变量一致,更直观。

注意,这里的X_train_scaled是在 4.2 中对训练集缩放的结果,测试集用同一个 scaler 转换。如果你的 y 是分类标签,则不能用回归代码,这是常识,但我在实际里真见过有人把分类标签直接喂给线性回归。

4.5 用 GridSearchCV 把参数扫描自动化

手动循环看输出可以直观,但参数一多效率太低。复现阶段我更喜欢 GridSearchCV:

from sklearn.model_selection import GridSearchCV from sklearn.svm import SVC param_grid = { 'C': [0.1, 1.0, 10], 'kernel': ['rbf', 'linear'], 'gamma': ['scale', 'auto'] } grid = GridSearchCV(SVC(), param_grid, cv=5, scoring='f1') grid.fit(X_train_scaled, y_train) print(grid.best_params_) print(grid.best_score_)

参数说明:param_grid里每个 key 对应模型构造函数的参数名,GridSearchCV会组合出所有参数组合,逐个做 5 折交叉验证。scoring='f1'让评估指标从准确率换成 F1,适合类别不平衡;数据平衡时用'accuracy'也行。best_params_给出最优组合,best_score_是它在交叉验证上的平均分。

这段代码能直接验证源码包的默认参数是不是最优,也让“基于 Python 实现算法”这件事真正变成“能调、能用、能评估”。

5. 避坑指南:复现机器学习源码常见的 5 个翻车现场

5.1 运行报错类:numpy 旧写法与 sklearn 接口翻车

复现带源码的机器学习项目,九成报错集中在环境,而不是算法本身。最常见的当然是 numpy 版本带来的问题。

现象:在导入某个算法模块时,直接抛AttributeError: module 'numpy' has no attribute 'float',或者类似的np.boolnp.int问题。原因:numpy 2.x 移除了这些历史遗留别名,而很多教学源码还在用np.floatnp.bool。解决:有两条路,优先把 numpy 固定到 1.26.4 重新安装,其次在源码里全局替换旧写法。我推荐第一条路,因为改源码容易引入新的错误,改动越小越好。

pip install numpy==1.26.4

固定版本后,再跑一次之前的导入测试程序。如果还报错,就说明代码里确实有需要替换的名字。批量替换时注意不要动np.float64np.bool_这种合法名称,直接用 IDE 的全局替换就可以。

第二个常见报错是 sklearn 参数接口变化。现象:运行旧源码,出现FutureWarning或者TypeError: __init__() got an unexpected keyword argument。原因:sklearn 版本更替时,一些参数名改过,比如learning_ratetol这类,不同版本默认值也不同。解决:把 sklearn 固定到一个较新但稳定的版本,例如scikit-learn==1.5.2,然后以官方文档为准。源码里如果用的是旧参数,要么升级代码,要么降级 sklearn,二选一。我一般选固定版本,因为社区解决方案和文档都围绕常用版本展开。

5.2 结果不对类:数据泄漏、划分不一致、学习率过大

运行不报错不代表复现成功。很多时候代码能跑,但结果跟源码作者给的指标差很远,这往往是最难查的。

现象:验证分数高得离谱,但换一组数据就崩。原因:在划分训练集和测试集之前,就对全量数据做了标准化,测试集的信息提前进入训练流程,这叫数据泄漏。解决:先train_test_split,再用训练集的 scaler 去transform测试集。前面 4.2 已经写过,代码再贴一次:

scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)

现象:分类结果所有样本都被预测成多数类。原因:训练集和测试集类别比例不一致,比如原数据 70% 是 0 类,30% 是 1 类,随机划分后测试集里几乎全是 0 类,模型自然不输出 1。解决:在train_test_split里加stratify=y,让划分保持原始类别比例。这个参数是救命用的,不是可选项。

现象:手写逻辑回归或感知机,损失函数不下降,甚至变成 NaN。原因:学习率设置太大,参数更新时梯度爆炸;或者特征没有归一化,导致某些特征的梯度比其他特征大得多。解决:把学习率从 0.01 降到 0.0001,或者先对特征做标准化。如果损失还是 NaN,检查训练数据里是否有缺失值或无穷值:

import numpy as np print(np.isnan(X).any()) print(np.isinf(X).any())

逻辑说明:这两行分别检查数组里是否存在 NaN 和无穷大。如果返回 True,说明数据源头有问题,需要回到数据清洗阶段。X在这里是特征矩阵,如果数据集太大,也可以切片检查。

5.3 排查方法论:一次只改一个变量

上面五条记录了最常见的坑,但实际排查时你可能会遇到多条同时起作用。这时候最怕的就是同时改版本、改数据、改参数,结果出了问题都不知道是哪个改动引起的。

我现在的习惯是:先复现报错,然后一次只改一个变量。如果 numpy 版本固定后还报错,那就先不改代码,去看是不是 sklearn 版本不匹配;确认环境完全一致后,再动数据。最后才看参数。这样做表面上慢,实际是最快的,因为它把“玄学”排除掉了。

提示:如果你把自己改过的变量记在笔记里,每一条后面标上结果,那这份源码包你已经吃透了。源码复现阶段最有价值的产物不是模型,而是你自己排错的过程。

6. 从源码到自己跑实验:把算法封装成统一的 fit/predict 接口

当你把源码包里的算法都跑通后,下一步不是删掉它,而是把它变成自己的工具。我的习惯是每个算法写一个很小的封装类,只暴露fitpredict两个方法,这样后面换算法、做交叉验证、调参都只需要改一行。

from sklearn.base import BaseEstimator, ClassifierMixin import numpy as np class MyKNN(BaseEstimator, ClassifierMixin): def __init__(self, k=3): self.k = k def fit(self, X, y): self.X_train = np.asarray(X) self.y_train = np.asarray(y) return self def predict(self, X): result = [] for p in np.asarray(X): dist = np.linalg.norm(self.X_train - p, axis=1) idx = np.argsort(dist)[:self.k] vals, counts = np.unique(self.y_train[idx], return_counts=True) result.append(vals[np.argmax(counts)]) return np.array(result)

逻辑说明:继承BaseEstimatorClassifierMixin后,这个类就能直接放进cross_val_scoreGridSearchCV里使用。__init__只存参数,不计算任何东西,这是 sklearn 对自定义模型的基本要求,否则会在克隆模型时出错。fit返回self也是规范之一。

用法:

from sklearn.model_selection import cross_val_score scores = cross_val_score(MyKNN(k=5), X_scaled, y, cv=5) print(scores.mean(), scores.std())

注意:X_scaled必须是经过标准化的数据,否则结果会和 sklearn 内置 KNN 差很多。这也是我每次收尾时一定会检查的地方。

写到这,想重复一句我血泪换来的习惯:拿到这类源码包,先看 README,再固定版本,然后只改一个参数跑通一次,最后才动整个流程。不要想着一口气把十来个算法全都调好。尤其是初学者,一上来就调 SVM 的 gamma,很可能调一晚上都是玄学,还耽误后面学习。希望帮到你。

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

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

坦克检测数据集实战:VOC转YOLO与yolov8训练全流程

简介:这份资源是面向目标检测初学者与算法工程师的坦克检测数据集,采用Pascal VOC与YOLO双格式标注,可直接用于YOLO系列模型的训练与验证,适合军事目标识别、遥感图像分析等场景的入门实践与算法调优。压缩包共2000个文件&#xf…

作者头像 李华
网站建设 2026/9/23 14:39:50

OpenHarmony中React Native AsyncStorage批量操作优化实践

1. 项目背景与核心价值在OpenHarmony生态中集成React Native技术栈时,数据持久化一直是开发者面临的痛点问题。AsyncStorage作为React Native官方推荐的轻量级存储方案,其批量操作能力在实际业务场景中尤为重要。想象一下电商应用的购物车同步、社交应用…

作者头像 李华
网站建设 2026/9/23 14:39:51

手游脚本软件哪个好用:源码解析避坑指南

手游脚本软件哪个好用:源码解析避坑指南 版本升级后 API 全变了?昨天还能跑的代码,今天一启动直接闪退,报错信息还看不懂。别急着骂娘,这时候去翻 源码解析 ,比盲目试错快十倍。很多老手都在坑里躺过,今天就把几款主流手游脚本工具的底层逻辑拆开了讲,告诉你到底哪款适合你,怎么改代码才能稳住。 1.…

作者头像 李华
网站建设 2026/9/23 14:39:35

ps怎么做印章手写实现:3个避坑指南让性能提升10倍

ps怎么做印章手写实现:3个避坑指南让性能提升10倍 配置环境就卡半天?别慌。很多转岗做前端或后端的朋友,一接触图像处理就头大,装库、配依赖、调参数,半天过去了代码还没跑通。这篇避坑指南,直接给你能跑通的代码和性能数据,不整虚的。 性能瓶颈:为什么你的印章生成慢如蜗牛…

作者头像 李华