简介这份资源是面向计算机相关专业在校学生、教师及企业员工的期末大作业与课程设计资料包围绕对数几率回归模型实现西瓜与鸢尾花数据集的识别分类任务展开适合作为机器学习入门进阶练习也可直接用于毕设、课程设计或初期项目立项演示。压缩包共30个文件约544KB包含6个Python源码文件、4个Jupyter Notebook、2份Word作业报告、2份Markdown项目说明以及xml、iml等IDE配置文件和pyc缓存文件源码附带详细注释便于理解算法实现与调试过程。目前已有296人学习下载。读者可获得完整的对数几率回归建模流程、数据预处理与分类评估代码、可直接提交的作业报告模板以及清晰的目录结构既能对照复现实验也方便在此基础上进行二次开发与功能拓展。1. 对数几率回归做西瓜鸢尾花分类期末大作业里最容易被低估的一行代码很多人拿到「基于对数几率回归模型实现西瓜鸢尾花识别分类」这个题目第一反应是逻辑回归太简单了sklearn 三行代码就能跑完期末大作业写这个是不是显得没水平我当年也这么想直到帮学弟调他的作业报告才发现真正翻车的地方根本不在模型本身——他把西瓜数据集和鸢尾花数据集混在一起读特征列对不上准确率一直在 0.33 附近晃他还以为是逻辑回归不适合多分类。对数几率回归Logistic Regression本质是线性分类器套一个 Sigmoid 映射二分类是它的主场多分类要靠 One-vs-Rest 或 Softmax 扩展。西瓜数据集是二分类好瓜/坏瓜鸢尾花是三分类三种花两个任务放在一份作业里恰好覆盖了从二分类到多分类的完整链路。这篇笔记面向正在做这个期末大作业、或者想拿它当 Python 入门练手项目的人把数据读取、模型训练、参数调节、报告撰写和注释规范整条路径讲清楚让你交上去的东西经得起追问。2. 先搞清楚两个数据集的结构差异西瓜二分类和鸢尾花三分类不是一回事2.1 西瓜数据集 3.0 的字段含义与标签编码西瓜数据集 3.0 是周志华《机器学习》里的经典数据共 17 个样本每个样本有 8 个特征色泽、根蒂、敲声、纹理、脐部、触感、密度、含糖率。前 6 个是离散字符串后 2 个是连续数值。标签是「好瓜」和「坏瓜」。很多人直接把这个数据集丢给逻辑回归会报could not convert string to float的错误因为 sklearn 不接受字符串特征。常见做法是先用 pandas 读入然后对离散列做映射编码。注意不要用 OneHotEncoder 无脑展开17 个样本展开成几十维反而容易过拟合。我一般用简单的字典映射把「青绿/乌黑/浅白」映射成 0/1/2这样既保留了序关系又不会维度爆炸。import pandas as pd import numpy as np # 读取西瓜数据集假设文件为 watermelon3.0.csv df pd.read_csv(watermelon3.0.csv, encodingutf-8) # 离散特征映射字典按语义顺序编码 color_map {青绿: 0, 乌黑: 1, 浅白: 2} root_map {蜷缩: 0, 稍蜷: 1, 硬挺: 2} sound_map {浊响: 0, 沉闷: 1, 清脆: 2} texture_map {清晰: 0, 稍糊: 1, 模糊: 2} umbilicus_map {凹陷: 0, 稍凹: 1, 平坦: 2} touch_map {硬滑: 0, 软粘: 1} df[色泽] df[色泽].map(color_map) df[根蒂] df[根蒂].map(root_map) df[敲声] df[敲声].map(sound_map) df[纹理] df[纹理].map(texture_map) df[脐部] df[脐部].map(umbilicus_map) df[触感] df[触感].map(touch_map) # 标签编码好瓜1坏瓜0 df[好瓜] df[好瓜].map({是: 1, 否: 0}) # 检查缺失值 print(df.isnull().sum())这段代码的关键在于映射字典的顺序要和数据集里的类别一一对应如果映射错了模型学到的就是错的序关系。参数方面encodingutf-8是为了防止中文列名读取乱码如果你在 Windows 上遇到UnicodeDecodeError可以换成gbk试试。isnull().sum()用来确认映射过程中有没有产生 NaN因为如果某个类别没在字典里map 会返回 NaN后续训练直接报错。2.2 鸢尾花数据集的加载与特征标准化鸢尾花数据集在 sklearn 里自带150 个样本4 个连续特征花萼长度、花萼宽度、花瓣长度、花瓣宽度3 个类别各 50 个样本。这个数据集干净得多但有一个坑三个类别的特征分布范围不同花瓣长度和花萼宽度的量纲差异会导致逻辑回归的梯度下降收敛慢。我一般会做标准化把均值归到 0、方差归到 1。from sklearn.datasets import load_iris from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split # 加载鸢尾花数据集 iris load_iris() X, y iris.data, iris.target # 标准化逻辑回归对特征尺度敏感标准化能加速收敛 scaler StandardScaler() X_scaled scaler.fit_transform(X) # 划分训练集和测试集stratify 保证类别比例一致 X_train, X_test, y_train, y_test train_test_split( X_scaled, y, test_size0.3, random_state42, stratifyy ) print(f训练集样本数: {X_train.shape[0]}, 测试集样本数: {X_test.shape[0]}) print(f类别分布: {np.bincount(y_train)})StandardScaler的fit_transform只能在训练集上做测试集要用训练集的均值和方差来transform否则就是数据泄露。stratifyy保证划分后每个类别的比例和原始一致150 个样本按 7:3 划分后训练集每类 35 个测试集每类 15 个。random_state42固定随机种子保证你每次跑出来的结果一样报告里写准确率才有意义。提示西瓜数据集样本太少标准化后反而可能放大噪声建议只对连续特征「密度」和「含糖率」做标准化离散特征保持原样。3. 对数几率回归的两种实现路径手写梯度下降和 sklearn 调包3.1 手写二分类逻辑回归的梯度下降期末大作业如果只调包报告里没什么可写的。我建议至少手写一遍二分类的逻辑回归把 Sigmoid、交叉熵损失、梯度更新这三个核心公式落到代码里。这样报告里可以画损失曲线老师一看就知道你真懂了。def sigmoid(z): # 防止 exp 溢出对 z 做截断 z np.clip(z, -500, 500) return 1.0 / (1.0 np.exp(-z)) def train_logistic_regression(X, y, lr0.1, epochs1000): 手写二分类逻辑回归训练 X: 特征矩阵 (n_samples, n_features) y: 标签向量 (n_samples,) lr: 学习率 epochs: 迭代次数 返回: 权重 w, 偏置 b, 损失历史 n_samples, n_features X.shape w np.zeros(n_features) b 0.0 loss_history [] for i in range(epochs): # 前向传播 z np.dot(X, w) b y_pred sigmoid(z) # 交叉熵损失加 1e-9 防止 log(0) loss -np.mean(y * np.log(y_pred 1e-9) (1 - y) * np.log(1 - y_pred 1e-9)) loss_history.append(loss) # 梯度计算 dw np.dot(X.T, (y_pred - y)) / n_samples db np.mean(y_pred - y) # 参数更新 w - lr * dw b - lr * db return w, b, loss_history学习率lr是最关键的参数设 0.1 在标准化后的数据上一般能收敛如果损失曲线震荡就降到 0.01如果下降太慢就升到 0.5 试试。epochs设 1000 通常够用你可以画loss_history看它什么时候趋于平稳。np.clip(z, -500, 500)是防止np.exp溢出这是血泪经验不加上去在某些样本上会直接报RuntimeWarning: overflow。3.2 sklearn 的 LogisticRegression 多分类参数鸢尾花是三分类sklearn 的LogisticRegression默认用multi_classauto在数据量小的时候会选 OvR数据量大且类别多的时候选 Softmax。你可以显式指定multi_classmultinomial来强制用 Softmax配合solverlbfgs或solversaga。from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score, classification_report # 多分类逻辑回归使用 Softmax 回归 clf LogisticRegression( multi_classmultinomial, solverlbfgs, C1.0, max_iter1000, random_state42 ) clf.fit(X_train, y_train) y_pred clf.predict(X_test) print(f准确率: {accuracy_score(y_test, y_pred):.4f}) print(classification_report(y_test, y_pred, target_namesiris.target_names))C是正则化强度的倒数默认 1.0越小正则化越强。如果报告里发现训练集准确率远高于测试集说明过拟合把C降到 0.1 或 0.01。max_iter默认 100在鸢尾花上可能不收敛设 1000 比较稳。classification_report会输出每个类别的精确率、召回率和 F1报告里直接贴这个表比只写一个准确率有说服力得多。3.3 西瓜数据集上的二分类验证西瓜数据集只有 17 个样本用留一法交叉验证比 train_test_split 更合理因为随机划分可能导致某一类在测试集里一个都没有。from sklearn.model_selection import LeaveOneOut from sklearn.linear_model import LogisticRegression # 准备西瓜数据 X_wm df[[色泽, 根蒂, 敲声, 纹理, 脐部, 触感, 密度, 含糖率]].values y_wm df[好瓜].values loo LeaveOneOut() acc_list [] for train_idx, test_idx in loo.split(X_wm): X_tr, X_te X_wm[train_idx], X_wm[test_idx] y_tr, y_te y_wm[train_idx], y_wm[test_idx] model LogisticRegression(max_iter500) model.fit(X_tr, y_tr) acc_list.append(model.score(X_te, y_te)) print(f留一法平均准确率: {np.mean(acc_list):.4f})留一法每次只留一个样本做测试17 个样本跑 17 次最终准确率是 17 次的平均。这个数字在报告里比单次划分更可信。注意西瓜数据集样本少准确率波动大0.7 到 0.9 之间都算正常不要为了追求高准确率去调参数调到过拟合。4. 避坑与排查逻辑回归作业里最容易翻车的 5 个地方4.1 准确率一直上不去检查标签编码是否反了现象模型训练完准确率在 0.3 到 0.5 之间比随机猜还差。原因标签映射时把「好瓜」映射成 0、「坏瓜」映射成 1但预测时又按 1 是好瓜来解读导致精确率和召回率对调。解决统一标签编码规范在代码开头用注释写清楚0坏瓜, 1好瓜所有评估指标都按这个约定解读。4.2 报错 could not convert string to float现象fit的时候直接抛ValueError: could not convert string to float: 青绿。原因西瓜数据集的离散列没有做编码直接传给了 sklearn。解决在fit之前用df.select_dtypes(includeobject).columns检查还有哪些字符串列逐一映射。如果懒得手动映射可以用pd.get_dummies做 OneHot 编码但 17 个样本展开后维度太高不推荐。4.3 损失曲线不下降或者震荡现象手写梯度下降时loss_history一直在 0.69 附近不动或者上下大幅震荡。原因学习率设得太大导致震荡或者特征没有标准化导致梯度尺度差异大。解决先把学习率降到 0.01 试如果下降太慢再逐步升到 0.1、0.3。同时确认连续特征做了标准化西瓜数据集的「密度」在 0.3 到 0.8 之间「含糖率」在 0.05 到 0.45 之间量纲接近但鸢尾花的花瓣长度在 1 到 7 之间不标准化会影响收敛。4.4 多分类时 predict_proba 返回的列数不对现象鸢尾花三分类predict_proba返回的却是两列。原因multi_class参数设成了ovr且某个类别被当成正类、其余合并成负类。解决显式设multi_classmultinomial并且确认solver支持多分类lbfgs和saga都支持liblinear不支持多分类。4.5 作业报告里注释太少被扣分现象代码能跑但报告分数不高老师评语写「注释不足可读性差」。原因只写了# 导入库这种无意义注释没有解释参数含义和设计决策。解决每个函数写 docstring说明输入输出和关键参数每个映射字典旁边写清楚类别顺序每个超参数写一行注释说明为什么选这个值。参考 Python 文档注释规范用写函数说明用#写行内说明。注意不要用# -*- coding: utf-8 -*-这种老式编码声明Python 3 默认就是 UTF-8写了反而显得不专业。5. 报告撰写与注释规范让大作业从及格线拉到优秀5.1 作业报告的结构模板期末大作业的报告一般包括问题描述、数据集说明、方法原理、实验设置、结果分析、结论。我建议在「方法原理」部分把对数几率回归的公式推导写清楚从线性回归到 Sigmoid 映射从极大似然估计到交叉熵损失从梯度推导到参数更新。这部分不用太长一页纸足够但公式要自己敲不要截图。「实验设置」部分要写清楚训练集测试集划分比例、随机种子、标准化方法、超参数取值。这些细节决定了你的实验能不能被复现。「结果分析」部分除了准确率还要放混淆矩阵和分类报告鸢尾花三分类的混淆矩阵能看出哪个类别容易混。from sklearn.metrics import confusion_matrix import seaborn as sns import matplotlib.pyplot as plt # 绘制混淆矩阵 cm confusion_matrix(y_test, y_pred) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsiris.target_names, yticklabelsiris.target_names) plt.xlabel(预测类别) plt.ylabel(真实类别) plt.title(鸢尾花分类混淆矩阵) plt.tight_layout() plt.savefig(confusion_matrix.png, dpi150)fmtd表示显示整数cmapBlues是配色方案dpi150保证图片清晰度够打印。保存图片而不是只show是因为报告里要插入图片直接截图会有白边。5.2 代码注释的三个层次第一层是模块级注释在文件开头写清楚这个脚本做什么、依赖哪些库、数据文件放在哪里。第二层是函数级注释用 docstring 写清楚输入参数的类型和含义、返回值的结构。第三层是行内注释只在对非直观操作做解释时写比如「对 z 做截断防止 exp 溢出」这种。 西瓜鸢尾花分类作业 依赖: pandas, numpy, sklearn, matplotlib, seaborn 数据: watermelon3.0.csv 放在同目录下 运行: python classification.py 这种模块级注释看起来简单但很多同学交上来的代码连文件名和运行方式都没写老师想跑都跑不起来。加上这三行印象分直接拉满。5.3 参数调优的记录方式报告里不要只写「最终准确率 0.95」要写「在 C1.0 时准确率 0.93C0.1 时 0.95C0.01 时 0.91最终选 C0.1」。用一个表格记录不同参数下的结果比一段文字描述清楚得多。C 值训练集准确率测试集准确率备注0.010.900.91正则化过强欠拟合0.10.960.95最佳1.00.990.93轻微过拟合10.01.000.91过拟合明显这张表放在报告里老师一眼就能看出你做了调参实验而不是随便跑了一次就交。注意训练集准确率和测试集准确率的差距差距越大过拟合越严重。5.4 用交叉验证替代单次划分如果想让结果更稳可以用cross_val_score做 5 折交叉验证报告里写「5 折交叉验证平均准确率 0.95±0.03」比单次划分的 0.95 更有说服力。from sklearn.model_selection import cross_val_score clf_cv LogisticRegression(multi_classmultinomial, solverlbfgs, C0.1, max_iter1000, random_state42) scores cross_val_score(clf_cv, X_scaled, y, cv5, scoringaccuracy) print(f5折交叉验证: {scores.mean():.4f} ± {scores.std():.4f})cv5表示 5 折scoringaccuracy表示用准确率评估。scores.std()是标准差越小说明模型越稳定。如果标准差超过 0.05说明数据划分对结果影响大报告里要说明这一点。5.5 最后检查一遍这些细节交作业之前我一般会过一遍这个清单代码能不能在干净环境里跑通把__pycache__删掉重跑、数据文件路径是不是相对路径、有没有硬编码的绝对路径、图片有没有保存到正确目录、报告里的数字和代码输出是否一致。这些细节看起来琐碎但每年都有同学因为路径写死在自己电脑上老师一跑就报FileNotFoundError直接扣分。我自己的习惯是在项目根目录放一个requirements.txt写清楚依赖库和版本虽然期末大作业不一定要求但加上去显得规范。另外代码里不要出现print调试语句残留交之前全局搜一下print该删的删该改成日志的改成日志。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?