1.2 Scikit-learn 的核心模块 本节摘要:Scikit-learn 的核心模块是按"机器学习工作流"的节奏组织的:datasets 管数据入口,preprocessing 与 featureselection 管特征加工,modelselection 管切分与调参,linearmodel、tree、ensemble、svm、cluster 等管具体算法,metrics 管评估,pipeline 把这一切串成一条流水线。本节逐个讲清每个模块"管哪一段、典型零件是什么、什么时候用",让你在写代码前先在脑子里有张地图。
本节摘要:Scikit-learn 的核心模块是按"机器学习工作流"的节奏组织的:datasets 管数据入口,preprocessing 与 feature_selection 管特征加工,model_selection 管切分与调参,linear_model、tree、ensemble、svm、cluster 等管具体算法,metrics 管评估,pipeline 把这一切串成一条流水线。本节逐个讲清每个模块"管哪一段、典型零件是什么、什么时候用",让你在写代码前先在脑子里有张地图。
阅读完本节,你应当能够:
load 与 make 两类数据入口的用途很多库的文档是按字母或按作者来排的,Scikit-learn 不是。它的模块划分几乎和机器学习的工作流一一对应:先有数据,再加工特征,再切分数据,再选算法训练,最后评估、上线。你顺着工作流走一遍,模块名自然就记住了。
这背后是一套"零件化"的设计哲学:每个模块只解决一个明确问题,模块之间通过统一接口衔接。好处是——你要做缺失值填充,去 preprocessing 找;要切训练集测试集,去 model_selection 找;要做聚类,去 cluster 找。不用翻遍整个文档。
我们用一张时序图看一个完整流程里各模块的出场顺序:
下面逐个拆解。
datasets 是这趟旅程的起点,它干两件事:加载现成数据和现场造数据。
加载用的函数以 load 开头,返回一个类似字典的对象,里面装着数据、标签、特征名等。鸢尾花、手写数字、乳腺癌、葡萄酒这些经典数据集都在这里,专供你练手和验证算法。它们的价值不是"数据多好",而是"标准化、没歧义"——所有人都用同一份数据,你跑出的准确率才能和别人比较。
拿到这个对象后,.data 是特征矩阵、.target 是标签、.feature_names 是特征名,这三件套基本够用。它虽然长得像字典,但字段是固定的,你摸清这几个属性名,换哪个数据集都一样。
造数据用的函数以 make 开头,按你指定的样本数、特征数、噪声水平生成合成数据。make_classification 造分类数据,make_regression 造回归数据,make_blobs 造一团团聚在一起的数据。为什么要造数据?因为真实数据往往太乱,你想单独验证"算法对这个特性敏不敏感"时,合成数据能让你控制变量。
💡 关键直觉:
load是你练手时的"标准练习册",make是你做实验时的"可调参数实验台"。前者求可比,后者求可控。
拿到数据后,很少能直接喂给模型。数值量纲差太大、类别字段是文字、某些格子里是空的——这些都要先处理。这就是 preprocessing 模块的活。
它最常用的几类零件:StandardScaler 做标准化,把每个特征缩成均值 0、标准差 1,适合对量纲敏感的算法(近邻、支持向量机、逻辑回归);MinMaxScaler 做归一化,压到 0 到 1 区间;OneHotEncoder 把"红色、蓝色、绿色"这类文字类别变成哑变量;SimpleImputer 填缺失值。这些都属于"特征还没变好之前要过的关"。
feature_selection 则更进一步:特征已经变好了,但太多了、或很多是冗余的,怎么办?它帮你筛。VarianceThreshold 直接砍掉几乎不变的列;SelectKBest 按统计得分挑最相关的 K 个;RFE 递归地训练、逐轮删掉最不重要的特征。它和 preprocessing 的区别在于:preprocessing 是"改每一列的形态",feature_selection 是"决定留哪些列"。
⚠️ 常见坑:预处理和特征选择都必须"只学训练集"。你在训练集上算出的均值、标准差、要保留的特征,必须原封不动套用到测试集上。如果先拿全部数据一起标准化再切分,测试集的信息就漏进了训练过程,评估结果会虚高——这叫做数据泄露,是新手最容易犯、也最隐蔽的错。
顺带说一句标准化和归一化怎么选:StandardScaler 把数据压成均值 0、标准差 1,适合近邻、支持向量机这类靠"距离"或"梯度"工作的算法,它们对量纲敏感;MinMaxScaler 把数据压到 0 到 1 区间,适合需要非负输入、或你要把不同特征放在同一张图里比较的场景。没有谁更好,只有谁更配当前的算法。
model_selection 这个名字容易让人误会它只做"选模型",其实它扛两类活:切数据和调参数。
切数据的是 train_test_split,把数据按比例分成训练集和测试集,训练集用来学,测试集用来考。它有一个不起眼但重要的参数 random_state——固定它,每次切的都一样,实验才可复现。
调参数的是交叉验证和搜索:KFold 把训练数据再折成若干份,轮流拿一份当验证集;GridSearchCV 遍历你给的所有参数组合,用交叉验证给每组打分,选出最好的一组;RandomizedSearchCV 在参数空间里随机抽样,适合参数空间太大的情况。这些工具的共性,是它们都站在"用交叉验证而不是单次切分来评估"这个更严谨的基础上。
为什么交叉验证比"单次切分"更可信?因为单次切分的结果依赖这一次随机怎么切——换一个 random_state,准确率可能上下浮动好几个点。交叉验证把数据折成几份、轮流验证再取平均,等于把"运气成分"摊薄了。这也是 GridSearchCV 要内置交叉验证的原因:如果只在一份验证集上挑参数,你其实是在"用验证集过拟合参数",挑出来的参数未必经得起新数据检验。
这是工具箱里抽屉最多的部分,也是很多人以为的"全部"。按"有没有标签"分成两大阵营。
监督学习——有标签,要学"从特征到标签"的映射。分类和回归都在这里。对应模块有一串:linear_model 放线性回归、逻辑回归、岭回归;tree 放决策树;ensemble 放随机森林、梯度提升这些"多棵树投票"的集成模型;svm 放支持向量机;neighbors 放 K 近邻;naive_bayes 放朴素贝叶斯。选哪个,取决于数据规模、要不要可解释、非线性程度,第 3 章会给出具体的选型地图。
无监督学习——没标签,要自己从数据里找结构。cluster 做聚类,把样本自动分组(K 均值、DBSCAN 都在这里);decomposition 做降维,把高维数据压到低维同时尽量保留信息(主成分分析就是最典型的一个);manifold 做流形学习,擅长把高维数据的局部近邻关系在二维平面上展开,常用来做可视化。
把这两大阵营和前面几个模块拼起来,就是一张完整的模块速查表:
| 模块 | 职责 | 典型零件或函数 |
|---|---|---|
| datasets | 加载、生成数据 | load 系列、make 系列 |
| preprocessing | 改特征形态 | StandardScaler、OneHotEncoder、SimpleImputer |
| feature_selection | 挑特征 | VarianceThreshold、SelectKBest、RFE |
| model_selection | 切分、调参 | train_test_split、GridSearchCV |
| linear_model | 线性模型 | LinearRegression、LogisticRegression |
| tree / ensemble | 树与集成 | DecisionTree、RandomForest |
| svm / neighbors / naive_bayes | 其他监督算法 | SVC、KNeighbors、GaussianNB |
| cluster / decomposition | 聚类与降维 | KMeans、PCA |
| metrics | 评估打分 | accuracy_score、混淆矩阵 |
| pipeline | 串联流程 | Pipeline |
选算法的第一直觉,不是"哪个名字听起来高级",而是先看三件事:数据有没有标签(决定走监督还是无监督)、标签是连续还是离散(决定回归还是分类)、样本量和特征数有多大(决定用线性模型还是树和集成)。多数情况下,先拿一个线性模型跑出基线,再上随机森林或梯度提升,是一条既快又稳的路。
最后这个模块,是把前面所有零件"组装成流水线"的关键。pipeline 让你把"标准化 + 特征选择 + 训练"这些步骤,打包成一个对象,对外仍然只暴露 fit 和 predict 两个接口。
它解决的不只是代码整洁。更重要的价值在于把预处理和模型绑定在一起,杜绝数据泄露。因为整条流水线在 fit 时,会自动让每个预处理步骤只在训练集上学习、再套用到测试集上。你不再需要手动记着"这个标准化器是用训练集拟合的"——流水线替你管住了顺序和边界。
一个概念性的最小管道长这样:
from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression pipe = Pipeline([ ("scaler", StandardScaler()), ("model", LogisticRegression()), ]) # 一次调用:先标准化训练集,再训练模型 pipe.fit(X_train, y_train) # 预测时自动用同一套标准化规则 pipe.predict(X_test)
你看,用了 pipeline 之后,外部代码反而比手写六步更短了。因为它把"顺序"这种容易出错的隐性知识,变成了结构化的显式声明。
更妙的是,这个 pipe 对象本身就是一个"标准零件"——你可以把它直接传给交叉验证、网格搜索,就像传一个普通模型一样。因为 pipeline 对外暴露的也是 fit / predict,它和单个模型在接口层面完全等价。这种"零件可以无限嵌套"的特性,是 Scikit-learn 统一接口最漂亮的地方。
💡 关键直觉:把 pipeline 想象成一条自动化的装配线——原料(数据)从一头进去,依次经过每道工序,成品(预测)从另一头出来。你只需定义工序顺序,装配线自己保证每道工序拿到的都是正确的前序产物。
模块记不住没关系,记住两条导航规则就够了。
第一,顺工作流找。要数据去 datasets,要加工去 preprocessing,要切分去 model_selection,要建模去对应的算法模块,要打分去 metrics,要组装去 pipeline。路线是固定的。
第二,认接口不背清单。具体到每个类名,不必硬背——它们大多遵循"名词即用途"的命名(StandardScaler 就是"做标准化的缩放器")。真正要刻进脑子的是"所有零件都长着 fit / transform / predict 这副面孔",第 2 章会把这三副面孔背后的抽象——估计器、转换器、预测器——彻底讲透。
load 加载标准数据求可比,make 生成合成数据求可控。下一章我们进入本书最关键的部分——把"估计器、转换器、预测器"这三种对象抽象彻底拆开,搞懂 Scikit-learn 统一接口背后的设计逻辑。