scikit-learn__02.2__Basic-Principles

机器学习的基本原则

在这里,我们将深入探讨机器学习的基本原理,以及如何通过Scikit-Learn API使用它们。

在简要介绍scikit-learn的Estimator对象之后,我们将介绍有监督的学习,包括分类和回归问题,以及无监督的学习,包括降维和聚类问题。

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn')

The Scikit-learn Estimator Object

每种算法都通过“ Estimator”对象在scikit学习中公开。 例如,线性回归是这样实现的:

from sklearn.linear_model import LinearRegression

估计器参数:估计器的所有参数都可以在实例化时设置,并具有合适的默认值:

model = LinearRegression(normalize=True)
print(model.normalize)
>>True
print(model)
>>LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=True)

估计的模型参数:当数据与估计器拟合时,将从手头的数据估计参数。 所有估计的参数都是估计对象的属性,其下划线结尾:

x = np.arange(10)
y = 2 * x + 1
print(x)
print(y)
>>[0 1 2 3 4 5 6 7 8 9]
[ 1  3  5  7  9 11 13 15 17 19]
plt.plot(x, y, 'o');

在这里插入图片描述

# The input data for sklearn is 2D: (samples == 10 x features == 1)
X = x[:, np.newaxis]
print(X)
print(y)
>>[[0]
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]]
[ 1  3  5  7  9 11 13 15 17 19]
# fit the model on our data 使模型适合我们的数据
model.fit(X, y)
>>LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=True)
# underscore at the end indicates a fit parameter 末尾的下划线表示一个合适的参数
print(model.coef_)#参数
print(model.intercept_)#截距
>>[2.]
1.0

这个模型找到了一条斜率为2、截距为1的直线,正如我们所期望的那样。

监督学习:分类和回归

在“监督学习”中,我们有一个既包含要素又包含标签的数据集。
任务是构造一个能够预测对象标签的估计器
给定的功能集。 一个相对简单的例子是预测
虹膜给出了一组其花朵的尺寸。 这是一个相对简单的任务。
一些更复杂的示例是:
-通过望远镜获得物体的多色图像,确定
该物体是恒星,类星体还是星系。
-给定某人的照片,在照片中标识该人。
-给出一个人观看过的电影列表及其个人评价
电影中,推荐他们想要的电影列表
(所谓的“推荐系统”:一个著名的例子是[Netflix奖](http://en.wikipedia.org/wiki/Netflix_prize))。
这些任务的共同点是存在一个或多个未知数
与对象相关的数量需要从其他对象确定
观察到的数量。
监督学习被进一步分为两类,“分类”和“回归”。
在分类中,标签是离散的,而在回归中,标签是连续的。 例如,
在天文学中,确定物体是恒星,星系还是类星体的任务是
分类问题:标签来自三个不同的类别。 另一方面,我们可能
希望基于这样的观察来估计物体的寿命:这将是一个回归问题,
因为标签(年龄)是连续的数量。

分类的例子

K最近邻居(kNN)是最简单的学习策略之一:给定一个新的未知观察值,在您的参考数据库中查找具有最接近特征并指定主要类别的参考。
让我们尝试一下鸢尾花分类问题:

from sklearn import neighbors, datasets

iris = datasets.load_iris()
X, y = iris.data, iris.target

# create the model
knn = neighbors.KNeighborsClassifier(n_neighbors=5)

# fit the model
knn.fit(X, y)

# What kind of iris has 3cm x 5cm sepal and 4cm x 2cm petal?
# call the "predict" method:
result = knn.predict([[3, 5, 4, 2],])

print(iris.target_names[result])
>>['versicolor']

您还可以进行概率预测:

knn.predict_proba([[3, 5, 4, 2],])
>>array([[0. , 0.8, 0.2]])
from fig_code import plot_iris_knn
plot_iris_knn()

在这里插入图片描述

练习

对同一问题使用不同的估计:sklearn.svm.SVC。
请注意,你不必知道它是什么,使用它。我们只是在尝试这里的界面
如果你提前完成,试着用奇异值分解估计器创建一个类似的图。

from sklearn.svm import SVC

回归示例

最简单的回归问题之一是将一条线拟合到数据,正如我们在上面看到的。
Scikit-learn还包含更复杂的回归算法

# Create some simple data
import numpy as np
np.random.seed(0)
X = np.random.random(size=(20, 1))
y = 3 * X.squeeze() + 2 + np.random.randn(20)

plt.plot(X.squeeze(), y, 'o');

在这里插入图片描述

model = LinearRegression()
model.fit(X, y)

# Plot the data and the model prediction
X_fit = np.linspace(0, 1, 100)[:, np.newaxis]
y_fit = model.predict(X_fit)

plt.plot(X.squeeze(), y, 'o')
plt.plot(X_fit.squeeze(), y_fit);

在这里插入图片描述
Scikit-learn还具有一些更复杂的模型,它们可以响应数据中的更精细功能:

# Fit a Random Forest
from sklearn.ensemble import RandomForestRegressor
model = RandomForestRegressor()
model.fit(X, y)

# Plot the data and the model prediction
X_fit = np.linspace(0, 1, 100)[:, np.newaxis]
y_fit = model.predict(X_fit)

plt.plot(X.squeeze(), y, 'o')
plt.plot(X_fit.squeeze(), y_fit);

在这里插入图片描述
这些因素是否适合,取决于许多因素。 在本教程的后面,我们将讨论如何选择模型的详细信息。


Exercise

使用IPython的帮助功能探索``RandomForestRegressor’'对象(即在该对象之后添加一个问号)。

``RandomForestRegressor’'可以使用哪些参数?

如何上面的情节变化,如果你改变这些参数呢?

这些类级参数称为* hyperparameters *,稍后我们将在模型验证部分讨论如何选择超参数。


机器学习:降维和聚类

机器学习 解决一种不同的问题。这里的数据没有标签,我们感兴趣的是找出这些物体之间的相似之处。从某种意义上说,您可以将无监督学习视为从数据本身中发现标签的一种手段。机器学习包括诸如降维聚类密度估计。例如,在上面讨论的虹膜数据中,我们可以在无监督的情况下使用方法来确定最能显示数据。正如我们将在下面看到的,这样的数据投影可以用来可视化二维四维数据集。一些更复杂的无监督学习问题是:

  • 根据对遥远星系的详细观察,确定哪些特征或特征组合最能概括信息。
  • 给定两个声源的混合(例如,一个人边听音乐边讲话),将这两个声源分开(这称为[盲源分离])(http://en.wikipedia.org/wiki/Blind_signal_separation) problem).
  • 给定视频,请隔离运动对象并根据已看到的其他运动对象进行分类。

有时甚至可以将两者结合起来: 无监督学习可用于发现有用的东西异构数据中的特征,然后可以在监督下使用这些特征框架。

Dimensionality Reduction: PCA

主成分分析(PCA)是一种降维技术,可以找到解释最大方差的变量组合。
以iris数据集为例。因为它有4个特征,所以它不能在一个2D图中被可视化。我们将提取两个组合的萼片和花瓣的规模,以可视化它

X, y = iris.data, iris.target

from sklearn.decomposition import PCA
pca = PCA(n_components=0.95)
pca.fit(X)
X_reduced = pca.transform(X)
print("Reduced dataset shape:", X_reduced.shape)
>>Reduced dataset shape: (150, 2)

import pylab as plt
plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=y,
           cmap='RdYlBu')

print("Meaning of the 2 components:")
for component in pca.components_:
    print(" + ".join("%.3f x %s" % (value, name)
                     for value, name in zip(component,
                                            iris.feature_names)))
>>Meaning of the 2 components:
0.361 x sepal length (cm) + -0.085 x sepal width (cm) + 0.857 x petal length (cm) + 0.358 x petal width (cm)
0.657 x sepal length (cm) + 0.730 x sepal width (cm) + -0.173 x petal length (cm) + -0.075 x petal width (cm)

在这里插入图片描述

集群:k - means

聚类将相对于给定标准而言均一的观察分组在一起,从而在数据中找到“簇”。
请注意,只有使用的标准突出显示这些簇时,它们才会发现数据的相关隐藏结构。

from sklearn.cluster import KMeans
k_means = KMeans(n_clusters=3, random_state=0) # Fixing the RNG in kmeans
k_means.fit(X)
y_pred = k_means.predict(X)

plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=y_pred,
           cmap='RdYlBu');

在这里插入图片描述

概述:Scikit-learn的estimator接口

Scikit-learn努力为所有方法提供统一的界面,我们将在下面看到这些示例。 给定一个scikit学习估算器对象名为“模型”,可以使用以下方法:

  • Available in all Estimators
    • model.fit() : fit training data.
      对于监督学习应用, 这有两个参数: the data X and the labels y (e.g. model.fit(X, y)).
      对于非监督学习应用,只有一个参数 the data X (e.g. model.fit(X)).
  • Available in supervised estimators
    • model.predict() : given a trained model, predict the label of a new set of data.
      This method accepts one argument, the new data X_new (e.g. model.predict(X_new)),
      并返回数组中每个对象的学习标签.
    • model.predict_proba() : For classification problems, some estimators also provide
      this method, which returns the probability that a new observation has each categorical label.
      In this case, the label with the highest probability is returned by model.predict().
    • model.score() : for classification or regression problems, most (all?) estimators implement
      a score method. Scores are between 0 and 1, with a larger score indicating a better fit.
  • Available in unsupervised estimators
    • model.predict() : predict labels in clustering algorithms(聚类算法).
    • model.transform() : given an unsupervised model, transform new data into the new basis.
      This also accepts one argument X_new, and returns the new representation of the data based
      on the unsupervised model.
    • model.fit_transform() : some estimators implement this method,
      which more efficiently performs a fit and a transform on the same input data.

Model Validation

An important piece of machine learning is model validation: that is, determining how well your model will generalize from the training data to future unlabeled data. Let’s look at an example using the nearest neighbor classifier. This is a very simple classifier: it simply stores all training data, and for any unknown quantity, simply returns the label of the closest training point.

With the iris data, it very easily returns the correct prediction for each of the input points:

from sklearn.neighbors import KNeighborsClassifier
X, y = iris.data, iris.target
clf = KNeighborsClassifier(n_neighbors=1)
clf.fit(X, y)
y_pred = clf.predict(X)
print(np.all(y == y_pred))
>>True

A more useful way to look at the results is to view the confusion matrix(混淆矩阵), or the matrix showing the frequency (频率矩阵)of inputs and outputs:

from sklearn.metrics import confusion_matrix
print(confusion_matrix(y, y_pred))
>>[[50  0  0]
 [ 0 50  0]
 [ 0  0 50]]

For each class, all 50 training samples are correctly identified. But this does not mean that our model is perfect! In particular(在特别情况下), such a model generalizes extremely poorly to new data. We can simulate this by splitting our data into a training set and a testing set. Scikit-learn contains some convenient routines to do this:

from sklearn.model_selection import train_test_split
Xtrain, Xtest, ytrain, ytest = train_test_split(X, y,test_size=0.3)
clf.fit(Xtrain, ytrain)
ypred = clf.predict(Xtest)
print(confusion_matrix(ytest, ypred))
>>[[12  0  0]
[ 0 17  0]
[ 0  1 15]]

This paints a better picture of the true performance of our classifier: apparently there is some confusion between the second and third species, which we might anticipate given what we’ve seen of the data above.

This is why it’s extremely important to use a train/test split when evaluating your models. We’ll go into more depth on model evaluation later in this tutorial.

Flow Chart: How to Choose your Estimator

这是由scikit-learn超级贡献者[Andreas Mueller](https://github.com/amueller)创建的流程图,它很好地总结了在各种情况下选择哪种算法。 随身携带以备参考!
在这里插入图片描述

Quick Application: Optical Character Recognition(光学字符识别)

为了在一个更有趣的问题上演示上述原则,让我们考虑OCR(光学字符识别),即识别手写数字。在野外,这个问题涉及到定位和识别图像中的字符。在这里,我们将使用一个快捷方式,并使用scikit-learn的一组预格式化的数字,这是内置到库中的。

加载和显示数字数据

我们将使用scikit-learn的数据访问界面,并查看以下数据:

from sklearn import datasets
digits = datasets.load_digits()
digits.images.shape
>>(1797, 8, 8)

Let’s plot a few of these:

fig, axes = plt.subplots(10, 10, figsize=(8, 8))
fig.subplots_adjust(hspace=0.1, 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')
    ax.set_xticks([])
    ax.set_yticks([])

在这里插入图片描述
这里的数据只是8x8网格内的每个像素值:

# The images themselves
print(digits.images.shape)
print(digits.images[0])
>>(1797, 8, 8)
[[ 0.  0.  5. 13.  9.  1.  0.  0.]
 [ 0.  0. 13. 15. 10. 15.  5.  0.]
 [ 0.  3. 15.  2.  0. 11.  8.  0.]
 [ 0.  4. 12.  0.  0.  8.  8.  0.]
 [ 0.  5.  8.  0.  0.  9.  8.  0.]
 [ 0.  4. 11.  0.  1. 12.  7.  0.]
 [ 0.  2. 14.  5. 10. 12.  0.  0.]
 [ 0.  0.  6. 13. 10.  0.  0.  0.]]
# The data for use in our algorithms
print(digits.data.shape)
print(digits.data[0])
>>(1797, 64)
[ 0.  0.  5. 13.  9.  1.  0.  0.  0.  0. 13. 15. 10. 15.  5.  0.  0.  3.
 15.  2.  0. 11.  8.  0.  0.  4. 12.  0.  0.  8.  8.  0.  0.  5.  8.  0.
  0.  9.  8.  0.  0.  4. 11.  0.  1. 12.  7.  0.  0.  2. 14.  5. 10. 12.
  0.  0.  0.  0.  6. 13. 10.  0.  0.  0.]
# The target label
print(digits.target)
>>[0 1 2 ... 8 9 8]

无监督学习:降维

我们想在64维参数空间中可视化我们的点,但是很难在64维中绘制点!
相反,我们将使用无监督方法将尺寸减小到2。
在这里,我们将使用称为Isomap的流形学习算法,并将数据转换为二维。

from sklearn.manifold import Isomap
iso = Isomap(n_components=2)
data_projected = iso.fit_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)

在这里插入图片描述
我们在这里看到,数字在参数空间中是相当分开的。 这告诉我们,监督分类算法应能表现良好。 试一试吧。

数字分类

让我们尝试对数字进行分类任务。 我们要做的第一件事是将数字分成训练和测试样本:

from sklearn.model_selection import train_test_split
Xtrain, Xtest, ytrain, ytest = train_test_split(digits.data, digits.target,
                                                random_state=2)
print(Xtrain.shape, Xtest.shape)
>>(1347, 64) (450, 64)
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression(penalty='l2')
clf.fit(Xtrain, ytrain)
ypred = clf.predict(Xtest)
from sklearn.metrics import accuracy_score
accuracy_score(ytest, ypred)
>>0.9466666666666667

这个数字并不能告诉我们我们出了什么问题:一种不错的方法是使用混淆矩阵

from sklearn.metrics import confusion_matrix
print(confusion_matrix(ytest, ypred))
>>[[42  0  0  0  0  0  0  0  0  0]
 [ 0 45  0  1  0  0  0  0  3  1]
 [ 0  0 47  0  0  0  0  0  0  0]
 [ 0  0  0 42  0  2  0  3  1  0]
 [ 0  2  0  0 36  0  0  0  1  1]
 [ 0  0  0  0  0 52  0  0  0  0]
 [ 0  0  0  0  0  0 42  0  1  0]
 [ 0  0  0  0  0  0  0 48  1  0]
 [ 0  2  0  0  0  0  0  0 38  0]
 [ 0  0  0  1  0  1  0  1  2 34]]
plt.imshow(np.log(confusion_matrix(ytest, ypred)),
          cmap='Blues', interpolation='nearest')
plt.grid(False)
plt.ylabel('true')
plt.xlabel('predicted');

在这里插入图片描述

fig, axes = plt.subplots(10, 10, figsize=(8, 8))
fig.subplots_adjust(hspace=0.1, wspace=0.1)

for i, ax in enumerate(axes.flat):
    ax.imshow(Xtest[i].reshape(8, 8), cmap='binary')
    ax.text(0.05, 0.05, str(ypred[i]),
            transform=ax.transAxes,
            color='green' if (ytest[i] == ypred[i]) else 'red')
    ax.set_xticks([])
    ax.set_yticks([])

在这里插入图片描述
有趣的是,即使使用这种简单的逻辑回归算法,许多错误贴标签的案例也是我们自己可能会出错的案例!
有很多方法可以改进此分类器,但是我们在这里没有时间。 更进一步,我们可以使用更复杂的模型,使用交叉验证或应用其他技术。 在本教程的后面,我们将介绍其中一些主题。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章