主要使用python和scikit-learn库
必要的库和工具
SciPy
所有代码默认导入以下库:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import mglearn
SciPy
如果想保存一个大部分元素都是0的二维数组,可以使用稀疏矩阵:
from scipy import sparse
import numpy as np
#创建一个二维NumPy数组,对角线为 1,其余都为0
eye = np.eye(4)
print("NumPy array:\n{}".format(eye))
NumPy array:
[[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 0. 1.]]
#将NumPy数组转换为CSR格式的SciPy稀疏矩阵
#只保存非零元素
sparse_matrix = sparse.csr_matrix(eye)
print("\nSciPy sparse CSR matrix:\n{}".format(sparse_matrix))
SciPy sparse CSR matrix:
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
(3, 3) 1.0
matplotlib
matplotlib是Python主要的科学绘图库,其功能为生成可发布的可视化内容,如折线图、直方图、散点图等。
举例:
%matplotlib inline
import matplotlib.pyplot as plt
#在-10和10之间生成一个数列,共100个数
x=np.linspace(-10,10,100)
#用正弦函数创建第二个数组
y=np.sin(x)
#plot函数绘制一个数组关于另一个数组的折线图
plt.plot(x,y,marker="x")
需要指出的是,这个库在pycharm上并不能跑,要画图的话需要用其他库。
pandas
pandas是用于处理和分析数据的Python库。
import pandas as pd
from IPython.display import display
#创建关于人的简单数据集
data={'Name':["John","Anna","Peter","Linda"],
'location':["New York","Paris","Berlin","London"],
'Age':[24,13,53,33]
}
data_pandas=pd.DataFrame(data)
display(data_pandas)
Name location Age
0 John New York 24
1 Anna Paris 13
2 Peter Berlin 53
3 Linda London 33
查询这个表格的方法有很多种。举个例子:
#选择年龄大于30的所有行
display(data_pandas[data_pandas.Age >30])
输出结果如下:
Name location Age
2 Peter Berlin 53
3 Linda London 33
第一个应用:鸢尾花分类
我们的目标是构建一个机器学习模型,可以从这些已知品种的鸢尾花测量数据中进行学习,从而可以预测新鸢尾花的品种。
因为我们有已知品种的鸢尾花的测量数据,所以这是一个监督学习问题。
在这个问题中,我们要在多个选项中预测其中一个(鸢尾花的品种)。这是一个分类问题。
可能的输出(鸢尾花的不同品种)叫做类别。
数据集中的每朵鸢尾花都属于三个类别之一,所以这是一个三分类问题。
单个数据点(一朵鸢尾花)的预期输出是这朵花的品种。对于一个数据点来说,它的品种叫做标签。
from sklearn.datasets import load_iris
iris_dataset=load_iris()
print("Keys of iris_dataset:\n{}".format(iris_dataset.keys()))
输出:
Keys of iris_dataset:
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])
print(iris_dataset['DESCR'][:193]+"\n...")
输出:
.. _iris_dataset:
Iris plants dataset
--------------------
**Data Set Characteristics:**
:Number of Instances: 150 (50 in each of three classes)
:Number of Attributes: 4 numeric, pre
...
data数据的每一行对应一朵花,列代表每朵花的四个测量数据:
print("Shape of data:{}".format(iris_dataset['data'].shape))
输出:
Shape of data:(150, 4)
可以看出,数组中包含150朵不同的花的测量数据。
机器学习中的个体叫做样本,其属性叫做特征。
data数组的形状(shape)是样本数乘以特征数。
训练数据与测试数据
我们使用新数据来评估模型的性能。
通常的做法是将收集好的带标签数据分成两部分,一部分用于构建机器学习模型,叫做训练数据或训练集。其余的数据用来评估模型性能,叫做测试数据、测试集或留出集。
scikit-learn中的train_test_split函数可以打乱数据集并进行拆分。这个函数将75%的行数据及其对应标签作为训练集,剩下25%的数据及其标签作为测试集。
训练集和测试集的分配比例可以随意,但使用25%的数据作为测试集是很好的经验法则。
scikit-learn中的数据通常用大写的X表示,而标签用小写的y表示。我们用大写的X是因为数据是一个二维数组(矩阵),用小写的y是因为目标是一个一维数组(向量)。
对数据调用train_test_split,并对输出结果采用下面这种命名方法:
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(iris_dataset['data'],iris_dataset['target'],random_state=0)
为了确保多次运行同一函数能够得到相同的输出,我们利用random_state参数指定了 随机数生成器的种子。这样函数输出就是固定不变的,所以这行代码的输出始终相同。
train_test_split函数的输出为X_train、X_test、y_train和y_test,它们都是Numpy数组。X_train包含75%的行数据,X_test包含剩下 的25%:
print("X_train shape:{}".format(X_train.shape))
print("y_train shape:{}".format(y_train.shape))
输出:
X_train shape:(112, 4)
y_train shape:(112,)
输入:
print("X_test shape:{}".format(X_test.shape))
print("y_test shape:{}".format(y_test.shape))
输出:
X_test shape:(38, 4)
y_test shape:(38,)
观察数据
检查数据的最佳方法之一是将其可视化。
一种可视化方法是绘制散点图
数据不多——散点图矩阵,从而两两查看所有的特征。
#利用X_train中的数据创建DataFrame
#利用iris_dataset.feature_names中的字符串对数据列进行标记
iris_dataframe=pd.DataFrame(X_train,columns=iris_dataset.feature_names)
#利用DataFrame创建散点图矩阵,按y_train着色
grr=pd.scatter_matrix(iris_dataframe,c=y_train,figsize=(15,15),marker='o',hist_kwds={'bins':20},s=60,alpha=.8,cmap=mglearn.cm3)
运行文件正式代码:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import mglearn
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
import pandas as pd
iris_dataset=load_iris()
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(iris_dataset['data'],iris_dataset['target'],random_state=0)
#利用X_train中的数据创建DataFrame
#利用iris_dataset.feature_names中的字符串对数据列进行标记
iris_dataframe=pd.DataFrame(X_train,columns=iris_dataset.feature_names)
#利用DataFrame创建散点图矩阵,按y_train着色
grr=pd.plotting.scatter_matrix(iris_dataframe,c=y_train,figsize=(15,15),marker='o',hist_kwds={'bins':20},s=60,alpha=.8,cmap=mglearn.cm3)
plt.show()
从图中可以看出,利用花瓣和花萼的测量数据基本可以将三个类别区分开。
k近邻算法
K近邻分类器
构建此模型只需要保存训练集即可。要对一个新的数据点做出预测,算法会在训练集中寻找与这个新数据点距离最近的数据点,然后将找到的数据点的标签赋值给这个新数据点。
k近邻算法中k的含义是,我们可以考虑训练集里与新数据点最近的任意k个邻居(比如最近的3个或5个邻居),而非只考虑最近的那一个。然后,我们可以用这些邻居中数量最多的类别做出预测。
scikit-learn中所有的机器学习模型都在各自的类中实现,这些类被称为Estimator类。
k近邻分类算法是在neighbors模块的KNeighborsClassifier类中实现的。我们需要将这个类实例化为一个对象,然后才能使用这个模型。
这时我们需要设置模型的参数。
NeighborsClassifier最重要的参数就是邻居的数目,这里我们设为1:
from sklearn.neighbors import KNeighborsClassifier
knn=KNeighborsClassifier(n_neighbors=1)
想要基于训练集来构建模型,需要调用knn对象的fit方法,输入参数为X_train和y_train,二者都是Numpy数组,前者包含训练数据,后者包含相应的训练标签:
knn.fit(X_train,y_train)
做出预测
假设:我们在野外发现了一朵鸢尾花,花萼长5cm宽2.9cm,花瓣长1cm宽0.2cm。这朵鸢尾花属于哪个品种?我们可以将这些数据放在一个Numpy数组中,再次计算形状,样本形状为样本数(1)乘以特征数(4):
X_new = np.array([[5,2.9,1,0.2]])
print("X_new.shape:{}".format(X_new.shape))
输出:
X_new.shape:(1, 4)
我们必须将这朵花的测量数据转换为二维Numpy数组的一行,这是因为scikit-learn的输入数据必须是二维数组。
我们调用knn对象的predict方法来进行预测:
prediction=knn.predict(X_new)
print("Prediction:{}".format(prediction))
print("Predict target name :{}".format(iris_dataset['target_names'][prediction]))
输出:
Prediction:[0]
Predict target name :[‘setosa’]
评估模型
这里需要用到之前创建的测试集,这些数据并没有用于构建模型,但我们知道测试集中每朵鸢尾花的实际品种。
因此,我们可以对测试数据中的每朵鸢尾花进行预测,并将预测结果与标签(已知的品种)进行对比。
我们可以通过计算精度来衡量模型的优劣,精度就是品种预测正确的花所占的比例:
y_pred=knn.predict(X_test)
print("Test set prediction:\n{}".format(y_pred))
输出:
Test set prediction:
[2 1 0 2 0 2 0 1 1 1 2 1 1 1 1 0 1 1 0 0 2 1 0 0 2 0 0 1 1 0 2 1 0 2 2 1 0
2]
print("Test set score:{:.2f}".format(np.mean(y_pred==y_test)))
输出:
Test set score:0.97
我们还可以使用knn对象的score方法来计算测试集的精度:
print("Test set score:{:.2f}".format(knn.score(X_test,y_test)))
输出:
Test set score:0.97
模型的精度是0.97,也就是说,对于测试集中的鸢尾花,我们的预测有97%是正确的。
监督学习
分类与回归
监督机器学习问题主要有两种,分别叫做分类和回归。
分类问题的目标是预测类别标签,这些标签来自预定义的可选列表。
分类问题有时分为二分类和多分类。
在二分类问题中,我们通常将其中一个类别称为正类,另一个类别称为反类。
泛化、过拟合与欠拟合
如果一个模型能够对没见过的数据做出准确预测,我们就说它能够从训练集泛化到测试集。
过拟合:训练集上表现很好,不能新数据上的模型——对现有信息量而言过于复杂
欠拟合:过于简单的模型,甚至在训练集上表现就很差。
监督学习算法
一个模拟的二分类数据集示例是forge数据集,它有两个特征。
下列代码将绘制一个散点图,将此数据集中的所有数据点可视化。
图像以第一个特征为x轴,第二个特征为y轴。
每个数据点对应图像中一点,每个点的颜色和形状对于其类别。
#生成数据集
X,y=mglearn.datasets.make_forge()
#数据集绘图
mglearn.discrete_scatter(X[:0],X[:,1],y)
plt.legend(["Class 0","Class 1"],loc=4)
plt.xlabel("First feature")
plt.ylabel("Second feature")
print("X.shape:{}".format(X.shape))
输出:
X.shape:(26,2)
从X.shape可以看出,这个数据集包含26个数据点和2给特征。
用模拟的wave数据集来说明回归算法。
wave数据集只有一个输入特征和一个连续的目标变量(或响应),后者是模型想要预测的对象。
下面绘制的图像中单一特征位于x轴,回归目标(输出)位于y轴。
X,y=mglearn.datasets.make_wave(n_samples=40)
plt.plot(X,y,'o')
plt.ylim(-3,3)
plt.xlabel("Feature")
plt.ylabel("Target")
plt.show()
k近邻
k近邻分类
k-NN算法最简单的版本只考虑一个最近邻,也就是与我们想要预测的数据点最近的训练数据点。
预测结果就是这个训练数据点的已知输出。
mglearn.plots.plot_knn_classification(n_neighbors=1)
除了仅考虑最近邻,还可以考虑任意个(k个)邻居。
3个近邻的例子:
mglearn.plots.plot_knn_classification(n_neighbors=3)
现在看一下如何通过scikit-learn来应用k近邻算法。
首先,将数据分为训练集和测试集,以便评估泛化性能:
from sklearn.model_selection import train_test_split
X,y = mglearn.datasets.make_forge()
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=0)
然后,导入类并将其实例化。
这时可以设置参数,比如邻居的个数。
这里我们将其设为3:
from sklearn.neighbors import KNeighborsClassifier
clf=KNeighborsClassifier(n_neighbors=3)
现在,利用训练集对分类器进行拟合。
对于KNeighborsClassifier来说就是保存数据,以便在预测时计算与邻居之间的距离:
clf.fit(X_train,y_train)
调用predict方法来对测试数据进行预测。
对于测试集中的每个数据点,都要计算它在训练集的最近邻,然后找出其中出现次数最多的类别。
print("Test set predictions :{}".format(clf.predict(X_test)))
输出:
Test set predictions :[1 0 1 0 1 0 0]
为了评估模型的泛化能力好坏,我们可以对测试数据和测试标签调用score方法:
print("Test set accuracy :{:.2f}".format(clf.score(X_test,y_test)))
输出:
Test set accuracy :0.86
模型精度约为86%
分析KNeighborsClassifier
对于二维数据集,我们还可以在xy平面上画出所有可能的测试点的预测结果。
我们根据平面中每个点所属的类别对平面进行着色。
这样可以查看决策边界,即算法对类别0和类别1的分界线。
下面代码分别将1个、3个和9个邻居三种情况的决策边界可视化。
fig ,axes = plt.subplots(1,3,figsize=(10,3))
for n_neighbors,ax in zip([1,3,9],axes):
clf = KNeighborsClassifier(n_neighbors=n_neighbors).fit(X,y)
mglearn.plots.plot_2d_separator(clf,X,fill=True,eps=0.5,ax=ax,alpha=.4)
mglearn.discrete_scatter(X[:,0],X[:,1],y,ax=ax)
ax.set_title("{}neighbor(s)".format(n_neighbors))
ax.set_xlabel("feature 0")
ax.set_ylabel("feature 1")
axes[0].legend(loc=3)
从左图可以看出,使用单一邻居绘制的决策边界紧跟着训练数据。随着邻居个数越来越多,决策边界也越来越平滑。
使用更少的邻居对应更高的模型复杂度。
我们来研究一下是否能证实模型复杂度和泛化能力之间的关系。
我们将在现实世界的乳腺癌数据集上进行研究。
先将数据集分成训练集和测试集,然后用不同的邻居个数对训练集和测试集的性能进行评估。
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
X_train,X_test,y_train,y_test=train_test_split(cancer.data,cancer.target,stratify=cancer.target,random_state=66)
training_accuracy=[]
test_accuracy=[]
neighbors_settings=range(1,11)
for n_neighbors in neighbors_settings:
#构建模型
clf=KNeighborsClassifier(n_neighbors=n_neighbors)
clf.fit(X_train,y_train)
#记录数据集精度
training_accuracy.append(clf.score(X_train,y_train))
#记录泛化精度
test_accuracy.append(clf.score(X_test,y_test))
plt.plot(neighbors_settings,training_accuracy,label="training accuracy")
plt.plot(neighbors_settings,test_accuracy,label="test accuracy")
plt.ylabel("Accuracy")
plt.xlabel("n_neighbors")
plt.legend()
plt.show()
k近邻回归
k近邻算法可以用于回归。
我们从单一近邻开始,这次使用wave数据集。
我们添加了3个测试数据点,在x轴上用绿色五角星表示。
利用单一邻居的预测结果就是最近邻的目标值。在图中用蓝色五角星表示:
mglearn.plots.plot_knn_regression(n_neighbors=1)
同样,也可以用多个近邻进行回归。
在使用多个近邻时,预测结果为这些邻居的平均值:
mglearn.plots.plot_knn_regression(n_neighbors=3)
用于回归的k近邻算法在scikit-learn的KNeighborsRegressor类中实现。
from sklearn.neighbors import KNeighborsRegressor
X,y=mglearn.datasets.make_wave(n_samples=40)
#将wave数据集分为训练集和测试集
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=0)
#模型实例化,并将邻居个数设为3
reg=KNeighborsRegressor(n_neighbors=3)
#利用训练数据和训练目标值来拟合模型
reg.fit(X_train,y_train)
现在可以对测试集进行预测:
print("Test set predictions:\n{}".format(reg.predict(X_test)))
Test set predictions:
[-0.05396539 0.35686046 1.13671923 -1.89415682 -1.13881398 -1.63113382
0.35686046 0.91241374 -0.44680446 -1.13881398]
我们还可以用score方法来 评估模型,对于回归问题,这一方法返回的是分数。分数也叫做决定系数,是回归模型预测的优先度量,位于0到1之间。对应完美预测,对应常数模型,即总是预测训练集响应(y_train)的平均值:
print("Test set R^2:{:.2f}".format(reg.score(X_test,y_test)))
Test set R^2:0.83
分析KNeighborsRegressor
对于我们的一维数据集,可以查看所有特征值对应的预测结果。
为了便于绘图,我们创建一个由许多点组成的测试数据集:
fig,axes=plt.subplots(1,3,figsize=(15,4))
#创建1000个数据点,在-3和3之间均匀分布
line=np.linspace(-3,3,1000).reshape(-1,1)
for n_neighbors,ax in zip([1,3,9],axes):
#利用1个,3个或9个邻居分别进行预测
reg=KNeighborsRegressor(n_neighbors=n_neighbors)
reg.fit(X_train,y_train)
ax.plot(line,reg.predict(line))
ax.plot(X_train,y_train,'^',c=mglearn.cm2(0),markersize=8)
ax.plot(X_test,y_test,'v',c=mglearn.cm2(1),markersize=8)
ax.set_title(
"{}neighbor(s)\n train score:{:.2f} test score:{:.2f}".format(
n_neighbors,reg.score(X_train,y_train),
reg.score(X_test,y_test)))
ax.set_xlabel("Feature")
ax.set_ylabel("Target")
axes[0].legend(["Model predictions","Training data/target","Test data/target"],loc="best")
线性模型
线性模型利用输入特征的线性函数进行预测。
用于回归的线性模型
对于回归问题,线性模型预测的一般公式如下:
这里到表示单个数据点的特征(本例中特征个数为p+1),和是学习模型的参数,是模型的预测结果。
对于单一特征的数据集,公式如下:
下列代码可以在一维wave数据集上学习参数和
mglearn.plots.plot_linear_regression_wave()
w[0]: 0.393906 b: -0.031804
线性回归(最小二乘法)
线性回归,或者普通最小二乘法,是回归问题最简单也是最经典的线性方法。线性回归寻找参数和,使得对训练集的预测值与真实的回归目标值之间的均方误差最小。
均方误差是预测值与真实值之差的平方和除以样本数。
from sklearn.linear_model import LinearRegression
X,y=mglearn.datasets.make_wave(n_samples=60)
X_train,X_tset,y_train,y_test=train_test_split(X,y,random_state=42)
lr=LinearRegression().fit(X_train,y_train)
斜率(也叫做权重或系数),被保存在coef_属性中,
而偏移或截距()被保存在intercept_属性中。
print("lr.coef_:{}".format(lr.coef_))
print("lr.intercept_:{}".format(lr.intercept_))
lr.coef_:[0.39390555]
lr.intercept_:-0.031804343026759746
岭回归
岭回归也是一种用于回归的线性模型,因此他的预测公式与普通最小二乘法相同。
在岭回归中,对系数的选择不仅要在训练集上得到好的预测效果,还要拟合附加约束。我们还希望系数尽量小。
正则化是指对模型做显式约束,避免过拟合。
岭回归用到的这种被称为L2正则化。
mglearn.plots.plot_ridge_n_samples()
岭回归和线性回归在波士顿房价数据集上的学习曲线
lasso
除了Ridge,还有一种正则化的线性回归是lasso。
与岭回归相同,使用lasso也是约束系数使其接近于0,但用的是L1正则化。
L1正则化的结果是,使用lasso时某些系数刚好为0.
在实践中,两个模型中一般首选岭回归。但如果特征很多,你认为只有其中几个是重要的,那选择lasso可能更好。
用于分类的线性模型
对于用于分类的线性模型,决策边界是输入的线性函数。
换句话说,(二元)线性分类器是利用直线、平面或超平面来分开两个类别的分类器。
学习线性模型有很多种算法。这些算法的区别在于以下两点:
- 系数和截距的特定组合对训练数据拟合好坏的度量方法;
- 是否使用正则化,以及使用哪种正则化方法。
最常见的两种线性分类算法是Logistic回归和线性支持向量机。
前者在linear_model.LogisticRegression中实现,后者在svm.LinearSVC中实现。
我们可将LogisticRegression和LinearSVC模型 应用到forge数据集上,并将线性模型找到的决策边界可视化。
from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
X,y =mglearn.datasets.make_forge()
fig,axes=plt.subplots(1,2,figsize=(10,3))
for model ,ax in zip([LinearSVC(),LogisticRegression()],axes):
clf = model.fit(X,y)
mglearn.plots.plot_2d_separator(clf,X,fill=False,eps=0.5,ax=ax,alpha=.7)
mglearn.discrete_scatter(X[:,0],X[:,1],y,ax=ax)
ax.set_title("{}".format(clf._class_._name_))
ax.set_xlabel("Feature 0")
ax.set_ylabel("Feature 1")
axes[0].legend()
在这张图中,forge数据集的第一个特征位于x轴,第二个特征位于y轴。
图中分别展示了LinearSVC和LogisticRegression得到的决策边界,都是直线,将顶部归为类别1的区域和底部归为类别0 的区域分开了。
换句话说,对于每个分类器而言,位于黑线上方的新数据点都会被划为类别1,而在黑线下方的点都会被划为类别0.
对于上述二者,决定正则化强度的权衡参数叫做C。C值越大,对应的正则化越弱。
换句话说,如果参数C值较大,二者将尽可能将训练集拟合到最好,而如果C值较小,那么模型更强调使系数向量()接近于0 .
mglearn.plots.plot_linear_svc_regularization()
不同C值的线性SVM在forge数据集上的决策边界
我们在乳腺癌数据集上详细分析LogisticRegression
from sklearn.datasets import load_breast_cancer
cancer=load_breast_cancer()
X_train,X_test,y_train,y_test=train_test_split(cancer.data,cancer.target,stratify=cancer.target,random_state=42)
logreg=LogisticRegression().fit(X_train,y_train)
logreg100=LogisticRegression(C=100).fit(X_train,y_train)
logreg001=LogisticRegression(C=0.01).fit(X_train,y_train)
plt.plot(logreg.coef_.T,'o',label="C=1")
plt.plot(logreg100.coef_.T,'^',label="C=100")
plt.plot(logreg001.coef_.T,'v',label="C=0.001")
plt.xticks(range(cancer.data.shape[1]),cancer.feature_names,rotation=90)
plt.hlines(0,0,cancer.data.shape[1])
plt.ylim(-5,5)
plt.xlabel("Coefficient index")
plt.ylabel("Coefficient magnitude")
plt.legend()
用于多分类的线性模型
将二分类算法推广到多分类算法的一种常见方法是"一对其余"方法。
在这个方法中,对每个类别都学习一个二分类模型,将这个类别与所有其他类别尽量分开,这样就生成了与类别个数一样多的二分类模型。
在测试点运行所有二类分类器来进行预测。
在对应类别上分数最高的分类器”胜出",将这个类别标签返回作为预测结果。
我们将”一对其余“方法应用在一个简单的三分类数据集上。
我们用到了一个二维数据集,每个类别的数据都是从一个高斯分布中采样得出的。
from sklearn.datasets import make_blobs
X,y= make_blobs(random_state=42)
mglearn.discrete_scatter(X[:,0],X[:,1],y)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
plt.legend(["Class 0","Class 1","Class 2"])
包含3个类别的二位玩具数据集:
现在,在这个数据集上训练一个LinearSVC分类器:
linear_svm=LinearSVC().fit(X,y)
mglearn.discrete_scatter(X[:,0],X[:,1],y)
line=np.linspace(-15,15)
for coef,intercept,color in zip(linear_svm.coef_,linear_svm.intercept_,['b','r','g']):
plt.plot(line,-(line*coef[0]+intercept)/coef[1],c=color)
plt.ylim(-10,15)
plt.xlim(-10,8)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
plt.legend(['Class 0','Class 1','Class 2',' Line Class 0',' Line Class 1',' Line Class 2'],loc=(1.01,0.3))
mglearn.plots.plot_2d_classification(linear_svm,X,fill=True,alpha=.7)
mglearn.discrete_scatter(X[:,0],X[:,1],y)
line=np.linspace(-15,15)
for coef,intercept,color in zip(linear_svm.coef_,linear_svm.intercept_,['b','r','g']):
plt.plot(line,-(line*coef[0]+intercept)/coef[1],c=color)
plt.ylim(-10,15)
plt.xlim(-10,8)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
plt.legend(['Class 0','Class 1','Class 2',' Line Class 0',' Line Class 1',' Line Class 2'],loc=(1.01,0.3))