机器学习测试笔记(10)——K邻近算法

2021-01-04 14:44:03 浏览数 (1)

监督学习和非监督学习

我们谈起机器学习经常会听到监督学习和非监督学习,它们的区别在哪里呢?监督学习是有标签的,而非监督学习是没有标签的。比如有一批酒,我们知道里面包括红酒和白酒,算法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
代码语言:javascript复制
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

过拟合和欠拟合

这里介绍一下过拟合和欠拟合。所谓欠拟合即不管在训练集还是在测试集上表现都不佳,欠拟合是由于训练不够造成的;所谓过拟合即不管在训练集还是在测试集上表现很高,但是在测试集上表现不佳,过拟合是由于训练过度造成的。

—————————————————————————————————

0 人点赞