监督学习和非监督学习
我们谈起机器学习经常会听到监督学习和非监督学习,它们的区别在哪里呢?监督学习是有标签的,而非监督学习是没有标签的。比如有一批酒,我们知道里面包括红酒和白酒,算法f可以用于鉴别某一个酒是否为红酒和白酒,这时候算法f就称作为监督学习,红酒、白酒即为标签。如果现在另有一批酒,我们知道里面包括不同品种的酒,但是不知道有几类,算法g可以把相同类别的酒归为一类,不同类别的酒归为不同的类(比如:红酒、白酒、啤酒、米酒…), 算法g就称作为非监督学习。在监督学习中我们称作“分类”,在非监督学习中我们称作“聚类”。本文提到的K邻近算法属于监督学习内的“分类”算法。
分类和回归算法
分类问题用于分类型数据,比如红酒、白酒、啤酒、米酒;回归问题用于连续的数值型数据,比如股票的走势。K邻近算法用KNeighborsClassifier类实现分类算法,用KNeighborsRegressor实现回归算法。
K邻近算法实现分类问题
在上图(a)中已经知道有2个分类,红色与黑色,现在有一个新的节点(绿色),我们判断这个点属于红色还是绿色。K邻近算法的核心思想是寻找与这个点最近的点。比如绿色的点为A(x1,y1), 已知的点为B(xi,yi),最近的点即为(xi-x1)2 (yi-y1)2最小,即方差最小或欧式空间最小。现在我们指定最近邻数为k,k=1(上图(b)),这是找到一个红点离它最近,所以把这个绿点认为属于红色。但是当最近邻数设为k=3(上图(c)),有一个红点离它最近,两个黑点离它最近,把这个绿点认为属于黑色。由此可以看出,在K邻近算法中最近邻数设置不同,会影响最后的结果。
看下面代码
代码语言:javascript复制# coding:utf-8
# 导入数据集生成器
from sklearn.datasets import make_blobs
# 导入KNN分类器
from sklearn.neighbors import KNeighborsClassifier
# 导入画图工具
import matplotlib.pyplot as plt
# 导入数据划分模块、分为训练集和测试集
from sklearn.model_selection import train_test_split
def sklearn_base():
# 产生200个新样本,分成2类,随机生成器的种子为8
data = make_blobs(n_samples=200,centers=2, random_state=8)
X,y =data
print("X is :",X)
print("y is :",y)
#将数据集用散点图方式进行可视化分析
plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.spring,edgecolor='k')
plt.show()
使用make_blobs类设置200个新样本,分成2类,然后以散点图方式可视化如下:
这两类数据分别为紫色和黄色。
输出:
代码语言:javascript复制X is : [[ 6.75445054 9.74531933]
[ 6.80526026 -0.2909292 ]
[ 7.07978644 7.81427747]
…
y is : [0 1 0 1 0 0 1 0 0 1 1 1 0 0 1 1 0 0 1 0 0 1 1 0 1 0 1 1 1 0 1 1 0 1 1 1 1]
由于X是一个矩阵,表示数据,y是一个向量,表示属于哪个类。所以X一般为大写,y一般为小写
接下来我们绘制紫色区域和黄色区域,并且看看一个点(6.75,4.82)属于哪个紫色还是黄色?
代码语言:javascript复制#加载KNeighborsClassifier
clf = KNeighborsClassifier()
clf.fit(X,y)
#下面代码用于画图
x_min,x_max = X[:,0].min()-1,X[:,0].max() 1
y_min,y_max = X[:,1].min()-1,X[:,1].max() 1
#生成网格点坐标矩阵
xx,yy = np.meshgrid(np.arange(x_min,x_max,.02),np.arange(y_min,y_max,.02))
#预测数据集X的结果
Z = clf.predict(np.c_[xx.ravel(),yy.ravel()])
Z = Z.reshape(xx.shape)
#绘制分类图
plt.pcolormesh(xx, yy, Z,shading='auto',cmap=plt.cm.Spectral)
plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.spring,edgecolor='k')
#设置或查询 x 轴限制
plt.xlim(xx.min(),xx.max())
#设置或查询 y 轴限制
plt.ylim(yy.min(),yy.max())
#设置图的标题
plt.title("Classifier:KNN")
plt.scatter(6.75,4.82,marker='*',c='red',s=200紫色和黄色为代测试分类的点
plt.show()
print('[6.75,4.82]属于分类:',clf. predict([[6.75,4.82]]))
输出:
代码语言:javascript复制[6.75,4.82]属于分类:[1]
即黄色,图为:
图中待测的点通过函数plt.scatter内的marker='*' ,c='red'以红五星呈现(marker默认为'o',即圆点)。(在Python的机器学习中函数的参数很多,我们不用全部记住,记住重要的几个参数即可)。
上面仅仅以两类的分类,下面我们来看看多个类的分类。
代码语言:javascript复制def sklearn_multivariate():
data2 = make_blobs(n_samples=500,centers=5, random_state=8)
X2,y2 =data2
plt.scatter(X2[:,0],X2[:,1],c=y2,cmap=plt.cm.spring,edgecolor='k')
plt.show()
现在有500个样本,分为5类make_blobs(n_samples=500,centers=5…),如下图所示:
我们通过颜色的差异可以看到这五类数据,其中有两类(黄色和橙色有些合为一起)。我们画出它的区域图,并且查看它的准确率。
代码语言:javascript复制 clf = KNeighborsClassifier()
clf.fit(X2,y2)
x_min,x_max = X2[:,0].min()-1,X2[:,0].max() 1
y_min,y_max = X2[:,1].min()-1,X2[:,1].max() 1
xx,yy = np.meshgrid(np.arange(x_min,x_max,.02),
np.arange(y_min,y_max,.02))#生成网格点坐标矩阵
Z = clf.predict(np.c_[xx.ravel(),yy.ravel()])#预测数据集X的结果
Z = Z.reshape(xx.shape)
plt.pcolormesh(xx, yy, Z,shading='auto',cmap=plt.cm.Spectral)#绘制分类图
plt.scatter(X2[:,0],X2[:,1],c=y2,cmap=plt.cm.spring,edgecolor='k')
plt.xlim(xx.min(),xx.max())#设置或查询 x 轴限制
plt.ylim(yy.min(),yy.max())#设置或查询 y 轴限制
plt.title("Classifier:KNN")
plt.show()
print('模型正确率:{:.2f}'.format(clf.score(X2,y2)))
输出:
代码语言:javascript复制模型正确率:0.96
模型正确率:0.96(96%),说明成绩还是可以的。
K邻近算法实现回归问题
介绍了分类问题,我们来看一下K邻近算法实现分类问题。
代码语言:javascript复制#导入make_regression数据集成生成器
from sklearn.datasets import make_regression
def sklearn_regression():
X,y = make_regression(n_features=1,n_informative=1,noise=50,random_state=8)
#将数据集用散点图方式进行可视化分析
plt.scatter(X,y,c='orange',edgecolor='k')
plt.show()
通过make_regression生成回归数据,并且仍旧通过plt.scatter方法以散点图方法显示。
代码语言:javascript复制 reg = KNeighborsRegressor()
# 用KNN模型拟合数据
reg.fit(X,y)
# 把预测结果图像化
z = np.linspace(-3,3,200).reshape(-1,1)
plt.scatter(X,y,c='orange',edgecolor='k')
plt.plot(z,reg.predict(z),c='k',linewidth=3)
plt.title("KNN Regressor")
plt.show()
print('模型正确率:{:.2f}'.format(reg.score(X,y)))
输出:
代码语言:javascript复制模型正确率:0.77
通过KNeighborsRegressor类的fit方法拟合数据,并且以折线方式显示出来。
这个时候。模型的正确率仅为0.77,拟合不好(我们从拟合折线也可以直观看出拟合不好)。在默认情况下,n_neighbors=5,我们下面把n_neighbors设置为2,看看拟合情况。
代码语言:javascript复制 reg = KNeighborsRegressor(n_neighbors=2)
reg.fit(X,y)
z = np.linspace(-3,3,200).reshape(-1,1)
plt.scatter(X,y,c='orange',edgecolor='k')
plt.plot(z,reg.predict(z),c='k',linewidth=3)
plt.title("KNN Regressor")
plt.show()
print('模型正确率:{:.2f}'.format(reg.score(X,y)))
输出:
代码语言:javascript复制模型正确率:0.86
拟合准确率提升到0.86,从图上我们也发现拟合程度比上次好。
案例1:红酒分类
上面我们采用make_blobs模拟数据来介绍K邻近算法,下面我们通过sklearn数据集来看一下K邻近算法的表现。
代码语言:javascript复制# 红酒案例
# 导入sklearn数据集
from sklearn import datasets
def Sklean_wine():
#导入红酒数据集
wine_dataset = datasets.load_wine()
print('红酒数据集中的键:{}'.format(wine_dataset.keys()))
输出:
代码语言:javascript复制红酒数据集中的键:dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names'])
- 数据:data
- 目标分类:target
- 设计:frame
- 目标分类名称:target_names
- 数据描述:DESCR
- 特征变量名称:feature_names
print('红酒数据概况:{}'.format(wine_dataset['data'].shape))
输出:
代码语言:javascript复制红酒数据概况:(178, 13)
说明红酒数据中有178个样本,13个特征变量。下面代码可以显示更详细的数据信息。
代码语言:javascript复制print('红酒数据:{}:n'.format(wine_dataset['data']))
输出:
代码语言:javascript复制红酒数据:
[[1.423e 01 1.710e 00 2.430e 00 ... 1.040e 00 3.920e 00 1.065e 03]
[1.320e 01 1.780e 00 2.140e 00 ... 1.050e 00 3.400e 00 1.050e 03]
[1.316e 01 2.360e 00 2.670e 00 ... 1.030e 00 3.170e 00 1.185e 03]
...
[1.327e 01 4.280e 00 2.260e 00 ... 5.900e-01 1.560e 00 8.350e 02]
[1.317e 01 2.590e 00 2.370e 00 ... 6.000e-01 1.620e 00 8.400e 02]
[1.413e 01 4.100e 00 2.740e 00 ... 6.100e-01 1.600e 00 5.600e 02]]
代码语言:javascript复制print('红酒数据描述:{}'.format(wine_dataset['DESCR']))
输出:
代码语言:javascript复制红酒数据描述:.. _wine_dataset:
Wine recognition dataset
------------------------
**Data Set Characteristics:**
:Number of Instances: 178 (50 in each of three classes)
:Number of Attributes: 13 numeric, predictive attributes and the class
:Attribute Information(属性信息):
- Alcohol
- Malic acid
- Ash
- Alcalinity of ash
- Magnesium
- Total phenols
- Flavanoids
- Nonflavanoid phenols
- Proanthocyanins
- Color intensity
- Hue
- OD280/OD315 of diluted wines
- Proline
- class:
- class_0
- class_1
- class_2
…
代码语言:javascript复制 #将数据分为训练集和测试集
X = wine_dataset['data']
y = wine_dataset['target']
#测试集占30%
X_train,X_test,y_train,y_test = train_test_split(X, y, random_state=0,test_size=0.3)
# 打印X_train,X_test,y_train,y_test的形态
print("X_train,的形态:{}".format(X_train.shape))
print("X_test的形态:{}".format(X_test.shape))
print("y_train的形态:{}".format(y_train.shape))
print("y_test的形态:{}".format(y_test.shape))
输出:
代码语言:javascript复制X_train,的形态:(124, 13)
X_test的形态:(54, 13)
y_train的形态:(124,)
y_test的形态:(54,)
从输出可以看出,训练集的数量124(124/178=70%),测试集的数量54 (54/178=30%)。
代码语言:javascript复制 #导入KNN算法
knn = KNeighborsClassifier(n_neighbors=1)
knn.fit(X_train,y_train)
print('测试数据的得分:{}:n'.format(knn.score(X_test,y_test)))
输出
代码语言:javascript复制测试数据的得分:0.7592592592592593:
代码语言:javascript复制#输出计算值
print(knn.predict(X_test))
#输出实际标签
print(y_test)
输出
代码语言:javascript复制[0 1 1 0 1 1 0 2 1 1 0 1 0 2 1 1 0 0 1 0 1 0 1 1 0 1 1 1 2 2 0 0 1 0 0 0 2 1 1 1 2 0 1 1 1 2 2 2 2 0 2 1 0 2]
[0 2 1 0 1 1 0 2 1 1 2 2 0 1 2 1 0 0 1 0 1 0 0 1 1 1 1 1 1 2 0 0 1 0 0 0 2 1 1 2 0 0 1 1 1 0 2 1 2 0 2 2 0 2]
数据得分为0.76,从输出结果也可以看出,有13个数据错误(54-13)/54=0.76。准确率才0.76,K邻近算法拟合度在红酒分类中表现不是太好。
不管如何,假设我们现在有一瓶酒,它的参数如下:
- Alcohol(酒精): 25.5
- Malic acid(苹果酸):3.14
- Ash(灰) : 3.22
- Alcalinity of ash(灰分的碱性) : 18.5
- Magnesium(镁) : 95.8
- Total phenols(总酚): 0.97
- Flavanoids(黄酮类化合物) :2.52
- Nonflavanoid phenols(非薰衣草酚类) :0.67
- Proanthocyanins(原花青素) :1.52
- Color intensity (彩色亮度): 7.3
- Hue(色彩) : 0.98
- OD280/OD315 of diluted wines(稀释葡萄酒的OD280/OD315) : 2.96
- Proline(脯氨酸) : 990
我们通过下面的程序进行判断。
代码语言:javascript复制 X_new = np.array([[25.5,3.14,3.22,18.5,95.8, 0.97, 2.52, 0.67, 1.52, 7.3, 0.98, 2.96, 990]])
prediction = knn.predict(X_new)
print('预测的红酒为:{}:n'.format(wine_dataset['target_names'][prediction]))
输出
代码语言:javascript复制预测的红酒为:['class_0']:
案例2:鸢尾花分类
由于代码与红酒相似,我们直接上代码。
代码语言:javascript复制def Sklean_iris():
# 加载数据其中的鸢尾花数据
iris_dataset = datasets.load_iris()
print('鸢尾花数据集中的键:{}'.format(iris_dataset.keys()))
print('鸢尾花数据概况:{}'.format(iris_dataset['data'].shape))
print('鸢尾花数据:{}:n'.format(iris_dataset['data']))
print('鸢尾花数据描述:{}'.format(iris_dataset['DESCR']))
#将数据分为训练集和测试集
X = iris_dataset['data']
y = iris_dataset['target']
#测试集占30%
X_train,X_test,y_train,y_test = train_test_split(X, y, random_state=0,test_size=0.3)
# 打印X_train,X_test,y_train,y_test的形态
print("X_train,的形态:{}".format(X_train.shape))
print("X_test的形态:{}".format(X_test.shape))
print("y_train的形态:{}".format(y_train.shape))
print("y_test的形态:{}".format(y_test.shape))
# 定义模型算法为K近邻分类器
knn = KNeighborsClassifier()
# 用fit完成训练
knn.fit(X_train,y_train)
print('测试数据的得分:{}:n'.format(knn.score(X_test,y_test)))
# 将测试数据集x_test运用到训练完成后的knn模型中去
print(knn.predict(X_test))
# 输出测试集中的真实结果
print(y_test)
输出:
代码语言:javascript复制鸢尾花数据集中的键:dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])
鸢尾花数据概况:(150, 4)
鸢尾花数据:
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
…
鸢尾花数据集中的键:dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])
鸢尾花数据概况:(150, 4)
鸢尾花数据:
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
…
鸢尾花数据描述:.. _iris_dataset:
Iris plants dataset
--------------------
**Data Set Characteristics:**
:Number of Instances: 150 (50 in each of three classes)
:Number of Attributes: 4 numeric, predictive attributes and the class
:Attribute Information:
- sepal length in cm
- sepal width in cm
- petal length in cm
- petal width in cm
- class:
- Iris-Setosa
- Iris-Versicolour
- Iris-Virginica
X_train,的形态:(105, 4)
X_test的形态:(45, 4)
y_train的形态:(105,)
y_test的形态:(45,)
测试数据的得分:0.9777777777777777:
[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 1 1 2 0 2 0 0]
[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 1 1 1 2 0 2 0 0]
运用K邻近算法对鸢尾花分类的准确度为0.98,非常好。
同样我们假设现在有一颗鸢尾花,它的数据为:
- sepal length in cm:4.5
- sepal width in cm :3.6
- petal length in cm :1.3
- petal width in cm :0.3
通过代码
代码语言:javascript复制 X_new = np.array([[4.5,3.6,1.3,0.3]])
prediction = knn.predict(X_new)
print('预测的鸢尾花为:{}:n'.format(iris_dataset['target_names'][prediction]))
输出
代码语言:javascript复制预测的鸢尾花为:['setosa']:
Sklean数据
上面介绍了Sklean的鸢尾花和红酒数据,Sklean.datasets还提供了其他静态数据和动态数据。
静态数据
数据集 | 函数 | 介绍 |
---|---|---|
鸢尾花数据集 | load_iris() | 用于分类任务的数据集 |
手写数字数据集 | load_digits() | 用于分类任务或者降维任务的数据集 |
乳腺癌数据集 | load_barest_cancer() | 简单经典的用于二分类任务的数据集 |
糖尿病数据集 | load_diabetes() | 经典的用于回归认为的数据集 |
波士顿房价数据集 | load_boston() | 经典的用于回归任务的数据集 |
体能训练数据集 | load_linnerud() | 经典的用于多变量回归任务的数据集 |
红酒数据集 | load_wine() | 经典的用于多变量回归任务的数据集 |
两个月亮集 | make_moons() | 二分类数据集,像两个月亮一样(太极) |
动态数据
函数 | 介绍 |
---|---|
fetch_olivetti_faces() | 脸部图片数据集 |
fetch_20newsgroups() | 用于文本分类、文本挖据和信息检索研究的国际标准数据集之一。数据集收集了大约20,000左右的新闻组文档,均匀分为20个不同主题的新闻组集合。返回一个可以被文本特征提取器。向量化后的数据fetch_20newsgroups_vectorized(),返回一个已提取特征的文本序列,即不需要使用特征提取器 |
fetch_lfw_people() | 打好标签的人脸数据集 |
fetch_lfw_pairs() | 该任务称为人脸验证:给定一对两张图片,二分类器必须预测这两个图片是否来自同一个人 |
fetch_covtype() | 森林植被类型,总计581012个样本,每个样本由54个维度表示(12个属性,其中2个分别是onehot4维和onehot40维),以及target表示植被类型1-7,所有属性值均为number,详情可调用fetch_covtype()['DESCR']了解每个属性的具体含义 |
fetch_rcv1() | 路透社新闻语料数据集 |
fetch_kddcup99() | KDD竞赛在1999年举行时采用的数据集,KDD99数据集仍然是网络入侵检测领域的事实Benckmark,为基于计算智能的网络入侵检测研究奠定基础,包含41项特征 |
fetch_california_housing() | 加利福尼亚的房价数据,总计20640个样本,每个样本8个属性表示,以及房价作为target,所有属性值均为number,详情可调用fetch_california_housing()['DESCR']了解每个属性的具体含义 |
fetch_species_distributions() | 物种分布数据集 |
Sklearn 交叉验证
人工智能分为训练集和测试集,训练集和测试集选择不当往往会造成过拟合或者欠拟合。我们可以通过交叉验证来解决这个问题。
我们把所有的样本数据分为n等份,第1次用第1个作为测试样本数据,第2…n个作为训练样本数据;第2次用第2个作为测试样本数据,第1、3…n个作为训练样本数据;….; 第n次用第n个作为测试样本数据,第1…n-1个作为训练样本数据。
代码语言:javascript复制#交叉验证法
from sklearn import svm
from sklearn.model_selection import cross_val_score
def Sklean_iris_cross_validation():
iris_dataset = datasets.load_iris()
X,y = datasets.load_iris(return_X_y=True)
print(X.shape,X.shape)
X_train,X_test,y_train,y_test = train_test_split(X, y, test_size=0.4, random_state=0)
print("X_train,的形态:{}".format(X_train.shape))
print("X_test的形态:{}".format(X_test.shape))
print("y_train的形态:{}".format(y_train.shape))
print("y_test的形态:{}".format(y_test.shape))
clf = svm.SVC(kernel='linear',C=1).fit(X_train,y_train)
print('交叉验证法前测试数据的得分:{}:n'.format(clf.score(X_test,y_test)))
clf = svm.SVC(kernel='linear',C=1)
scores = cross_val_score(clf,X,y,cv=5)#实现交叉验证,cv=5:分5组
print('交叉验证法后测试数据的得分:{}:n'.format(scores))
输出
代码语言:javascript复制(150, 4) (150, 4)
X_train,的形态:(90, 4)
X_test的形态:(60, 4)
y_train的形态:(90,)
y_test的形态:(60,)
交叉验证法前测试数据的得分:0.9666666666666667:
交叉验证法后测试数据的得分:[0.96666667 1. 0.96666667 0.96666667 1. ]:
可以看出使用交叉验证法后,有些情形下的得分竟然高达1.即100%正确,我们用交叉后的对上面鸢尾花的数据进行再次鉴别。特征数据为[4.5,3.6,1.3,0.3]
X_new = np.array([[4.5,3.6,1.3,0.3]])
代码语言:javascript复制 clf.fit(X_train,y_train)
prediction = clf.predict(X_new)
print('预测的鸢尾花为:{}:n'.format(iris_dataset['target_names'][prediction]))
输出
代码语言:javascript复制预测的鸢尾花为:['setosa']:
与上面一样,输出结果仍旧为setosa
过拟合和欠拟合
这里介绍一下过拟合和欠拟合。所谓欠拟合即不管在训练集还是在测试集上表现都不佳,欠拟合是由于训练不够造成的;所谓过拟合即不管在训练集还是在测试集上表现很高,但是在测试集上表现不佳,过拟合是由于训练过度造成的。
—————————————————————————————————