多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

机器学习入门代码实战:六算法统一框架与企鹅数据集

机器学习入门代码实战:六算法统一框架与企鹅数据集 简介这份资源面向机器学习初学者与需要快速上手经典算法的开发者系统整理了六类基础模型的入门代码覆盖分类与回归两大任务场景。压缩包共14个文件以13个Python脚本和1个CSV数据集为主整体约24KB轻量易读适合边看边跑。内容涵盖BP神经网络MLP的反向传播与非线性拟合、KNN回归中K值选择与交叉验证、SVM最大间隔超平面及软间隔实现、基于企鹅数据集的决策树分类、朴素贝叶斯条件独立假设以及逻辑回归借助sigmoid输出概率的二分类思路并附带iris等经典数据练习。已有343人学习代码结构清晰、注释友好可作为课程实验、自学练手与算法对比的参考模板帮助读者在动手实践中理解各模型原理、训练流程与调参要点逐步建立数据分析和机器学习的基础能力。1. 机器学习入门代码从企鹅数据集到 SVM 超平面一套能跑通的六算法实战很多人学机器学习卡在同一个地方理论书翻了大半公式推得头头是道真给一份 CSV 却不知道从哪下手。这份入门代码合集瞄准的正是这个断层——它把 BP 神经网络MLP、KNN 回归、SVM 超平面、决策树、朴素贝叶斯、逻辑回归六个最经典的算法全部落到同一套 Python 代码框架里用企鹅数据集这类小样本数据把「加载→预处理→训练→评估」的完整链路走一遍。适合刚学完吴恩达机器学习课程、想找一份能直接跑起来的 python 机器学习入门代码的读者也适合期末复习阶段需要快速回顾各算法 API 调用方式的同学。下面按「先跑通再调参」的顺序把每个算法的落地细节和踩坑点讲清楚。2. 六算法代码骨架统一数据流与最小可运行示例2.1 为什么选企鹅数据集做统一入口入门阶段最怕的不是算法难而是数据格式五花八门。今天用鸢尾花明天换手写数字光数据加载和特征对齐就耗掉大半精力。企鹅数据集Palmer Penguins的好处是样本量适中约 344 条、特征维度低4 个数值特征 3 个类别、自带缺失值天然适合练「数据清洗→特征工程→模型训练」的完整流程。常见做法是用seaborn.load_dataset(penguins)直接拉取或者从本地 CSV 读取。我一般会先做三件事看缺失值分布、看类别是否均衡、看数值特征的量纲差异。这三步决定了后面要不要插补、要不要分层采样、要不要标准化。import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler, LabelEncoder # 加载企鹅数据集 df pd.read_csv(penguins.csv) # 1. 查看缺失值 print(df.isnull().sum()) # 2. 查看类别分布 print(df[species].value_counts()) # 3. 查看数值特征统计 print(df.describe()) # 丢弃缺失值入门阶段最简处理 df df.dropna() # 特征与标签分离 feature_cols [bill_length_mm, bill_depth_mm, flipper_length_mm, body_mass_g] X df[feature_cols].values y df[species].values # 标签编码 le LabelEncoder() y_encoded le.fit_transform(y) # 划分训练集和测试集stratify 保证类别比例一致 X_train, X_test, y_train, y_test train_test_split( X, y_encoded, test_size0.2, random_state42, stratifyy_encoded ) # 标准化KNN、SVM、逻辑回归对量纲敏感必须做 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)这段代码的关键点有三个。第一dropna()是最粗暴的缺失值处理实际项目中要根据缺失比例决定是插补还是丢弃入门阶段先用最简方式跑通。第二stratifyy_encoded保证训练集和测试集的类别比例与原始数据一致否则小样本下可能出现某个类别在测试集中完全缺失的情况。第三StandardScaler的fit只在训练集上做测试集用transform这是防止数据泄露的基本功——很多入门代码在这里翻车把全量数据一起 fit导致评估结果虚高。2.2 六个算法的最小调用模板统一数据流之后每个算法的调用其实只有几行。下面按「回归类」和「分类类」分开列因为 KNN 回归和逻辑回归虽然名字里有回归但用法差异很大。from sklearn.neural_network import MLPClassifier from sklearn.neighbors import KNeighborsRegressor from sklearn.svm import SVC from sklearn.tree import DecisionTreeClassifier from sklearn.naive_bayes import GaussianNB from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score, mean_squared_error # 1. BP 神经网络MLP分类 mlp MLPClassifier(hidden_layer_sizes(64, 32), activationrelu, solveradam, max_iter500, random_state42) mlp.fit(X_train_scaled, y_train) mlp_pred mlp.predict(X_test_scaled) print(MLP 准确率:, accuracy_score(y_test, mlp_pred)) # 2. KNN 回归用体长预测体重做回归任务 X_reg df[[bill_length_mm, bill_depth_mm, flipper_length_mm]].values y_reg df[body_mass_g].values Xr_train, Xr_test, yr_train, yr_test train_test_split(X_reg, y_reg, test_size0.2, random_state42) knn KNeighborsRegressor(n_neighbors5, weightsdistance) knn.fit(Xr_train, yr_train) knn_pred knn.predict(Xr_test) print(KNN 回归 MSE:, mean_squared_error(yr_test, knn_pred)) # 3. SVM 超平面分类 svm SVC(kernelrbf, C1.0, gammascale, probabilityTrue, random_state42) svm.fit(X_train_scaled, y_train) svm_pred svm.predict(X_test_scaled) print(SVM 准确率:, accuracy_score(y_test, svm_pred)) # 4. 决策树 dt DecisionTreeClassifier(max_depth4, criteriongini, random_state42) dt.fit(X_train_scaled, y_train) dt_pred dt.predict(X_test_scaled) print(决策树准确率:, accuracy_score(y_test, dt_pred)) # 5. 朴素贝叶斯 nb GaussianNB() nb.fit(X_train_scaled, y_train) nb_pred nb.predict(X_test_scaled) print(朴素贝叶斯准确率:, accuracy_score(y_test, nb_pred)) # 6. 逻辑回归 lr LogisticRegression(max_iter1000, multi_classmultinomial, random_state42) lr.fit(X_train_scaled, y_train) lr_pred lr.predict(X_test_scaled) print(逻辑回归准确率:, accuracy_score(y_test, lr_pred))每个算法的参数含义需要单独说。MLP 的hidden_layer_sizes(64, 32)表示两层隐藏层第一层 64 个神经元第二层 32 个入门阶段不用堆太深两层足够拟合企鹅数据。solveradam是自适应学习率优化器比 SGD 更容易收敛。KNN 回归的weightsdistance表示距离越近的邻居权重越大比均匀权重更合理。SVM 的kernelrbf是径向基核函数C控制惩罚力度gammascale让 sklearn 自动按特征方差缩放。决策树的max_depth4是预剪枝防止树长得太深过拟合。逻辑回归的multi_classmultinomial表示多分类用 softmax而不是一对多。提示MLP 的max_iter500在企鹅数据上通常够用如果看到ConvergenceWarning先调大max_iter或者换solverlbfgs不要一上来就加层数。3. BP 神经网络与 MLP结构、参数与训练过程排查3.1 BP 神经网络结构图背后的三个关键决策搜「bp神经网络结构图」的人多半是在确认输入层、隐藏层、输出层的节点数怎么定。以企鹅数据为例输入层 4 个节点4 个特征输出层 3 个节点3 个类别隐藏层节点数是超参数。常见经验公式是hidden sqrt(input output) alpha其中 alpha 取 1 到 10。但入门阶段不用纠结公式直接试(8,)、(16,)、(32, 16)三组看验证集准确率哪个高。BP 的核心是反向传播前向计算输出算损失链式法则求梯度更新权重。sklearn 的MLPClassifier把这些全封装了但理解backprop的流程对排查问题很重要——比如损失不下降可能是学习率太大导致震荡也可能是激活函数选错导致梯度消失。# 手动观察 MLP 训练过程中的损失曲线 import matplotlib.pyplot as plt mlp MLPClassifier(hidden_layer_sizes(16,), activationrelu, solveradam, learning_rate_init0.001, max_iter300, random_state42) mlp.fit(X_train_scaled, y_train) plt.plot(mlp.loss_curve_) plt.xlabel(Iteration) plt.ylabel(Loss) plt.title(MLP Training Loss Curve) plt.show()loss_curve_是 sklearn 在训练过程中记录的损失值。正常情况应该是一条下降然后趋于平缓的曲线。如果曲线剧烈震荡把learning_rate_init从 0.001 降到 0.0001如果曲线几乎不下降检查数据是否标准化了——未标准化的数据会让梯度更新方向混乱这是新手最常见的翻车点。3.2 MLP 参数怎么调从学习率到正则化MLP 的可调参数比想象中多但入门阶段只需要盯住四个hidden_layer_sizes、activation、learning_rate_init、alpha。alpha是 L2 正则化系数默认 0.0001如果训练集准确率远高于测试集把它调到 0.001 或 0.01。activation在 relu 和 tanh 之间选relu 收敛快但可能出现神经元死亡tanh 更平滑但慢。我一般先用 relu 跑一遍如果效果不好再换 tanh。# 用 GridSearchCV 粗调 MLP 参数 from sklearn.model_selection import GridSearchCV param_grid { hidden_layer_sizes: [(8,), (16,), (32, 16)], alpha: [0.0001, 0.001, 0.01], learning_rate_init: [0.001, 0.01] } grid GridSearchCV(MLPClassifier(max_iter500, random_state42), param_grid, cv5, scoringaccuracy, n_jobs-1) grid.fit(X_train_scaled, y_train) print(最佳参数:, grid.best_params_) print(最佳交叉验证准确率:, grid.best_score_)cv5是 5 折交叉验证n_jobs-1用满所有 CPU 核心。注意 GridSearchCV 在小数据集上很快但如果是 optdigits 手写数字那种 5620 样本、64 维特征的数据参数组合多的时候会跑很久建议先用随机搜索RandomizedSearchCV粗筛。注意MLP 对随机种子敏感同样的参数换一个random_state结果可能差几个百分点。评估时至少跑 3 次取平均不要拿单次结果下结论。4. KNN 回归与 SVM 超平面距离度量与核函数选择4.1 KNN 回归的 K 值怎么定从欠拟合到过拟合KNN 回归的核心参数只有一个n_neighbors。K 太小模型对噪声敏感预测值波动大K 太大模型过于平滑失去局部特征。企鹅数据用体长、喙深、鳍长预测体重K 从 1 试到 20画一条 MSE 曲线就能找到拐点。from sklearn.neighbors import KNeighborsRegressor from sklearn.metrics import mean_squared_error k_values range(1, 21) mse_scores [] for k in k_values: knn KNeighborsRegressor(n_neighborsk, weightsdistance) knn.fit(Xr_train, yr_train) pred knn.predict(Xr_test) mse_scores.append(mean_squared_error(yr_test, pred)) # 找最小 MSE 对应的 K best_k k_values[np.argmin(mse_scores)] print(最佳 K 值:, best_k) print(对应 MSE:, min(mse_scores))这段代码的逻辑是遍历 K 值每次训练一个 KNN 回归器记录测试集 MSE。weightsdistance让近邻的权重按距离倒数加权通常比uniform更稳。如果 MSE 曲线在某个 K 之后开始上升说明模型进入过拟合区间。注意 KNN 不需要训练过程fit只是存数据真正的计算在predict时发生所以大数据集上预测会很慢——这是 KNN 的固有缺陷不是代码写错了。4.2 SVM 超平面与核函数线性不可分时怎么办SVM 的目标是找一个超平面把不同类别的样本分开并且间隔最大化。企鹅数据有三个类别原始空间里线性不可分所以用核函数把数据映射到高维空间。kernelrbf是最常用的非线性核C控制间隔和分类错误的权衡C 大容忍少容易过拟合C 小容忍多容易欠拟合。gamma控制单个样本的影响范围gamma 大影响范围小决策边界复杂gamma 小影响范围大决策边界平滑。from sklearn.svm import SVC from sklearn.model_selection import cross_val_score C_values [0.1, 1, 10, 100] gamma_values [0.001, 0.01, 0.1, 1] for C in C_values: for gamma in gamma_values: svm SVC(kernelrbf, CC, gammagamma, random_state42) scores cross_val_score(svm, X_train_scaled, y_train, cv5) print(fC{C}, gamma{gamma}, 平均准确率{scores.mean():.4f})这段双重循环打印不同 C 和 gamma 组合下的交叉验证准确率。入门阶段不用记网格搜索的完整流程手动跑几组就能看出趋势C 从 0.1 到 100准确率通常先升后降gamma 从 0.001 到 1也是先升后降。最佳组合一般在中间区域。如果数据量再大一些比如 optdigits 手写数字分类SVM 的训练时间会显著增加这时候要考虑用LinearSVC或者降维后再跑。提示SVM 的probabilityTrue会启用概率估计但内部用的是 Platt 缩放训练时间会增加。如果只关心类别预测不要开这个参数。5. 决策树、朴素贝叶斯与逻辑回归可解释性与概率输出5.1 决策树在企鹅数据集上的分裂逻辑决策树的最大优势是可解释性。企鹅数据训练出来的树可以直接打印规则看它先按哪个特征分裂、阈值是多少。max_depth4是预剪枝防止每个叶子节点只有一个样本。criteriongini是基尼不纯度也可以用entropy信息增益。两者在企鹅数据上差异不大但 gini 计算更快。from sklearn.tree import DecisionTreeClassifier, export_text dt DecisionTreeClassifier(max_depth4, criteriongini, random_state42) dt.fit(X_train_scaled, y_train) # 打印决策规则 tree_rules export_text(dt, feature_namesfeature_cols) print(tree_rules) # 查看特征重要性 importances dt.feature_importances_ for name, imp in zip(feature_cols, importances): print(f{name}: {imp:.4f})export_text输出的是纯文本规则比如「如果 flipper_length_mm -0.5 且 bill_depth_mm 0.3则预测 Adelie」。特征重要性告诉你哪个特征对分类贡献最大企鹅数据里通常是flipper_length_mm和bill_length_mm排前两位。如果发现某个特征重要性接近 0可以考虑删掉它再训练简化模型。5.2 朴素贝叶斯与逻辑回归的概率输出对比朴素贝叶斯假设特征之间条件独立这个假设在企鹅数据上显然不成立体长和体重高度相关但它依然能给出不错的分类结果因为分类边界对独立性假设不敏感。逻辑回归不假设独立性直接建模后验概率输出的是每个类别的概率值。两者都可以用predict_proba看概率。from sklearn.naive_bayes import GaussianNB from sklearn.linear_model import LogisticRegression nb GaussianNB() nb.fit(X_train_scaled, y_train) nb_proba nb.predict_proba(X_test_scaled) lr LogisticRegression(max_iter1000, multi_classmultinomial, random_state42) lr.fit(X_train_scaled, y_train) lr_proba lr.predict_proba(X_test_scaled) # 对比前 5 个样本的概率输出 print(朴素贝叶斯概率:) print(nb_proba[:5]) print(逻辑回归概率:) print(lr_proba[:5])朴素贝叶斯的概率输出往往比较极端接近 0 或 1因为它假设特征独立概率连乘后容易饱和。逻辑回归的概率更平滑因为它是直接优化对数似然。如果业务场景需要校准的概率值比如风控评分逻辑回归更合适如果只关心分类结果两者差异不大。逻辑回归的multi_classmultinomial表示用 softmax 处理多分类solverlbfgs是默认优化器数据量大时换saga支持 L1 正则。注意朴素贝叶斯的GaussianNB假设特征服从正态分布如果特征明显偏态比如收入分布先做对数变换再训练。6. 避坑与排查入门代码跑不通的五个常见原因6.1 现象准确率 100%但换一批数据就崩原因数据泄露。最常见的是在划分训练集之前做了标准化或者用全量数据 fit 了 scaler。另一个隐蔽原因是特征里混入了标签相关的列比如用「物种名称」的字符串长度作为特征。解决严格按「先划分再 fit 训练集再 transform 测试集」的顺序。用Pipeline把预处理和模型串起来避免手动操作出错。from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC pipe Pipeline([ (scaler, StandardScaler()), (svm, SVC(kernelrbf, C1.0, gammascale)) ]) pipe.fit(X_train, y_train) print(Pipeline 准确率:, pipe.score(X_test, y_test))6.2 现象MLP 训练时出现 ConvergenceWarning原因迭代次数不够或者学习率太小导致收敛慢。企鹅数据 344 条max_iter200通常够但如果特征未标准化收敛会非常慢。解决先检查是否做了标准化再把max_iter调到 500 或 1000。如果还不行换solverlbfgs它在小数据集上收敛更快。6.3 现象KNN 回归预测值全是同一个数原因K 值太大比如 K 等于样本总数模型退化成全局均值。或者weightsuniform且近邻距离都很远权重没有区分度。解决把 K 降到 5 到 10 之间改用weightsdistance。同时检查特征是否标准化未标准化的特征会让距离计算被大量纲特征主导。6.4 现象SVM 训练时间过长内存爆掉原因RBF 核的复杂度是 O(n²) 到 O(n³)样本量超过一万时非常慢。optdigits 手写数字有 5620 条样本用 RBF 核跑网格搜索会很久。解决先用LinearSVC试线性核如果效果可接受就用线性核。必须用非线性核时先做 PCA 降维或者用Nystroem近似核映射。6.5 现象决策树训练集准确率 100%测试集只有 70%原因过拟合。树长得太深每个叶子节点对应一个训练样本完全没有泛化能力。解决加max_depth、min_samples_split、min_samples_leaf三个参数。入门阶段先设max_depth4min_samples_leaf5再根据验证集表现微调。7. 从入门代码到实战用交叉验证和混淆矩阵做模型验收跑通六个算法只是起点真正决定模型能不能用的是验收环节。我一般会做三件事分层交叉验证看稳定性、混淆矩阵看错分模式、学习曲线看数据量是否足够。以企鹅数据为例用StratifiedKFold做 10 折交叉验证比单次划分可靠得多。from sklearn.model_selection import StratifiedKFold, cross_val_score from sklearn.metrics import confusion_matrix, classification_report import seaborn as sns # 10 折分层交叉验证 cv StratifiedKFold(n_splits10, shuffleTrue, random_state42) models { MLP: MLPClassifier(hidden_layer_sizes(16,), max_iter500, random_state42), SVM: SVC(kernelrbf, C1.0, gammascale, random_state42), DecisionTree: DecisionTreeClassifier(max_depth4, random_state42), NaiveBayes: GaussianNB(), LogisticRegression: LogisticRegression(max_iter1000, random_state42) } for name, model in models.items(): scores cross_val_score(model, X_train_scaled, y_train, cvcv, scoringaccuracy) print(f{name}: 平均准确率{scores.mean():.4f}, 标准差{scores.std():.4f}) # 混淆矩阵 svm SVC(kernelrbf, C1.0, gammascale, random_state42) svm.fit(X_train_scaled, y_train) y_pred svm.predict(X_test_scaled) cm confusion_matrix(y_test, y_pred) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsle.classes_, yticklabelsle.classes_) plt.xlabel(Predicted) plt.ylabel(Actual) plt.title(SVM Confusion Matrix) plt.show() print(classification_report(y_test, y_pred, target_namesle.classes_))交叉验证的标准差很重要。如果某个模型平均准确率 0.95 但标准差 0.08说明它在某些折上表现很差稳定性不够。混淆矩阵能看出哪个类别容易被错分——企鹅数据里 Chinstrap 和 Adelie 容易混因为它们的喙长和喙深有重叠。classification_report给出每个类别的 precision、recall、f1-score比单一准确率更有参考价值。学习曲线用来判断「更多数据是否有帮助」。如果训练集准确率和验证集准确率都低说明模型欠拟合加数据没用要加特征或换模型如果训练集高、验证集低说明过拟合加数据可能有帮助。from sklearn.model_selection import learning_curve train_sizes, train_scores, val_scores learning_curve( SVC(kernelrbf, C1.0, gammascale, random_state42), X_train_scaled, y_train, cv5, n_jobs-1, train_sizesnp.linspace(0.1, 1.0, 10) ) plt.plot(train_sizes, train_scores.mean(axis1), labelTraining score) plt.plot(train_sizes, val_scores.mean(axis1), labelValidation score) plt.xlabel(Training examples) plt.ylabel(Accuracy) plt.legend() plt.show()这套验收流程跑下来基本能判断一个模型是「真的能用」还是「碰巧跑通」。我自己的习惯是任何模型上线前至少跑一次 10 折交叉验证加混淆矩阵单次划分的结果只用来快速筛选不用来做最终决策。入门代码的价值不在于跑出多高的准确率而在于让你把「数据→模型→评估→调参」的闭环走顺后面换数据集、换算法只是替换中间那几行调用。希望帮到你。本文还有配套的精品资源点击获取
返回列表