
总有朋友问我同一个问题想用 Python 做人工智能到底先学 scikit-learn 还是 TensorFlow我的回答每次都一样——别选两个都得学。这篇文章记录的是我从零开始用 scikit-learn、TensorFlow 和 Keras 三个库搭智能系统的完整过程包含环境配置、两个能跑通的入门项目、以及我踩过的真实坑。不管你之前用什么语言只要你懂点 Python 基础想把算法落到真实数据上这套流程可以直接照着抄。我会把项目拆成经典机器学习 深度学习两条路线先用 scikit-learn 做一个可解释的预测模型再用 TensorFlow/Keras 训练一个神经网络做图像识别。两个项目跑完你不仅知道这三个库各自干什么还能明白什么时候该用谁数据处理和模型评估的坑在哪里。这是系列第一篇定位是从 0 到 1 把完整流程跑通。1. 这套组合拳到底解决什么问题三个库的定位与分工1.1 三个库之间的真实关系很多人第一次接触 AI 会被工具搞晕scikit-learn 是干啥的TensorFlow 和 Keras 又是什么关系我用一句直白的话说清楚——scikit-learn 管的是传统机器学习TensorFlow 是深度学习框架而 Keras 是 TensorFlow 的高级接口。scikit-learn 解决的问题非常聚焦给定一张表格每行一个样本每列一个特征它提供一堆成熟算法线性回归、随机森林、SVM 等让你做预测或分类。它最大的优点是 API 统一且稳定所有模型都长一个样fit()训练、predict()预测、score()评估。新手学会一个模型其他模型基本无师自通。数据清洗、特征缩放、交叉验证、模型保存这些周边工具也都齐了所以我把 sklearn 当工具箱底座。TensorFlow 则是另一个层级的东西。它最初的设计目标是训练深层神经网络底层张量运算、自动求导、分布式训练这些它都管。问题是直接写底层 API 太痛苦所以 TensorFlow 2.x 把 Keras 吸收为官方高级接口tf.keras。Keras 的思路是搭积木你声明一层、两层、三层像堆乐高一样把模型堆出来然后一行compile编译、一行fit训练。你不需要手动算梯度、写反向传播Keras 全包了。1.2 什么时候该用谁一个选择框架拿装修打比方。scikit-learn 像是家装队负责基础改造和硬装拆墙特征选择、刷墙数据标准化、铺地板基础模型活干得标准、验收容易但你要做定制家居它就不太行了。TensorFlow/Keras 更像定制家具工作室能做出极复杂的东西但不是所有装修需求都需要定制——你只是刷个墙请定制团队就是杀鸡用牛刀。具体到项目里我是这么判断的数据是二维表格样本数量几万以内要求结果能解释——先走 scikit-learn。数据是图像、文本、语音或者样本量几十万上百万特征之间有复杂的非线性关系——走 TensorFlow/Keras。更常见的场景是两者配合scikit-learn 负责数据预处理和把基准结果跑出来Keras 负责上神经网络最后再回到 scikit-learn 的指标工具做对比。这套先基准、再深挖的工作流就是我整个系列的核心方法论后面两个项目都在演示它。1.3 三个库一起用的典型工作流我实际跑项目时流程基本固定成五步用pandas读数据用sklearn.model_selection.train_test_split切分训练集和测试集用sklearn.preprocessing里的工具做归一化、标准化别忘了只对训练集拟合先用一个逻辑回归或线性回归跑出基准分确保管线没毛病如果基准不够好或者数据形态适合深度模型再上 Keras最后用 sklearn 的classification_report、r2_score等方法统一评估两个模型。这套流程最大的好处是每一步都有明确的工具负责不会出现不知道下一步干吗的迷茫。接下来我把环境先搭好。2. 搭建开发环境版本匹配才是第一道坎2.1 选 Python 版本和安装方式别小看环境这一步我见过太多人卡在开头。scikit-learn、TensorFlow 和 Keras 对 Python 版本有各自的支持范围你随便装个最新版 Python有可能装不上某些库。我的建议是Python 3.10 或 3.11这是当前兼容性最稳的区域。TensorFlow 对 Python 版本的跟进比较慢换大版本时经常出现新 Python 装不了旧 TF的尴尬。# 检查当前 Python 版本 python --version如果版本不对去官网下载对应安装包注意勾选Add Python to PATH。这一步很多人忽略导致后面终端里敲python没反应。2.2 用虚拟环境隔离依赖我吃过大亏以前图省事直接往全局环境里pip install tensorflow结果装完把某个旧项目的 numpy 版本顶掉了一堆脚本当场瘫痪。从那以后我每个项目都开独立虚拟环境。# 创建虚拟环境 python -m venv ai_work # 激活Windows ai_work\Scripts\activate # 激活macOS/Linux source ai_work/bin/activate激活成功后命令行前面会出现(ai_work)前缀。后面所有安装和运行代码都在这个环境里互不干扰。2.3 CPU 还是 GPU第一次跑深度学习前的选择如果你是第一次跑 TensorFlow我强烈建议先装 CPU 版。很多人一上来就折腾 GPU结果被 CUDA、cuDNN 版本匹配折磨到怀疑人生。CPU 版装完直接能跑用来学习完全够用。MNIST 这种小数据集CPU 训练一个 epoch 也就几十秒。pip install scikit-learn tensorflow两条命令把三个库都装好。需要注意Keras 不需要单独装TensorFlow 2.x 已经把它内置为tf.keras。你在代码里这么导入import sklearn import tensorflow as tf from tensorflow import keras顺序很重要先import tensorflow再from tensorflow import keras能避免一部分包名冲突问题。关于 GPU等你确定自己要长期训练大模型再回头考虑。届时建议查一下 TensorFlow 官方对 CUDA 版本的适配表照着配不要自己猜。2.4 验证安装是否成功装完别急着写模型先跑个验证脚本确认版本和硬件状态import sklearn import tensorflow as tf from tensorflow import keras print(sklearn:, sklearn.__version__) print(TensorFlow:, tf.__version__) print(Keras:, keras.__version__) print(GPU 设备:, tf.config.list_physical_devices(GPU))如果最后一行是空列表说明走的是 CPU没问题。如果你看到一堆红色的 warning也别慌很多是找不到 GPU或者CPU 指令集优化的提示不影响运行。真正需要警惕的是一上来就报ImportError或ModuleNotFoundError那多半是版本不匹配回到 2.1 检查 Python 版本。到这里环境就绪可以开始第一个项目了。3. 第一个智能系统用 scikit-learn 做一个可解释的预测模型3.1 数据准备用内置数据集快速起步新手最容易卡在找数据上。我建议第一个项目别去爬数据、也别接数据库直接用 scikit-learn 内置数据集零成本起步。这里我用糖尿病数据集diabetes它是一个经典的回归数据集记录了 442 位患者的年龄、血压、血糖等 10 个数值型特征目标是预测病情进展指标。量级小、维度少特别适合演示流程。from sklearn.datasets import load_diabetes data load_diabetes() X, y data.data, data.target print(特征矩阵:, X.shape) print(目标值:, y.shape)输出特征矩阵: (442, 10) 目标值: (442,)看到这种规规矩矩的二维矩阵你就知道这是 sklearn 的主场。把它换成你自己以后的业务数据也是一样最终都要整理成行是样本列是特征的格式。3.2 训练集测试集划分与数据标准化的先后顺序这是网上教程最容易含糊的地方也是我踩过坑的地方。先直接给结论先划分训练集和测试集再做标准化并且标准化器只能拟合训练集。from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 )为什么要先划分因为测试集要充当未来真实数据的角色。如果你在全部数据上做了标准化然后才切分那测试集的均值和方差就已经被训练集污染了这叫信息泄漏。后果是测试评估结果虚高模型上生产环境后立刻现原形。接着做标准化from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)注意这里StandardScaler只有fit_transform用在训练集上测试集只调用transform。两个操作含义完全不同fit_transform是计算均值和标准差然后用它转换transform是直接用已有参数转换。糖尿病数据集的特征范围不大标准化看着影响小但到了量纲差异大的真实数据里这就是决定模型能不能收敛的关键。3.3 训练、评估、可视化一条龙我先上最简单的线性回归不追求最好成绩先把基线跑通from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, r2_score model LinearRegression() model.fit(X_train_scaled, y_train) pred model.predict(X_test_scaled) print(MAE:, mean_absolute_error(y_test, pred)) print(R2:, r2_score(y_test, pred))我跑出来的结果是 MAE 约 45.3R2 约 0.53。意思是模型能解释测试集 53% 的方差对糖尿病这种数据来说算合理毕竟人体指标影响因素太多。光看数字抽象我习惯再画一张预测值 vs 真实值的散点图直观感受模型哪里有偏差import matplotlib.pyplot as plt plt.figure(figsize(6, 6)) plt.scatter(y_test, pred, alpha0.6) plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], r--) plt.xlabel(真实值) plt.ylabel(预测值) plt.title(线性回归预测效果) plt.show()点越贴近那条对角线模型越准。上面部分点明显偏离说明有些样本的特征组合让模型猜不准没关系基准模型的价值在这里已经体现。3.4 模型持久化保存和加载模型训练完不能每次跑都重新训练一遍尤其以后上了大模型训练一次可能几小时。保存模型用joblib最省事import joblib joblib.dump(model, linear_model.pkl) joblib.dump(scaler, scaler.pkl)把标准化器和模型一起保存。下次加载时要先用保存的scaler.transform()处理新数据再喂给model.predict()。漏掉了任一环节预测结果都会出错——这个顺序是我实际踩坑后养成的肌肉记忆。到这里第一个智能系统跑通了数据加载、切分、标准化、训练、评估、可视化、保存完整链路都有了。现在进入第二个项目把同样的思路搬到深度学习上。4. 跨入深度学习用 TensorFlow/Keras 训练第一个神经网络4.1 Keras 在 TensorFlow 2.x 中的正确打开方式很多人分不清 Keras 和 TensorFlow 的使用差异。你在网上搜教程会发现有的代码写from keras.models import Sequential有的写from tensorflow.keras.models import Sequential到底哪个对我的建议永远是用后者。TensorFlow 2.x 之后Keras 是 TensorFlow 的官方内置模块独立安装的 Keras 容易出现版本和 TF 不匹配的问题。统一用tf.keras或from tensorflow import keras最保险。MNIST 手写数字识别是深度学习的Hello World数据本身就是图像6 万张 28x28 像素的灰度图每张图上有一个 0 到 9 的手写数字。这个任务特别适合第一次体验神经网络因为数据自带、量级适中、几秒钟就能看到效果。4.2 构建 MNIST 手写数字识别模型先加载数据from tensorflow import keras from tensorflow.keras import layers (x_train, y_train), (x_test, y_test) keras.datasets.mnist.load_data() print(训练样本:, x_train.shape) print(标签示例:, y_train[:5])输出训练样本: (60000, 28, 28) 标签示例: [5 0 4 1 ...]每个样本是一个 28x28 的二维数组。神经网络吃不了原始像素值需要做两件事一是归一化把像素值从 0~255 缩放到 0~1梯度下降更好收敛。二是转成适合模型的形状。图像是二维的如果用全连接网络需要把它拉平成一维 784 维的向量。x_train x_train.astype(float32) / 255.0 x_test x_test.astype(float32) / 255.0 x_train x_train.reshape(-1, 784) x_test x_test.reshape(-1, 784)接着搭模型。我用 Keras 的Sequential模型这是最简单的方式一层接一层顺序堆叠model keras.Sequential([ layers.Dense(128, activationrelu, input_shape(784,)), layers.Dropout(0.2), layers.Dense(10, activationsoftmax) ]) model.compile( optimizeradam, losssparse_categorical_crossentropy, metrics[accuracy] )逐层解释一下。第一个Dense(128)是全连接层128 个神经元用relu激活。Dropout(0.2)是每次训练随机丢弃 20% 的神经元连接防止过拟合。输出层 10 个神经元对应 0 到 9 十个类别用softmax把输出转成概率分布哪个数字概率最大就是预测结果。losssparse_categorical_crossentropy这里有个细节值得展开之所以用sparse_前缀是因为标签是整数0、1、2...不需要先做 one-hot 编码。如果你的标签已经是 one-hot 形式就得用categorical_crossentropy。搞反了会直接报维度错误这是新手最常见的坑之一。4.3 训练过程中的关键指标解读训练就一行fithistory model.fit( x_train, y_train, epochs5, batch_size32, validation_split0.2 )训练时终端会实时打印每个 epoch 的 loss 和 accuracy以及验证集的表现。我只训练了 5 轮因为这是演示项目5 轮已经足够看到趋势。如果你想效果更好可以加到 10 轮但要注意观察验证集准确率是否还在提升。batch_size32是每次迭代喂给网络 32 张图片32 个样本算一次梯度。validation_split0.2表示拿训练数据的 20% 当验证集每轮结束评估一次顺便观察有没有过拟合。我习惯把训练历史画成曲线看 loss 和 accuracy 的变化趋势import matplotlib.pyplot as plt plt.plot(history.history[accuracy], label训练准确率) plt.plot(history.history[val_accuracy], label验证准确率) plt.xlabel(Epoch) plt.ylabel(Accuracy) plt.legend() plt.show()如果训练准确率在涨但验证准确率停滞甚至下降说明过拟合了。这时可以加 Dropout、降模型复杂度或者增加数据量。这一步看着小却是深度学习调参的核心感觉。4.4 预测结果与可视化评估和预测test_loss, test_acc model.evaluate(x_test, y_test) print(测试集准确率:, test_acc) predictions model.predict(x_test[:10]) predicted_labels predictions.argmax(axis1) print(前 10 张预测结果:, predicted_labels) print(真实标签:, y_test[:10])softmax输出是 10 个概率值argmax(axis1)取概率最大的下标作为最终预测。我实测这个简单模型在测试集上准确率可以到 97% 左右。如果想看模型哪里认错了可以把预测错的样本画出来。我遇到过一个把7认成2的样本放大看确实那条横线写得歪歪扭扭人都不一定认得准。这种图很适合拿去给非技术朋友解释为什么 AI 会犯错。到这里你手里已经有两个能跑的智能系统了。接下来我把两个项目放在一起对比讲讲到底什么时候用哪个。5. 两个项目放在一起怎么选型经典机器学习 vs 深度学习5.1 数据量、特征维度、可解释性三个维度很多人问深度学习是不是一定比传统机器学习厉害我直接说结论不是。两种方法各有一片主场。维度经典机器学习scikit-learn深度学习TensorFlow/Keras数据量要求几千到几万样本可用通常需要几万起步越大越好特征类型表格、数值、类别特征图像、语音、文本、高维稀疏数据可解释性强可看系数、特征重要性弱中间层难以直观解释训练时间秒级到分钟级分钟到小时级GPU 加速更优硬件门槛CPU 即可大数据量需要 GPU这个表不是拍脑袋写的。我在 5.2 节用一个踩坑经历具体说明。5.2 一个踩坑经历拿神经网络硬刚小表格数据有段时间我接到一个某公司的内部项目只有 800 条销售记录、20 个特征目标是预测成交金额。我当时满脑子AI 等于神经网络二话不说搭了个 3 层 Keras 模型上去。结果很丢人训练集准确率飙到 98%测试集 R2 直接跌成负数模型预测的效果比永远猜平均值还差。后来我把同样的数据洗干净丢给 scikit-learn 的RandomForestRegressorR2 反而跑到了 0.61。原因不难理解800 条样本对神经网络来说太少特征的真实规律又基本是线性少量交互这种场景正是随机森林和线性模型的主场。那次之后我给自己定了规矩先跑 sklearn 基准再决定要不要上深度学习。如果基准模型已经不错优先追求可解释性如果基准模型到了瓶颈、数据量又足够大才考虑深度模型。这个习惯救了我很多次也推荐给你。5.3 混合使用用 sklearn 做特征工程用 Keras 做预测经典机器学习和深度学习不是非此即彼我越来越多的项目是混合式。scikit-learn 在特征工程上非常成熟而深度学习需要干净、规范的输入这个组合逻辑很顺。实际做法是用sklearn.preprocessing做标准化和编码用sklearn.model_selection做交叉验证划分然后喂给 Keras 模型。由于 Keras 模型不是 sklearn 标准接口不能直接用cross_val_score我会写一个小适配器类把fit、predict方法包装成 sklearn 风格。from sklearn.base import BaseEstimator, RegressorMixin class KerasRegressorAdapter(BaseEstimator, RegressorMixin): def __init__(self, build_model, epochs10, batch_size32): self.build_model build_model self.epochs epochs self.batch_size batch_size def fit(self, X, y): self.model_ self.build_model() self.model_.fit(X, y, epochsself.epochs, batch_sizeself.batch_size, verbose0) return self def predict(self, X): return self.model_.predict(X).flatten()然后就能直接塞进cross_val_scorefrom sklearn.model_selection import cross_val_score def build_model(): model keras.Sequential([ layers.Dense(64, activationrelu, input_shape(X_train.shape[1],)), layers.Dense(1) ]) model.compile(optimizeradam, lossmse) return model estimator KerasRegressorAdapter(build_modelbuild_model) scores cross_val_score(estimator, X_train_scaled, y_train, cv5, scoringr2) print(交叉验证 R2:, scores.mean())这套组合的好处是你既享受了 sklearn 统一的验证框架又能用 Keras 搭任意复杂的网络。我后来的大部分深度学习项目都是这个模式。6. 跑通两个项目之后我做了一份避坑清单6.1 版本兼容问题先装 TensorFlow 再装其他我在第 2 章提过虚拟环境这里再说一个具体教训。有一次我先装了 scikit-learn 和 pandas再把 TensorFlow 装进去结果 TensorFlow 自动把 numpy 升到了新版本scikit-learn 突然ImportError。原因是 sklearn 编译时依赖特定 numpy API版本跨度太大直接崩。避坑方法在一个干净环境里先pip install tensorflow让它把核心依赖的版本基线确定下来再装其他库。如果已经出问题就重建虚拟环境不要试图在现有环境里反复降级 numpy越降越乱。6.2 数据标准化泄露测试集只 transform 不 fit我在 3.2 写过标准化顺序但这里值得展开说说为什么这个坑如此隐蔽。有些代码习惯是scaler StandardScaler() X_all_scaled scaler.fit_transform(X_all) X_train, X_test train_test_split(X_all_scaled, y, test_size0.2)看起来没毛病都对。但测试样本的均值和标准差已经参与了fit_transform的计算模型在作弊它见到过测试集的大致分布。结果是测试指标虚高 5%~15% 不等你带着这个模型上线一遇到真实数据立刻现形。正确的做法必须是一个fit_transform训练集 一个transform测试集。验证这个坑是否踩了很简单重新检查代码里scaler的调用位置。6.3 固定多个随机种子让实验结果可复现我一开始不懂random_state的价值结果同一个模型每次跑出的分数都不一样上下波动 1% 到 3%。因为 sklearn、TensorFlow 都依赖随机数来划分数据、初始化权重不固定种子就没有可比性。scikit-learn 侧在train_test_split里设置random_state42TensorFlow 侧稍微麻烦一点import numpy as np import tensorflow as tf np.random.seed(42) tf.random.set_seed(42)注意即使这样如果代码用了 GPU 或并行线程仍然可能有不完全可复现的情况但对入门项目已经足够。我每次实验前把种子写死对比不同模型时心里才有底。6.4 MNIST 第一次下载慢或失败别慌keras.datasets.mnist.load_data()第一次会自动从网上下载网络不稳定时会超时失败。这不是代码问题处理办法是手动下载到本地~/.keras/datasets/目录下文件名不要改代码会自动跳过下载。我维护的一个项目还把 MNIST 缓存打包进了基础镜像团队所有人都用离线缓存训练再也没人卡在网络问题上。写在最后这条路的顺序比努力更重要两个项目跑下来我最深的体会是学 AI 最消耗耐心的不是算法本身而是工具链的混乱和流程顺序的模糊。scikit-learn 让我先理解数据要干净、评估要公平这些通用原则TensorFlow/Keras 则让我把模型能力往上推。二者缺一不可。如果你正准备开始我的建议是你现在就动手复现这两个项目。第一次跑通不需要弄懂所有细节先让代码跑起来、看到结果之后再回头啃原理效率会高很多。建立好数据预处理 → 基准模型 → 深度模型 → 统一评估这个心智框架之后后续不管学算法还是做项目都有了锚点。这个系列后面我会继续聊如何用 sklearn 做更细致的特征工程、Keras 模型的超参数怎么调、以及怎么把训练好的模型封装成接口给应用调用。先把你手头这两个项目跑通有问题欢迎在评论区交流我会把常见问题集中整理成一期答疑。