前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >机器学习测试笔记(10)——K邻近算法

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

作者头像
顾翔
发布2021-01-04 14:44:03
5570
发布2021-01-04 14:44:03
举报
文章被收录于专栏:啄木鸟软件测试

监督学习和非监督学习

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

过拟合和欠拟合

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
主机安全
主机安全(Cloud Workload Protection,CWP)基于腾讯安全积累的海量威胁数据,利用机器学习为用户提供资产管理、木马文件查杀、黑客入侵防御、漏洞风险预警及安全基线等安全防护服务,帮助企业构建服务器安全防护体系。现支持用户非腾讯云服务器统一进行安全防护,轻松共享腾讯云端安全情报,让私有数据中心拥有云上同等级别的安全体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档