[ sklearn version: 0.23.0 ]
Scikit-Learn为各种常用机器学习算法提供了高效版本。
机器学习是从数据创建模型的学问,因此首先需要了解怎样表示数据爱你让计算机理解。Scikit-Learn认为数据表示(data representation)最好的方法就是用数据表的形式。
基本的数据表就是二维网格数据,其中的每一行表示数据集中的每个样本(samples),而列表示构成每个样本的相关特征(features)。
# 鸢尾花数据集
import pandas as pd
iris = pd.read_csv('./seaborn-data-master/iris.csv')
iris.head()
这个表格布局通过二维数组或矩阵的形式将信息清晰地表达出来,通常把这类矩阵称为特征矩阵(features matrix)。
特征矩阵通常被简记为变量X
。它是维度为[n_samples, n_features]
的二维矩阵,通常可以用NumPy数组或Pandas的DataFrame来表示,不过Scikit-Learn也支持SciPy的稀疏矩阵。
样本(每一行)通常是指数据集中的每个对象(任何可以通过一组量化方法进行测量的实体)。
特征(每一列)通常是指每个样本都具有的某种量化观测值。一般情况下,特征都是实数,但有时也可能是布尔类型或离散值。
除了特征矩阵 X 之外,还需要一个标签或目标数组,通常简记为y
。
目标数组一般是一维数组,其长度就是样本总数n_samples
,通常都用一维的NumPy数组或Pandas的Series表示。
目标数组可以是连续的数值类型,也可以是离散的类型/标签。
有些Scikit-Learn的评估器可以处理具有多目标值的二维[n_samples, n_targets]目标数组,文中基本上只涉及常见一维目标数组问题。
如何区分目标数组的特征与特征矩阵中的特征列,一直是个问题。目标数组的特征通常是我们希望从数据中预测的量化结果,借用统计学的术语,y
就是因变量。
%matplotlib inline
import seaborn as sns
sns.set()
sns.pairplot(iris, hue='species', height=1.5)
抽取特殊矩阵和目标数组
# 从DataFrame中抽取特征矩阵和目标数组
X_iris = iris.drop('species', axis=1)
X_iris.shape # (150, 4)
X_iris
y_iris = iris['species']
y_iris.shape # (150,)
y_iris
Scikit-Learn API主要遵照以下设计原则:
Scikit-Learn中的所有机器学习算法都是通过评估器API实现的,它为各种机器学习应用提供了统一的接口
Scikit-Learn评估器API的常用步骤如下:
fit()
方法对数据进行拟合predict()
方法预测新数据的标签transform()
或predict()
方法转换或推断数据的性质演示一个简单线性回归的建模步骤:最常见的任务就是为散点数据集 ( x , y ) (x,y) (x,y)拟合一条直线
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
rng = np.random.RandomState(42)
x = 10 * rng.rand(50)
y = 2 * x - 1 + rng.randn(50)
plt.scatter(x, y)
(1) 选择模型类
在Scikit-Learn中,每个模型类都是一个Python类。
# 计算一个简单线性回归模型
from sklearn.linear_model import LinearRegression
(2) 选择模型超参数
注意:模型类与模型实例不同
当我们选择模型类之后,还有许多参数需要配置。根据不同模型的不同情况,你可能需要回答一下问题:
有一些重要的参数必须在选择模型类时确定好。这些参数通常被称为超参数,即在模型拟合数据之前必须被确定的参数。
在Scikit-Learn中,通常在模型初始化阶段选择超参数。
# 对于示例,可以实例化LinearRegression类
# 并用fit_intercept超参数设置是否想要拟合直线的截距
model = LinearRegression(fit_intercept=True)
model
# LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=False)
注意:对模型进行实例化仅仅是存储了超参数的值。我们还没有将模型应用到数据上:Scikit-Learn的API对选择模型和将模型应用到数据区别得很清晰。
(3) 将数据整理成特征矩阵和目标数组
Scikit-Learn的数据表示方法(需要二维特征矩阵和一维目标数组)。
虽然我们的目标数组已经有了y(长度为n_samples的数组),但还需要将数据x整理成[n_samples, n_features]的形式。
# 示例中,可以对一维数组进行简单的维度变换
X = x[:, np.newaxis]
X.shape # (50, 1)
(4) 用模型拟合数据
现在就可以将模型应用到数据上了,这一步通过模型的fit()
方法即可完成。
fit()
命令会在模型内部大量运算,运算结果将存储在模型属性中,供用户使用。
model.fit(X, y)
# LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=False)
在Scikit-Learn中,所有通过fit()
方法获得的模型参数都带一条下划线。
# 例如,在线回归模型中,模型参数如下
model.coef_ # array([1.9776566])
model.intercept_ # -0.9033107255311164
model.coef_
和model.intercept_
两个参数分别表示对样本数据拟合直线的斜率和截距模型参数的不确定性是机器学习经常遇到的问题。一般情况下,Scikit-Learn不会为用户提供直接从模型参数获得结论的工具,与其将模型桉树解释为机器学习问题,不如说它更像统计建模问题。机器学习的重点并不是模型的预见性。
(5) 预测新数据的标签
模型预测出来后,有监督机器学习的主要任务就变成了对不属于训练集的新数据进行预测。
在Scikit-Learn中,用predict()
方法进行预测
# 新数据是特征矩阵的x坐标值,需要用模型预测出目标数组的y轴坐标
xfit = np.linspace(-1, 11)
# 先将x值转换成[n_samples, n_features]的特征矩阵形式,之后将其输入到模型中
Xfit = xfit[:, np.newaxis]
yfit = model.predict(Xfit)
# 最后把原始数据和拟合结果可视化
plt.scatter(x, y)
plt.plot(xfit, yfit)
示例问题:如何为鸢尾花数据集建立模型,先用一部分数据进行㜕,再用模型预测出其他样本的标签?
我们将使用高斯朴素贝叶斯(Gaussian naive Bayes)方法完成。
这个方法假设每个特征中属于每一类的观测值都符合高斯分布。因为高斯朴素贝叶斯分类高斯朴素贝叶斯方法速度很快,而且不需要选择超参数,所以通常很适合作为初步分类手段,在借助更复杂的模型进行优化之前使用。
由于需要用模型之前没有接触过的数据评估它的训练效果,因此得现将数据分割成训练集(training set)和测试集(testing set)。使用train_test_split
函数
from sklearn.model_selection import train_test_split
Xtrain, Xtest, ytrain, ytest = train_test_split(X_iris, y_iris, random_state=1)
整理好数据后,用模型预测标签
from sklearn.naive_bayes import GaussianNB # 1.选择模型类
model = GaussianNB() # 2.初始化模型
model.fit(Xtrain, ytrain) # 3.用模型拟合数据
y_model = model.predict(Xtest) # 4.对新数据进行预测
最后用accuracy_score
工具验证模型预测结果的准确率(预测的所有结果中,正确结果占总预测样本数的比例)
from sklearn.metrics import accuracy_score
accuracy_score(ytest, y_model) # 输出:0.9736842105263158
无监督学习问题:对鸢尾花数据集进行降维,以便能更方便地对数据进行可视化。(鸢尾花数据集由四个维度构成,即每个样本都有四个维度。)
降维的任务是要找到一个可以保留数据本质特征的低维矩阵来表示高维数据。降维通常用于辅助数据可视化的工作(用二维数据画图比用四维甚至更高维的数据画图更方便)
以下将使用主成分分析(principle component analysis, PCA)方法,是一种快速线性降维技术。将用模型返回两个主成分,也就是用二维数据表示鸢尾花的四维数据。
from sklearn.decomposition import PCA # 1.选择模型类
model = PCA(n_components=2) # 2.设置超参数,初始化模型
model.fit(X_iris) # 3.拟合数据(注意这里不用y变量)
X_2D = model.transform(X_iris) # 4.将数据转换为二维
可视化结果:快速处理方法就是先将二维数据插入到鸢尾花的DataFrame中,然后用Seaborn的lmplot
方法画图
iris['PCA1'] = X_2D[:, 0]
iris['PCA2'] = X_2D[:, 1]
sns.lmplot('PCA1', 'PCA2', hue='species', data=iris, fit_reg=False)
聚类算法是要对没有任何标签的数据集进行分组。
此处使用聚类方法之高斯混合模型(Gaussian mixture model, GMM),GMM模型试图将数据构造成若干服从高斯分布的概率密度函数簇。
拟合高斯混合模型:
from sklearn.mixture import GaussianMixture # 1.选择模型类
model = GaussianMixture(n_components=3,
covariance_type='full') # 2.设置超参数,初始化模型
model.fit(X_iris) # 3.拟合数据(注意不需要y变量)
y_gmm = model.predict(X_iris) # 4.确定簇标签
将簇标签添加到鸢尾花的DataFrame中,并用Seaborn画出结果
iris['cluster'] = y_gmm
sns.lmplot('PCA1', 'PCA2', data=iris, hue='species',
col='cluster', fit_reg=False)
挑战一个光学字符识别问题:手写数字识别。这个问题包括图像中字符的定位和识别两部分。
用Scikit-Learn的数据获取接口加载数据并简单统计:
from sklearn.datasets import load_digits
digits = load_digits()
digits.images.shape # 输出:(1797, 8, 8)
# 图像数据是一个三维矩阵:共有1797个样本,每张图像都是8像素*8像素。
# 对前100张图进行可视化
import matplotlib.pyplot as plt
fig, axes = plt.subplots(10, 10, figsize=(8, 8),
subplot_kw={'xticks': [], 'yticks': []},
gridspec_kw=dict(hspace=0.2, wspace=0.1))
for i, ax in enumerate(axes.flat):
ax.imshow(digits.images[i], cmap='binary', interpolation='nearest')
ax.text(0.05, 0.05, str(digits.target[i]),
transform=ax.transAxes, color='green')
为了在Scikit-Learn中使用数据,需要一个维度为[n_samples, n_features]的二维特征矩阵,可以将每个样本图像的所有像素都作为特征,也就是将每个数字的8像素*8像素平铺成长度为64的一维数组。另外还需要一个目标数组,用来表示每个数字的真实值(标签)。
# 这两份数据已经在手写数字数据集的data与target属性中,可直接使用
X = digits.data
X.shape # 输出:(1797, 64)
y = digits.target
y.shape # 输出:(1797,)
# 一共有1797个样本和64个特征
需要借助无监督学习方法将维度降到二维,通过流形学习算法中的Isomap算法对数据进行降维:
from sklearn.manifold import Isomap
iso = Isomap(n_components=2)
iso.fit(digits.data)
data_projected = iso.transform(digits.data)
data_projected.shape # 输出:(1797, 2)
# 数据已投影到二维,将二维数据可视化
plt.scatter(data_projected[:, 0], data_projected[:, 1], c=digits.target,
edgecolor='none', alpha=0.5,
cmap=plt.cm.get_cmap('nipy_spectral', 10))
plt.colorbar(label='digit label', ticks=range(10))
plt.clim(-0.5, 9.5)
需要找到一个分类算法,对手写数字进行分类。
# 将数据分成训练集和测试集
Xtrain, Xtest, ytrain, ytest = train_test_split(X, y, random_state=0)
# 用高斯朴素贝叶斯模型来拟合
from sklearn.naive_bayes import GaussianNB
model = GaussianNB()
model.fit(Xtrain, ytrain)
y_model = model.predict(Xtest)
# 已完成模型预测,用模型在训练集中的正确识别样本量与总训练样本连进行对比,获得模型的准确率
from sklearn.metrics import accuracy_score
accuracy_score(ytest, y_model) # 输出:0.8333333333333334
# 用Scikit-Learn计算混淆矩阵,并用Seaborn可视化
from sklearn.metrics import confusion_matrix
mat = confusion_matrix(ytest, y_model)
sns.heatmap(mat, square=True, annot=True, cbar=True)
plt.xlabel('predicted value')
plt.ylabel('true value')
另一种显示模型特征的直观方式是将样本画出来,然后把预测标签放在左下角,用绿色表示预测正确,红色表示预测错误
fig, axes = plt.subplots(10, 10, figsize=(8, 8),
subplot_kw={'xticks':[], 'yticks':[]},
gridspec_kw=dict(hspace=0.1, wspace=0.1))
test_images = Xtest.reshape(-1, 8, 8)
for i, ax in enumerate(axes.flat):
ax.imshow(test_images[i], cmap='binary', interpolation='nearest')
ax.text(0.05, 0.05, str(y_model[i]),
transform=ax.transAxes,
color='green' if (ytest[i] == y_model[i]) else 'red')
机器学习相关阅读:
[Python3] 机器学习 ——(一)机器学习简介
总结自《Python数据科学手册》