目录
Scikit-learn(sklearn)是Python中一个非常优秀和流行的机器学习库,它提供了一系列高效的数据挖掘和数据分析工具,建立在NumPy、SciPy和matplotlib等优秀开源项目之上。它集成了包括分类、回归、聚类、降维、模型选择和数据预处理等常见任务的机器学习算法。
这篇教程将带领大家全面了解sklearn的基础知识,并通过大量实例来学习如何使用这个强大的库进行机器学习任务。
1. 获取并准备数据
在进行机器学习任务之前,首先需要获取并准备好数据。sklearn内置了一些标准数据集,用于入门和示例,可以通过datasets
模块加载:
from sklearn import datasets
# 加载内置的iris鸢尾花数据集
iris = datasets.load_iris()
X = iris.data # 数据特征
y = iris.target # 数据标签
print(X.shape) # 输出数据特征的维度 (150, 4)
print(y.shape) # 输出数据标签的维度 (150,)
sklearn同时还提供了读取外部数据文件的工具函数,支持多种格式如CSV、LibSVM等:
from sklearn import datasets
# 从网络加载Diabetes数据集
diabetes = datasets.load_diabetes()
print(diabetes.data.shape) # 输出数据特征的维度 (442, 10)
print(diabetes.target.shape) # 输出数据标签的维度 (442,)
直接加载的数据不一定完全准备就绪,可能需要进行一些预处理,比如填充缺失值、归一化等。为此,sklearn也提供了一套完善的数据预处理工具。
2. 训练测试数据划分
无论使用哪种机器学习算法,都需要准备好训练数据和测试数据。sklearn中的model_selection
模块提供了专门用于数据划分的函数。
from sklearn.model_selection import train_test_split
# 将iris数据划分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(X_train.shape) # (120, 4)
print(X_test.shape) # (30, 4)
print(y_train.shape) # (120,)
print(y_test.shape) # (30,)
train_test_split
默认将20%的数据作为测试集,80%作为训练集。通过test_size
参数也可以调整这个比例。另外,如果要保证每次执行时数据都是随机但相同的划分,可以设置一个固定的random_state
随机种子。
3. 训练机器学习模型
经过上面两步,现在我们就可以基于训练数据来训练一个机器学习模型了。以朴素贝叶斯分类器为例:
from sklearn.naive_bayes import GaussianNB
# 创建高斯朴素贝叶斯分类器实例
nb_model = GaussianNB()
# 用训练数据训练模型
nb_model.fit(X_train, y_train)
# 对测试集进行预测
y_pred = nb_model.predict(X_test)
print(y_pred) # 预测结果
训练模型的过程就这么简单!仅需要用 .fit()
方法就可以基于数据完成模型训练。
sklearn中提供了大量机器学习模型供选择,从简单的线性模型到复杂的神经网络等等,每种模型的使用方式基本类似:
-
导入模型类
-
创建模型实例
-
调用
fit()
方法训练模型 -
调用
predict()
方法做预测
4. 模型评估
上面我们已经得到了预测结果 y_pred
,但精确度如何呢?我们可以使用sklearn中的metrics
模块来评估模型性能:
from sklearn import metrics
# 计算准确率
accuracy = metrics.accuracy_score(y_test, y_pred)
print("Accuracy: ", accuracy)
# 计算精确率
precision = metrics.precision_score(y_test, y_pred)
print("Precision: ", precision)
# 计算召回率
recall = metrics.recall_score(y_test, y_pred)
print("Recall: ", recall)
metrics
模块提供了非常全面的评估指标工具,包括准确率、精确率、召回率、F1值、ROC曲线等,可以从多个维度评价模型表现。
对于回归任务,也有针对性的回归指标可以使用:
from sklearn.metrics import mean_squared_error, r2_score
# 准备回归目标变量
y_true = [3, -0.5, 2]
# 模型预测值
y_pred = [2.5, 0.1, 2]
mse = mean_squared_error(y_true, y_pred)
r2 = r2_score(y_true, y_pred)
print("MSE: ", mse)
print("R^2: ", r2)
5. 保存和加载模型
在实际应用中,我们往往需要对训练好的模型进行保存以备后续使用。在sklearn中,可以使用joblib
模块实现模型的持久化:
from sklearn.externals import joblib
# 保存训练好的模型
joblib.dump(nb_model, 'naive_bayes_model.pkl')
# 后续加载模型进行预测
nb_model_loaded = joblib.load('naive_bayes_model.pkl')
y_pred = nb_model_loaded.predict(X_test)
joblib
不仅可以保存模型,它也能保存数据或者 numpy 数组等任意 Python 对象。这为复杂的工作流建立了完整的管道,支持你在不同的程序运行或环境间共享数据和模型。
6. 数据预处理
在实际场景中,数据往往是杂乱和缺失的,需要进行预处理才能被模型有效地利用。sklearn中有专门的预处理模块(preprocessing
)为此提供工具。
比如,有时我们会遇到数据缺失或者异常值的问题:
import numpy as np
from sklearn.impute import SimpleImputer
# 有缺失值的数据
data = [[1, 2],
[np.nan, 3],
[7, 6]]
# 填充缺失值
imputer = SimpleImputer(strategy='mean')
print(imputer.fit_transform(data))
7. 特征缩放
在很多机器学习算法中,不同特征的数值范围差异很大会影响模型的性能和收敛速度。这时就需要进行特征缩放(Feature Scaling),将所有特征的值缩放到同一个数值范围内。
sklearn 的 preprocessing
模块提供了几种常用的特征缩放方法:
标准化(Standardization)
from sklearn.preprocessing import StandardScaler
# 一些数据
X = [[1., -1., 3.],
[2., 4., 2.],
[4., 6., -5.]]
# 标准化数据
scaler = StandardScaler()
print(scaler.fit_transform(X))
标准化将数据按其特征标准差缩放,使其均值为0,方差为1。
归一化(Normalization)
from sklearn.preprocessing import Normalizer
# 一些数据
X = [[4., 1., 2., 2.],
[1., 3., 9., 5.],
[7., 8., 5., 4.]]
# 归一化数据
transformer = Normalizer().fit_transform(X)
print(transformer)
归一化能够将数据缩放到单位范数,这在需要计算数据中的角度或者长度时非常有用。
二值化(Binarization)
from sklearn.preprocessing import Binarizer
# 一些数据
X = [[-1., -0.5],
[0.5, 1.5],
[2., 3.],
[3.5, 4.]]
# 二值化数据
binarizer = Binarizer(threshold=1.5)
print(binarizer.transform(X))
二值化会将数据按阈值映射为二进制值 0 或 1,可以看做一种特殊的数据桶技术。
8. 模型选择和验证
机器学习中常见的挑战之一就是如何从大量算法和参数组合中选择最优模型。sklearn 提供了多种模型选择和验证工具来解决这个问题。
K-折交叉验证
这是一种常用的模型评估方法,能够避免单一的训练测试集划分带来的影响。
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
# 加载数据
iris = datasets.load_iris()
X, y = iris.data, iris.target
# K-折交叉验证
log_reg = LogisticRegression()
scores = cross_val_score(log_reg, X, y, cv=5)
print("Accuracy scores:", scores)
print("Mean accuracy: ", scores.mean())
上例使用 5-折交叉验证来评估 LogisticRegression 在鸢尾花数据集上的平均准确率。
网格搜索
当模型有多个需要调参的超参数时,我们需要知道哪组超参数组合能够产生最优性能。网格搜索就是一种暴力搜索的手段。
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
# 超参数组合
parameters = {'kernel':('linear', 'rbf'),
'C':[1, 10]}
# 通过网格搜索交叉验证寻找最优参数
svm = SVC()
clf = GridSearchCV(svm, parameters, cv=5)
clf.fit(X_train, y_train)
print("Best params: ", clf.best_params_)
上例为SVM模型搜索最优的kernel
和惩罚系数C
参数,搜索结果是通过5-折交叉验证获得的。
除此之外,sklearn还提供其他一些高级模型选择和评估工具,如混淆矩阵、学习曲线、validation曲线等,有兴趣可以自行了解。
9. 管道(Pipeline)和特征工程
机器学习工作流中常需要将数据预处理、模型训练和模型评估等环节组合在一起。Pipeline就是为了将这些环节有机地组织起来。
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
# 创建管道
pipe = Pipeline([('scaler', StandardScaler()),
('logistic', LogisticRegression())])
# 在管道上训练和预测
pipe.fit(X_train, y_train)
print(pipe.score(X_test, y_test))
上例创建了一个包含标准缩放和逻辑回归的管道。管道的每个步骤都是基于上一步的输出,直到最后一步。管道还能自动完成诸如缓存中间结果以提高效率等工作。
Pipeline 结合 scikit-learn 强大的特征工程工具,能够实现更复杂的机器学习系统。sklearn 中的 FeatureUnion
、FunctionTransformer
等可以用于定制化的特征转换。
10. 有监督学习算法
sklearn库内置了非常全面的监督学习算法,包括:
-
线性模型:Logistic Regression, LinearRegression 等
-
支持向量机:SVM, SVR, NuSVM等
-
决策树与集成:DecisionTreeClassifier, RandomForestClassifier, GradientBoostingClassifier 等
-
贝叶斯方法:GaussianNB, BernoulliNB, MultinomialNB
-
最近邻算法:KNeighborsClassifier, RadiusNeighborsClassifier
-
神经网络和深度学习:MLPClassifier, MLPRegressor
这些算法的使用方式基本一致,我们通过一个实例来认识:
from sklearn.datasets import make_blobs
from sklearn.ensemble import RandomForestClassifier
from sklearn.inspection import DecisionBoundaryDisplay
# 构造数据
X, y = make_blobs(centers=4, n_features=2, random_state=1)
# 创建分类器
clf = RandomForestClassifier().fit(X, y)
# 绘制决策边界
DecisionBoundaryDisplay.from_estimator(clf, X, cmap="Paired_r")
上例使用随机森林分类器对一个人造的4类数据进行分类,并绘制了决策边界。我们简单地初始化分类器,调用 .fit()
训练模型,就可以完成各类工作了。
具体每种算法的参数设置和使用场景,可参考 sklearn 文档进一步了解。
总而言之,本教程对 Scikit-learn 这一优秀的机器学习库作了入门级的介绍,涵盖了从加载数据到训练模型、评估模型、特征工程、模型选择等机器学习全流程。
11. 无监督学习算法
除了有监督学习算法外,Scikit-learn 还提供了强大的无监督学习算法工具,可用于聚类、降维、异常检测等任务。
聚类算法
聚类是将数据样本划分为多个组(簇),使得同一簇内的样本相似程度较高,簇间相似程度较低。一些常用的聚类算法有:
-
K-Means
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
# 创建数据
X, y = make_blobs(n_samples=500, n_features=2, centers=4, cluster_std=1.0, random_state=42)
# 创建 K-Means 聚类器
kmeans = KMeans(n_clusters=4)
kmeans.fit(X)
y_pred = kmeans.predict(X)
# 可视化结果
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()
-
层次聚类
from sklearn.datasets import load_iris
from sklearn.cluster import AgglomerativeClustering
import matplotlib.pyplot as plt
# 加载数据
iris = load_iris()
X = iris.data
# 层次聚类
cluster = AgglomerativeClustering(n_clusters=3)
cluster.fit_predict(X)
# 可视化结果
plt.scatter(X[:, 2], X[:, 3], c=cluster.labels_)
plt.show()
-
DBSCAN
from sklearn.datasets import make_blobs
from sklearn.cluster import DBSCAN
import matplotlib.pyplot as plt
# 创建数据
X, y = make_blobs(n_samples=500, n_features=2, centers=4, cluster_std=1.0, random_state=42)
# DBSCAN 聚类
clustering = DBSCAN(eps=0.5, min_samples=5).fit(X)
# 可视化结果
plt.scatter(X[:, 0], X[:, 1], c=clustering.labels_)
plt.show()
除了上述经典算法外,sklearn 还支持谱聚类、Mean Shift、高斯混合模型等多种聚类方法。
降维算法
机器学习任务中常常需要降低数据的维度,以减少计算复杂度和去除冗余特征。主成分分析(PCA)和线性判别分析(LDA)是两种常用的降维技术:
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
# 加载数据
iris = load_iris()
X = iris.data
# PCA 降维
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
# 可视化
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=iris.target)
plt.show()
from sklearn.datasets import load_iris
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
import matplotlib.pyplot as plt
# 加载数据
iris = load_iris()
X = iris.data
y = iris.target
# LDA 降维
lda = LDA(n_components=2)
X_lda = lda.fit_transform(X, y)
# 可视化
plt.scatter(X_lda[:, 0], X_lda[:, 1], c=y)
plt.show()
异常检测
异常检测器能够检测和识别数据中的离群点和异常值。常见的算法包括一类支持向量机、Isolation Forest 等:
from sklearn.svm import OneClassSVM
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
import numpy as np
# 加载数据
X, _ = load_wine(return_X_y=True)
# 切分为训练和测试集
X_train, X_test = train_test_split(X, test_size=0.2, random_state=42)
# 初始化 OneClassSVM 模型
oc_svm = OneClassSVM(kernel="rbf", gamma="auto", nu=0.1)
oc_svm.fit(X_train)
# 标记异常样本
y_pred = oc_svm.predict(X_test)
outliers = np.where(y_pred == -1)[0]
print(f"Detected {len(outliers)} outliers in test set.")
from sklearn.ensemble import IsolationForest
from sklearn.datasets import load_boston
import numpy as np
# 加载波士顿房价数据
X, _ = load_boston(return_X_y=True)
# 初始化 Isolation Forest 异常检测器
isof = IsolationForest(contamination=0.1, random_state=42)
isof.fit(X)
# 检测异常点
y_pred = isof.predict(X)
outliers = np.where(y_pred == -1)[0]
print(f"Detected {len(outliers)} outliers.")
sklearn 中的无监督学习算法功能强大,涵盖了各种场景,可以与有监督学习算法一起解决更加复杂的问题。
12. 模型解释
随着机器学习模型越来越复杂,理解模型内部的工作原理和决策过程变得也越来越困难,因此模型解释工具变得愈发重要。sklearn 提供了多种可解释性工具。
特征重要性
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
import matplotlib.pyplot as plt
# 加载数据
iris = load_iris()
# 训练随机森林模型
rf = RandomForestClassifier(random_state=42)
rf.fit(iris.data, iris.target)
# 可视化特征重要性
plt.barh(iris.feature_names, rf.feature_importances_)
plt.show()
上例使用随机森林模型,并可视化了每个特征对于最终决策的重要程度。了解特征重要性有助于特征选择和模型优化。
单个预测的解释
LIME(Local Interpretable Model-Agnostic Explanation)是一种用于解释单个预测结果的通用算法。
import sklearn
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
import lime
import lime.lime_tabular
# 加载数据和模型
iris = load_iris()
rf = RandomForestClassifier(n_estimators=500)
rf.fit(iris.data, iris.target)
# 解释单个预测
explainer = lime.lime_tabular.LimeTabularExplainer(iris.data, feature_names=iris.feature_names)
i = np.random.randint(0, iris.data.shape[0])
exp = explainer.explain_instance(iris.data[i], rf.predict_proba)
exp.show_in_notebook(show_all=False)
LIME 通过训练一个局部替代模型,给出当前预测的解释,易于理解。
13. 处理非结构化数据
除了标准的数值数据外,Scikit-learn 还支持处理各种非结构化的数据,如文本、图像等。
文本数据
Scikit-learn 利用了流行的 NLTK 库处理自然语言文本数据。可以执行文本向量化、词袋/TF-IDF 提取、主题建模等常见任务。
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
# 加载新闻组文本数据
data = fetch_20newsgroups()
categories = data.target_names
# 训练并转换数据
vectorizer = TfidfVectorizer()
X_train_tfidf = vectorizer.fit_transform(data.data[:-3000])
X_test_tfidf = vectorizer.transform(data.data[-3000:])
# 建立并训练朴素贝叶斯模型
clf = MultinomialNB().fit(X_train_tfidf, data.target[:-3000])
# 评估模型
accuracy = clf.score(X_test_tfidf, data.target[-3000:])
print(f"Accuracy on test set: {accuracy:.2f}")
此示例从 20 个新闻组中提取文本数据,使用 TF-IDF 向量化后训练了一个多项式朴素贝叶斯分类器,并评估了其测试集上的准确率。
图像数据
利用 Python 图像处理库如 Pillow,Scikit-learn 能够处理图像数据。注意处理图像时需要将其展平为一维数组。
from sklearn import datasets
from sklearn.svm import SVC
import matplotlib.pyplot as plt
# 加载内置数字图像数据
digits = datasets.load_digits()
images = digits.images
targets = digits.target
# 展平图像数据
data = digits.images.reshape(digits.images.shape[0], -1)
# 建立并训练 SVM 分类器
clf = SVC(gamma=0.001)
clf.fit(data[:1000], targets[:1000])
# 评估模型
expected = targets[1000:1500]
predicted = clf.predict(data[1000:1500])
# 绘制混淆矩阵
conf = clf.confusion_matrix(expected, predicted)
plt.matshow(conf, cmap="binary", origin="lower")
plt.colorbar()
plt.show()
以上代码加载了 Scikit-learn 内置的手写数字图像数据集,训练了一个 SVM 分类器,并绘制了混淆矩阵评估其性能。
处理图像和其他非结构化数据需要额外的数据预处理步骤,但 Scikit-learn 提供了便利的工具与算法进行整合,使得机器学习流程更加高效。
14. 模型持久化
在实际应用场景中,我们通常需要在不同的环境和时间使用相同的模型。Scikit-learn 提供了 joblib
工具用于模型的持久化。
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.externals import joblib
# 加载并拆分数据
iris = load_iris()
X, y = iris.data, iris.target
# 训练模型
clf = LogisticRegression().fit(X, y)
# 保存模型
joblib.dump(clf, 'log_model.pkl')
# ... 在其他时间或环境下加载并使用模型
# 加载模型
loaded_clf = joblib.load('log_model.pkl')
# 模型可以继续使用
loaded_clf.predict(X[:5])
joblib.dump
可以将任何 Scikit-learn 模型或 Numpy 数组等 Python 对象保存到磁盘文件中。joblib.load
则用于重新加载它们。这种持久化功能不仅确保了跨环境和时间重用模型,还能避免重复训练的时间消耗。
15. 与 MLflow 集成跟踪实验
在许多机器学习项目中,我们需要跟踪各种实验的参数、代码版本、模型表现等信息。MLflow 是一个开源平台,旨在管理整个机器学习生命周期。Scikit-learn 可以很好地与它集成。
import mlflow
import sklearn
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import f1_score
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 启动 MLflow 并记录参数
mlflow.start_run()
mlflow.log_param('model', 'Logistic Regression')
# 加载并处理数据
iris = load_iris(as_frame=True)
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target)
# 训练和评估模型
model = LogisticRegression(C=1, solver='lbfgs', max_iter=1000)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
f1 = f1_score(y_test, y_pred, average='weighted')
# 记录指标并保存模型
mlflow.log_metric('f1', f1)
mlflow.sklearn.log_model(model, 'model')
# 结束运行并保存运行信息
mlflow.end_run()
在上例中,我们使用 MLflow 记录了逻辑回归模型的超参数、训练过程中的指标以及最终模型本身。MLflow 会自动记录代码版本、环境信息等其他元数据。这些信息被统一保存,方便了实验管理。
MLflow 还支持模型部署、服务化等其他功能,值得在机器学习项目中一试。当然,这只是开端,Scikit-learn 的功能远不止如此。希望这篇教程能激发继续探索和实践的兴趣,发掘出这个强大工具更多潜力,助力各种机器学习任务!