简介:这份资源是2023年春季复旦大学人工智能A实验课程的学习资料包,由马成整理,面向正在学习人工智能基础实验的高校学生与自学者,可用于复现课程实验、理解机器学习与深度学习的基本流程。压缩包共52个文件,以43个Python脚本为核心,配合4份Markdown说明、3份PDF实验报告与项目文档以及2个嵌套压缩包,整体约2.35MB,体量轻便、便于按实验模块检索。内容围绕lab1、lab2等实验展开,涵盖数据集处理、NER等具体任务,并附有Project与实验报告,能帮助读者对照代码理解算法实现思路、梳理实验步骤与结果分析。目前已有109人学习下载,适合需要参考完整实验代码与报告结构、查漏补缺的读者使用。
1. 一份 AI 实验包拆开来看:Python 零基础也能跑通的第一课
拿到一个名为“人工智能A实验”的压缩包,很多人的第一反应是:里面是不是一堆看不懂的公式推导和半成品代码?我拆过不少高校实验包,这类资源最典型的结构是“讲义 + 骨架代码 + 数据集 + 实验报告模板”四件套,真正值钱的是那套能跑通的骨架代码和配套数据。它解决的核心问题不是教你从零推导反向传播,而是让你在 Python 环境里亲手把数据读进来、把模型搭起来、把结果画出来,形成一条完整的实验闭环。适合谁?适合刚接触人工智能课程、需要交实验报告但卡在环境配置和代码调试上的学生,也适合想用最短时间摸清一个分类任务全流程的转行者。下面我按“环境怎么搭、代码怎么跑、参数怎么调、坑在哪”的顺序,把这份资源拆成能照着复现的步骤。
2. 环境与依赖:把 Python 实验的底座先焊死
2.1 为什么优先用 conda 而不是系统 Python
实验包里的代码通常依赖 numpy、matplotlib、scikit-learn 这几个库,版本不匹配是新手翻车的第一大来源。系统自带的 Python 往往被操作系统占用,你 pip install 装进去的包可能和系统工具冲突,轻则报错重则环境崩掉。常见做法是用 conda 建一个独立环境,把实验所需的解释器和依赖锁在一起,删掉环境就干净卸载,不留后患。
先确认本机有没有 conda,没有的话装一个轻量版即可。建环境时指定 Python 版本,实验包如果没写版本要求,3.9 或 3.10 是兼容性最稳的选择,太新的 3.12 有时会让老版本 numpy 编译失败。
# 创建名为 ai-lab 的独立环境,指定 Python 3.10 conda create -n ai-lab python=3.10 -y # 激活环境,后续所有命令都在这个环境里执行 conda activate ai-lab # 验证解释器路径,确认指向 conda 环境而非系统 Python which python-n ai-lab是环境名,你可以改成任何名字,但建议和项目挂钩方便识别。which python这步别省,很多人激活失败却以为成功了,结果 pip 装到系统环境里,跑代码时依然报 ModuleNotFoundError。激活成功的标志是命令行前缀出现(ai-lab)。
2.2 依赖安装与版本锁定
实验包一般会带一个 requirements.txt,但高校实验包的依赖文件经常写得很随意,只写包名不写版本。直接pip install -r requirements.txt可能装到最新版,而最新版 API 和老代码对不上。我的习惯是先看代码里 import 了什么,再手动装核心三件套并锁版本。
# 核心依赖,版本按实验包代码实际调用情况选 pip install numpy==1.24.3 matplotlib==3.7.2 scikit-learn==1.3.0 # 如果实验涉及深度学习框架,再补装(按需,不是所有实验都要) # pip install torch==2.0.1 torchvision==0.15.2 # 导出实际安装版本,方便写进实验报告的环境说明 pip freeze > env_locked.txtnumpy 锁 1.24 是因为 1.25 之后部分旧接口有弃用警告,matplotlib 3.7 对中文显示的支持相对稳定。pip freeze导出的文件比原始 requirements.txt 更可信,实验报告里附上它,答辩时被问环境问题能直接甩出来。装完跑一句python -c "import numpy, sklearn; print(numpy.__version__, sklearn.__version__)"验证,能打印出版本号才算底座焊死。
3. 数据读取与预处理:实验包里的数据到底怎么喂进模型
3.1 先摸清数据文件的组织方式
实验包的数据通常放在 data 目录下,格式无非 csv、txt 或图片文件夹。动手写代码前先做一件事:用命令行把目录结构和文件数量看清楚,别上来就写读取逻辑。很多实验包的 csv 没有表头,或者分隔符是分号不是逗号,直接 pandas 默认参数读会得到一列乱码。
# 查看数据目录结构,确认文件层级 ls -R data/ # 看 csv 前几行,判断有没有表头、分隔符是什么 head -n 5 data/dataset.csv # 统计样本数量,心里有个数 wc -l data/dataset.csvhead输出如果第一行是纯数字,说明没表头,pandas 读取时要加header=None。如果字段之间是分号,要加sep=';'。wc -l的行数减一是实际样本数(有表头时),这个数字后面划分训练测试集要用到,先记下来。
3.2 用 pandas 读数据并做基础清洗
读取阶段最容易翻车的是缺失值和异常值。实验数据往往是从真实场景截取的,空单元格、重复行、超出量纲的离群点都可能存在。下面这段是通用的读取加清洗骨架,参数按你的数据实际情况改。
import pandas as pd import numpy as np # 读取数据,header=None 表示无表头,sep 按实际分隔符改 df = pd.read_csv('data/dataset.csv', header=None, sep=',') # 给列起名,方便后续引用;列数按实际字段数调整 df.columns = [f'f{i}' for i in range(df.shape[1] - 1)] + ['label'] # 查看缺失值分布,决定是删还是填 print(df.isnull().sum()) # 数值列用中位数填充,比均值抗离群点 num_cols = df.select_dtypes(include=[np.number]).columns df[num_cols] = df[num_cols].fillna(df[num_cols].median()) # 去重,避免重复样本污染训练集 df = df.drop_duplicates().reset_index(drop=True) print('清洗后样本数:', len(df))header=None和sep是最关键的两个参数,读错这两个后面全白搭。fillna(median())用中位数而不是均值,是因为实验数据里常有极端值,均值会被拉偏。drop_duplicates去重后一定要reset_index(drop=True),否则索引断层会让后面的 iloc 切片出错。清洗完打印样本数,和前面wc -l的结果对一下,差太多说明清洗逻辑有问题。
3.3 特征标准化与数据集划分
分类任务里,特征量纲不一致会直接拖垮基于距离的模型。标准化放在划分之后做,用训练集的均值和方差去变换测试集,这是防止数据泄露的铁律。实验包里如果代码是先标准化再划分,那是个隐藏 bug,得改。
from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler X = df.drop(columns=['label']).values y = df['label'].values # 先划分,random_state 固定保证可复现 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) # 只在训练集上 fit,测试集只 transform scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test) print('训练集:', X_train.shape, '测试集:', X_test.shape)stratify=y保证训练测试集里各类别比例一致,样本不均衡时必加。random_state=42是约定俗成的种子,换成别的数字结果会变,实验报告里写清楚用的哪个种子,别人才能复现。fit_transform只对训练集用,测试集用transform,这个顺序错了,测试集信息就泄露进训练过程,准确率虚高,答辩时被追问会很难看。
4. 模型搭建与训练:从骨架代码到能出结果的完整链路
4.1 选哪个模型:先跑通再谈优化
实验包的骨架代码通常会给一个基础模型,常见的是逻辑回归或简单的多层感知机。新手容易犯的错是一上来就想换复杂模型,结果连基础流程都没跑通。我的建议是先用骨架里的默认模型跑出第一组结果,确认数据管道没问题,再考虑换模型对比。下面以逻辑回归为例,它是分类任务的基线,训练快、可解释性强,适合验证流程。
from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score, classification_report # max_iter 调大避免不收敛警告,C 是正则化强度的倒数 clf = LogisticRegression(max_iter=1000, C=1.0, random_state=42) clf.fit(X_train, y_train) # 预测并评估 y_pred = clf.predict(X_test) print('准确率:', accuracy_score(y_test, y_pred)) print(classification_report(y_test, y_pred))max_iter=1000是因为默认 100 在标准化后的高维数据上经常不收敛,会刷一屏 ConvergenceWarning,不是错误但看着烦。C控制正则化强度,C 越小正则越强,过拟合时调小,欠拟合时调大。classification_report输出每个类别的精确率、召回率、F1,比单一准确率信息量大得多,样本不均衡时准确率会骗人,一定要看这个报告。
4.2 训练过程的可视化:让实验报告有图可放
实验报告光有数字不够,学习曲线和混淆矩阵是加分项。学习曲线能看出模型是过拟合还是欠拟合,混淆矩阵能看出哪两类容易混。这两张图用 matplotlib 画,代码不长但很出效果。
import matplotlib.pyplot as plt from sklearn.metrics import ConfusionMatrixDisplay # 混淆矩阵 fig, ax = plt.subplots(figsize=(6, 5)) ConfusionMatrixDisplay.from_predictions(y_test, y_pred, ax=ax, cmap='Blues') ax.set_title('Confusion Matrix') plt.tight_layout() plt.savefig('confusion_matrix.png', dpi=150) plt.close() # 学习曲线:看训练集和验证集得分随样本量的变化 from sklearn.model_selection import learning_curve train_sizes, train_scores, val_scores = learning_curve( clf, X_train, y_train, cv=5, scoring='accuracy', train_sizes=np.linspace(0.1, 1.0, 8), random_state=42 ) plt.plot(train_sizes, train_scores.mean(axis=1), label='train') plt.plot(train_sizes, val_scores.mean(axis=1), label='validation') plt.xlabel('Training samples'); plt.ylabel('Accuracy'); plt.legend() plt.savefig('learning_curve.png', dpi=150) plt.close()ConfusionMatrixDisplay.from_predictions是 sklearn 较新版本才有的便捷接口,老版本要用confusion_matrix加手动imshow,版本对不上会报 AttributeError,这也是前面锁版本的原因之一。cv=5是五折交叉验证,train_sizes从 10% 到 100% 取 8 个点,点太多跑得慢,8 个够画曲线了。两条曲线如果训练集得分高、验证集得分低且差距大,就是过拟合;两条都低且贴近,就是欠拟合。这个判断写进实验报告的分析部分,比干巴巴贴准确率有说服力。
4.3 参数怎么调:网格搜索的实用配置
骨架代码给的默认参数往往不是最优的,实验报告里如果有调参环节,用 GridSearchCV 做一轮小范围搜索就够,不用上贝叶斯优化那种重武器。搜索空间别开太大,否则跑一晚上出不来结果。
from sklearn.model_selection import GridSearchCV # 搜索空间:C 取三个量级,solver 两种 param_grid = { 'C': [0.01, 0.1, 1.0, 10.0], 'solver': ['lbfgs', 'liblinear'] } grid = GridSearchCV( LogisticRegression(max_iter=1000, random_state=42), param_grid, cv=5, scoring='f1_weighted', n_jobs=-1 ) grid.fit(X_train, y_train) print('最优参数:', grid.best_params_) print('交叉验证最优得分:', grid.best_score_)scoring='f1_weighted'而不是默认的 accuracy,是因为加权 F1 对类别不均衡更鲁棒。n_jobs=-1用满所有 CPU 核心,4 组 C 乘 2 种 solver 再乘 5 折,一共 40 次训练,不开并行会等很久。搜索空间里C取了对数刻度上的四个点,覆盖弱正则到强正则,solver选 lbfgs 和 liblinear 是因为它们对中小规模数据都够快,saga 那种适合大数据集的没必要上。搜完把best_params_写进报告,说明为什么选这组参数,比只贴一个准确率数字完整得多。
5. 避坑与排查:实验包里最容易翻车的五个地方
5.1 中文乱码:matplotlib 画图全是方块
现象:图表标题和坐标轴标签里的中文显示成一个个方框,控制台还刷UserWarning: Glyph missing。原因:matplotlib 默认字体不含中文字形,系统里装了中文字体但没告诉 matplotlib 用哪个。解决:在画图代码开头显式指定字体,Windows 和 macOS 的字体名不一样,按平台选。
import matplotlib.pyplot as plt import platform if platform.system() == 'Windows': plt.rcParams['font.sans-serif'] = ['SimHei'] else: plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] plt.rcParams['axes.unicode_minus'] = False # 负号正常显示axes.unicode_minus=False这行别漏,否则负号也会变方块。字体名写错不会报错,只是继续显示方块,所以设完先画个带中文的测试图确认。
5.2 路径问题:相对路径在 IDE 里能跑、命令行里报错
现象:在 IDE 里点运行一切正常,切到终端python main.py就报 FileNotFoundError。原因:IDE 的工作目录默认是项目根目录,终端的工作目录是你当前所在目录,相对路径data/dataset.csv的解析基准不同。解决:用os.path基于脚本文件位置拼绝对路径,或者统一在项目根目录下执行命令。
import os BASE_DIR = os.path.dirname(os.path.abspath(__file__)) data_path = os.path.join(BASE_DIR, 'data', 'dataset.csv')__file__是当前脚本路径,abspath转绝对路径,dirname取所在目录,这样不管从哪执行都能找到数据。这是最稳的写法,实验包里如果用的是裸相对路径,建议改掉。
5.3 版本不兼容:sklearn 接口改名导致 AttributeError
现象:from sklearn.metrics import plot_confusion_matrix报 ImportError。原因:这个接口在 sklearn 1.0 之后被弃用,1.2 之后移除,换成了ConfusionMatrixDisplay.from_predictions。解决:要么降 sklearn 版本到 0.24,要么改代码用新接口。我倾向改代码,降版本会牵连其他依赖。判断方法很简单,报错信息里带was deprecated或has been removed就是版本问题,去官方文档查对应版本的替代接口。
5.4 内存溢出:一次性读入大文件把内存吃满
现象:读取数据时进程被系统杀掉,或者报 MemoryError。原因:实验数据如果是几十万行乘几百列,pandas 默认用 float64 存储,内存占用是实际数据量的好几倍。解决:读取时指定 dtype 降精度,或者用 chunksize 分块处理。
# 指定 float32 降一半内存,只读需要的列 df = pd.read_csv('data/dataset.csv', dtype='float32', usecols=range(20))usecols只读需要的列,实验数据里常有一堆无关字段,砍掉能省不少内存。dtype='float32'精度对分类任务足够,内存直接减半。如果还是不够,就上chunksize=10000分块迭代,每块处理完再读下一块。
5.5 结果不可复现:每次跑准确率都不一样
现象:同样的代码跑两次,准确率差好几个百分点。原因:没固定随机种子,数据划分、模型初始化、交叉验证的折分都带随机性。解决:在数据划分、模型构造、交叉验证三处都设random_state,并在报告里写明种子值。numpy 全局种子也设一下,np.random.seed(42),有些底层操作会用到它。这三处种子固定后,同一台机器上结果完全一致,换机器可能因底层库版本差异有微小浮动,属正常范围。
6. 进阶技巧:把实验包改造成自己的作品集
跑通骨架代码只是及格线,真正让这份资源产生复利的是把它改造成能展示你能力的作品。我的做法是保留数据管道,替换模型层做横向对比,再用交叉验证的统计结果说话。具体来说,在同一个训练测试划分上跑逻辑回归、随机森林、支持向量机三个模型,记录各自的准确率和 F1,用表格汇总。这样实验报告里就有一组对比数据,而不是孤零零一个模型的结果。
| 模型 | 准确率 | 加权 F1 | 训练耗时(s) |
|---|---|---|---|
| 逻辑回归 | 待填 | 待填 | 待填 |
| 随机森林 | 待填 | 待填 | 待填 |
| 支持向量机 | 待填 | 待填 | 待填 |
表格里的数字自己跑出来填,别抄别人的,数据不同结果不同。随机森林用n_estimators=100起步,支持向量机用SVC(kernel='rbf'),三个模型都套同一个cross_val_score做五折验证,取均值加减标准差,这样对比才有统计意义。耗时用time.time()前后差值记录,能直观看出复杂度差异。
另一个技巧是把预处理和模型串成 Pipeline,这样交叉验证时预处理只在每折的训练部分 fit,彻底杜绝数据泄露,代码也更干净。
from sklearn.pipeline import Pipeline from sklearn.ensemble import RandomForestClassifier pipe = Pipeline([ ('scaler', StandardScaler()), ('clf', RandomForestClassifier(n_estimators=100, random_state=42)) ]) scores = cross_val_score(pipe, X, y, cv=5, scoring='f1_weighted') print('五折 F1:', scores.mean().round(4), '±', scores.std().round(4))Pipeline 的好处是把标准化和模型绑成一个整体,cross_val_score内部会自动在每折训练集上 fit scaler,测试折只 transform,不用你手动管顺序。scores.std()是五折之间的波动,标准差大说明模型对数据划分敏感,稳定性差,这个指标写进报告比单看均值专业。
最后说个血泪经验:实验包里的代码能跑通不代表逻辑正确,我见过骨架代码把fit_transform用在测试集上的,也见过标签编码和特征混在一起标准化的。跑通之后一定要逐行读一遍数据流,确认没有信息泄露,确认评估指标和任务类型匹配。从那以后我每次拿到实验包,都先把数据管道单独抽出来跑一遍小样本,确认输入输出形状和数值范围合理,再往下接模型。希望帮到你。
本文还有配套的精品资源,点击获取