【机器学习】KNN算法介绍及py实现(详细代码,通俗易懂)

KNN算法(K-Nearest Neighbors)

目标

看完这篇博客你将学会:

  • 用KNN算法来对数据进行分类

在这里,我们将用knn对一个顾客数据集进行分类。不过什么是knn呢,什么是K-Nearest Neighbors,直观翻译就是k个最近的邻居。

K-Nearest Neighbors是一种监督学习算法,为了预测未知数据的类别,它考虑了k个最近数据点的类别,并选择k个最近数据点中的大多数属于的那个类别作为预测类别。

这是KNN的直观表示

在这种情况下,我们有 A 类和 B 类的数据点。我们想预测星(测试数据点)是什么。 如果我们考虑 k 值为 3(3 个最近的数据点),我们将获得 B 类的预测。然而,如果我们考虑 k 值为 6,我们将获得 A 类的预测。

从这个意义上说,重要的是要考虑 k 的值。 希望从这张图中,您应该了解什么是 K-Nearest Neighbors 算法。 它在预测测试点的分类时会考虑“K”个最近邻(数据点)。

安装sklearn以及导入包

!pip install scikit-learn==0.23.1

导入需要的包

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn import preprocessing
%matplotlib inline

关于数据集

想象一下,一家电信供应商已经按照服务使用模式对其客户群进行了细分,将客户分为四组。 如果人口统计数据可用于预测团体成员,公司可以为个别潜在客户定制优惠。 这是一个分类问题。 也就是说,给定具有预定义标签的数据集,我们需要建立一个模型来预测新案例或未知案例的类别。

这个例子侧重于使用人口统计数据(例如地区、年龄和婚姻)来预测。

名为 custcat 的目标字段有四个可能的值,对应于四个客户组,如下所示:

1- Basic Service
2- E-Service
3- Plus Service
4- Total Service

我们的目标是建立一个分类器,来预测未知案例的类别。 我们就将使用这次的knn来分类。

下载数据

https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBMDeveloperSkillsNetwork-ML0101EN-SkillsNetwork/labs/Module%203/data/teleCust1000t.csv

df = pd.read_csv('teleCust1000t.csv')
df.head()
regiontenureagemaritaladdressincomeedemployretiregenderresidecustcat
0213441964.0450.0021
13113317136.0550.0064
236852124116.01290.0123
32333301233.0200.0111
4223301930.0120.0043

数据可视化及分析

让我们看看数据集中每个类别有多少
df['custcat'].value_counts()
3    281
1    266
4    236
2    217
Name: custcat, dtype: int64
281 Plus Service, 266 Basic-service, 236 Total Service, and 217 E-Service customers

我们也可以画一个分布直方图来可视化一下

df.hist(column='income', bins=50)


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NMbqQmvn-1660611613546)(output_20_1.png)]

特征集合

我们来定义特征集合, X:

df.columns
Index(['region', 'tenure', 'age', 'marital', 'address', 'income', 'ed',
       'employ', 'retire', 'gender', 'reside', 'custcat'],
      dtype='object')

要使用 scikit-learn 库,我们必须将 Pandas 数据框转换为 Numpy 数组:

X = df[['region', 'tenure','age', 'marital', 'address', 'income', 'ed', 'employ','retire', 'gender', 'reside']] .values  #.astype(float)
X[0:5]

array([[  2.,  13.,  44.,   1.,   9.,  64.,   4.,   5.,   0.,   0.,   2.],
       [  3.,  11.,  33.,   1.,   7., 136.,   5.,   5.,   0.,   0.,   6.],
       [  3.,  68.,  52.,   1.,  24., 116.,   1.,  29.,   0.,   1.,   2.],
       [  2.,  33.,  33.,   0.,  12.,  33.,   2.,   0.,   0.,   1.,   1.],
       [  2.,  23.,  30.,   1.,   9.,  30.,   1.,   2.,   0.,   0.,   4.]])

再来看看我们的标签

y = df['custcat'].values
y[0:5]
array([1, 4, 3, 1, 3], dtype=int64)

标准化数据

数据标准化,就是让数据变成均值为0,方差为1。这个做法很好,特别是对于基于数据点距离的knn算法。

X = preprocessing.StandardScaler().fit(X).transform(X.astype(float))
X[0:5]
array([[-0.02696767, -1.055125  ,  0.18450456,  1.0100505 , -0.25303431,
        -0.12650641,  1.0877526 , -0.5941226 , -0.22207644, -1.03459817,
        -0.23065004],
       [ 1.19883553, -1.14880563, -0.69181243,  1.0100505 , -0.4514148 ,
         0.54644972,  1.9062271 , -0.5941226 , -0.22207644, -1.03459817,
         2.55666158],
       [ 1.19883553,  1.52109247,  0.82182601,  1.0100505 ,  1.23481934,
         0.35951747, -1.36767088,  1.78752803, -0.22207644,  0.96655883,
        -0.23065004],
       [-0.02696767, -0.11831864, -0.69181243, -0.9900495 ,  0.04453642,
        -0.41625141, -0.54919639, -1.09029981, -0.22207644,  0.96655883,
        -0.92747794],
       [-0.02696767, -0.58672182, -0.93080797,  1.0100505 , -0.25303431,
        -0.44429125, -1.36767088, -0.89182893, -0.22207644, -1.03459817,
         1.16300577]])

训练/测试集分割

Out of Sample Accuracy 是模型对模型未经过训练的数据做出的正确预测的百分比。 由于我们的模型过度拟合的可能性,在同一数据集上进行训练和测试很可能具有较低的样本外准确度。

重要的是,我们的模型具有较高的样本外准确度,因为任何模型的目的当然是对未知数据做出正确的预测。 那么我们如何提高样本外的准确性呢? 一种方法是使用一种称为训练/测试拆分的评估方法。

训练/测试拆分涉及将数据集分别拆分为互斥的训练集和测试集。 之后,您使用训练集进行训练并使用测试集进行测试。

这将对样本外准确性提供更准确的评估,因为测试数据集不是用于训练模型的数据集的一部分。 对于现实世界的问题,它更精准一些。

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=4)
print ('Train set:', X_train.shape,  y_train.shape)
print ('Test set:', X_test.shape,  y_test.shape)
Train set: (800, 11) (800,)
Test set: (200, 11) (200,)

分类

K nearest neighbor (KNN)

导入包

分类器实现 k 近邻投票。

from sklearn.neighbors import KNeighborsClassifier

训练

我们首先看看k的4的时候的情形:

k = 4
#Train Model and Predict  
neigh = KNeighborsClassifier(n_neighbors = k).fit(X_train,y_train)
neigh
KNeighborsClassifier(n_neighbors=4)

预测

我们可以用训练出来的模型在测试集上进行预测:

yhat = neigh.predict(X_test)
yhat[0:5]
array([1, 1, 3, 2, 4], dtype=int64)

准确性评估

在多标签分类中,accuracy classification score准确度分类得分)是计算子集准确度的函数。 此函数等同于 jaccard_score 函数。 本质上,它计算测试集中实际标签和预测标签的匹配程度。

from sklearn import metrics
print("Train set Accuracy: ", metrics.accuracy_score(y_train, neigh.predict(X_train)))
print("Test set Accuracy: ", metrics.accuracy_score(y_test, yhat))
Train set Accuracy:  0.5475
Test set Accuracy:  0.32

进一步练习

这次我们把k改成10。

# write your code here
k = 10
neigh10 = KNeighborsClassifier(n_neighbors = k).fit(X_train,y_train)
yhat10 = neigh10.predict(X_test)
print("Train set Accuracy: ", metrics.accuracy_score(y_train, neigh10.predict(X_train)))
print("Test set Accuracy: ", metrics.accuracy_score(y_test, yhat10))


Train set Accuracy:  0.4875
Test set Accuracy:  0.33
那其他的k呢?

KNN 中的 K 是要检查的最近邻的数量。 由用户指定,是最重要的参数。 那么,我们如何才能为 K 选择正确的值呢?
一般的解决方案是保留一部分数据用于测试模型的准确性。 然后选择k = 1,使用训练部分进行建模,并使用测试集中的所有样本计算预测的准确性。 重复这个过程,增加 k,看看哪个 k 最适合我们的模型。

我们可以计算 KNN 对不同 k 值的准确度。

Ks = 10
mean_acc = np.zeros((Ks-1))
std_acc = np.zeros((Ks-1))

for n in range(1,Ks):
    
    #Train Model and Predict  
    neigh = KNeighborsClassifier(n_neighbors = n).fit(X_train,y_train)
    yhat=neigh.predict(X_test)
    mean_acc[n-1] = metrics.accuracy_score(y_test, yhat)

    
    std_acc[n-1]=np.std(yhat==y_test)/np.sqrt(yhat.shape[0])

mean_acc
array([0.3  , 0.29 , 0.315, 0.32 , 0.315, 0.31 , 0.335, 0.325, 0.34 ])
绘制不同k的knn模型的准确性的图.
plt.plot(range(1,Ks),mean_acc,'g')
plt.fill_between(range(1,Ks),mean_acc - 1 * std_acc,mean_acc + 1 * std_acc, alpha=0.10)
plt.fill_between(range(1,Ks),mean_acc - 3 * std_acc,mean_acc + 3 * std_acc, alpha=0.10,color="green")
plt.legend(('Accuracy ', '+/- 1xstd','+/- 3xstd'))
plt.ylabel('Accuracy ')
plt.xlabel('Number of Neighbors (K)')
plt.tight_layout()
plt.show()


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-juwWjGc7-1660611613548)(output_50_0.png)]

print( "The best accuracy was with", mean_acc.max(), "with k=", mean_acc.argmax()+1) 
The best accuracy was with 0.34 with k= 9

谢谢大家的观看。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KNN算法是一种基于实例的学习算法,它的基本思想是将样本集中与待分类样本最近的K个样本作为参考,根据这K个样本的类别来判断待分类样本的类别。KNN算法的优点是简单易懂,不需要建立模型,分类效果较好,但是由于其计算量较大,对于大规模数据集不太适用。 以下是KNN算法的matlab代码实现: 1. 加载数据集 假设我们有一个数据集,其中包含3个样本,每个样本有2个特征。我们可以将数据集表示为一个3行2列的矩阵。 ```matlab data = [1 2; 2 1; 3 4]; ``` 2. 定义待分类样本 我们定义一个待分类样本,它有2个特征。 ```matlab testData = [2 3]; ``` 3. 计算距离 我们使用欧氏距离来计算每个样本与待分类样本之间的距离,距离计算公式为: $$d(x,y)=\sqrt{\sum_{i=1}^{n}(x_i-y_i)^2}$$ ```matlab dist = sqrt(sum((data - repmat(testData,size(data,1),1)).^2,2)); ``` 其中,`repmat(testData,size(data,1),1)`表示将待分类样本重复3次,然后与数据集相减,再对每个样本进行求和,最后取平方根,即可得到每个样本与待分类样本之间的距离。 4. 选择K个最近的样本 我们选择距离最小的K个样本作为参考,这里我们选择K=2。 ```matlab k = 2; [~, idx] = sort(dist); kIdx = idx(1:k); ``` 其中,`[~, idx] = sort(dist)`表示将距离从小到大排序,`kIdx = idx(1:k)`表示选择前K个最近的样本。 5. 统计K个最近样本的类别 我们统计K个最近样本的类别,并选择出现次数最多的类别作为待分类样本的类别。 ```matlab labels = [1 1 2]; testLabel = mode(labels(kIdx)); ``` 其中,`labels`表示每个样本的类别,这里我们假设有2个类别,分别为1和2,`mode`函数表示选择出现次数最多的元素。 完整代码如下: ```matlab data = [1 2; 2 1; 3 4]; testData = [2 3]; dist = sqrt(sum((data - repmat(testData,size(data,1),1)).^2,2)); k = 2; [~, idx] = sort(dist); kIdx = idx(1:k); labels = [1 1 2]; testLabel = mode(labels(kIdx)); ``` 以上就是KNN算法的matlab代码实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值