数据挖掘十大算法–KNN算法。K-NN是一种基于实例的学习,或者是局部近似和将所有计算推迟到分类之后的惰性学习。k-近邻算法是所有的机器学习算法中最简单的之一。基于实例的学习方法只是简单地把训练样例存储起来。从这些实例中泛化的工作被推迟到必须分类新的实例时。每当学习器遇到一个新的查询实例,它分析这个新实例与以前存储的实例的关系,并据此把一个目标函数值赋给新实例。
KNN算法虽然简单,但是很经典,对于后续有监督学习算法的学习理解会有很大的帮助。
FLAG:以后相关的机器学习算法都要自己编程实现,然后和相关的库函数实现做一个对比。
KNN最邻近分类算法的实现原理:为了判断未知样本的类别,以所有已知类别的样本作为参照,计算未知样本与所有已知样本的距离,从中选取与未知样本距离最近的K个已知样本,根据少数服从多数的投票法则(majority-voting),将未知样本与K个最邻近样本中所属类别占比较多的归为一类。
KNN算法的关键之处在于:
1、样本的所有特征都要做可比较的量化
若是样本特征中存在非数值的类型,必须采取手段将其量化为数值。例如样本特征中包含颜色,可通过将颜色转换为灰度值来实现距离计算。
2、样本特征要视情况做归一化处理
样本有多个参数,每一个参数都有自己的定义域和取值范围,他们对距离计算的影响不一样,如取值较大的影响力会盖过取值较小的参数。所以样本参数必须做一些 scale 处理,最简单的方式就是所有特征的数值都采取归一化处置。
3、需要一个距离函数以计算两个样本之间的距离
通常使用的距离函数有:欧氏距离、余弦距离、汉明距离、曼哈顿距离等,一般选欧氏距离作为距离度量,但是这是只适用于连续变量。在文本分类这种非连续变量情况下,汉明距离可以用来作为度量。
K值选的太大易引起欠拟合,太小容易过拟合,需交叉验证确定K值。
k太小,分类结果易受噪声点影响;k太大,近邻中又可能包含太多的其它类别的点。(对距离加权,可以降低k值设定的影响)
k值通常是采用交叉检验来确定(以k=1为基准)
经验规则:k一般低于训练样本数的平方根
KNN算法是基于实例的学习算法,没有一个规则的训练过程,因此KNN算法没有严格的数学推导过程,这里也就不再探讨。
需要指出的是:
kNN是一种懒惰算法,平时不好好学习,考试(对测试样本分类)时才临阵磨枪(临时去找k个近邻)。
懒惰的后果:构造模型很简单,但在对测试样本分类地的系统开销大,因为要扫描全部训练样本并计算距离。
已经有一些方法提高计算的效率,例如压缩训练样本量等。
客户流失预测、欺诈侦测等(更适合于稀有事件的分类问题)
KNN算法的流程图如下:
本实例用到得到实验数据为python的机器学习库自带的尾花卉数据集,并且对数据进行分割,从而形成训练集和测试集
PCA算法实现的脚本如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import scipy.io as sio # load mat
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import random
from sklearn.datasets import load_iris #导入IRIS数据集
from sklearn import preprocessing#导入数据标准化模块
import operator
'''
使用sklearn实现需要额外导入一下依赖库
'''
# 导入数据集生成器
from sklearn.datasets import make_blobs
# 导入KNN 分类器
from sklearn.neighbors import KNeighborsClassifier
# 导入数据集拆分工具
from sklearn.model_selection import train_test_split
# 这两句代码用来正确显示图中的中文字体,后续都要加上
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
iris = load_iris() #鸢尾花数据集特征矩阵
#给多维数组提那家一列数据的两种方法
# data = np.c_[np.array(iris.data),np.array(iris.target)]
data = np.insert(iris.data,4,values = iris.target,axis=1)
data = pd.DataFrame(data,columns=['Length', 'Width','PetalLength','PetalLength','label'])
#数据集导出为excel文件
# data.to_excel('C:/Users/13109/desktop/鸢尾花数据集.xlsx',encoding="gb2312")
data = data.values
# print(data)
##拆分数据集为训练集和测试集 train[],test[]
def splitdata(data,split,train=[],test=[]):
for x in range(len(data)):
if random.random() <= split:
train.append(data[x])
else:
test.append(data[x])
return np.array(train),np.array(test)
train=[]
test=[]
train,test=splitdata(data,0.5,train,test)
# print(train)
#导出测试集作对比
test1 = pd.DataFrame(test,columns=['Length', 'Width','PetalLength','PetalLength','label'])
test1.to_excel('C:/Users/13109/desktop/鸢尾花测试集.xlsx',encoding="gb2312")
print('训练集样本量:' + repr(len(train)))
print('测试集样本量:' + repr(len(test)))
#获取k个近邻
def getneighbors(train,test,k):
datasize = train.shape[0]
data = np.tile(test, (datasize, 1))
distance = np.sqrt(np.sum(np.square(train[:,:-1]-data[:,:-1]),axis=1))
sortdistance = distance.argsort()
neighbors = []
for x in range(k):
np.array(neighbors.append(train[sortdistance[x], :]))
neighbors = np.array(neighbors)
return neighbors
# # print(data[:,:-1])
# distance = np.sqrt(np.sum(np.square(train[:,:-1] - data[:,:-1]), axis=1))
# sortdistance = distance.argsort()
# # print(sortdistance)
# neighbors = []
# for x in range (5):
# np.array(neighbors.append(train[sortdistance[x],:]))
# neighbors = np.array(neighbors)
# print(neighbors)
##在距离较近的k个实例中找到占比较大的分类
def getclassvotes(neighbors):
classvotes = {}
for x in range(len(neighbors)):
votelabel = neighbors[x,-1]
classvotes[votelabel] = classvotes.get(votelabel,0)+1
sortclass = sorted(classvotes.items(),key=operator.itemgetter(1),reverse=True)
predata = max(classvotes,key = classvotes.get)
return predata,sortclass
##计算KNN准确率
def accuracy(test,predata):
correct = 0
for i in range(len(test)):
if test[i,-1] == predata[i]:
correct+=1
accur = (correct/float(len(test)))*100.0
return accur
def main():
predictions = []
for i in range(len(test)):
neighbors = getneighbors(train,test[i],5)
result,sortclass = getclassvotes(neighbors)
predictions.append(result)
accur = accuracy(test,predictions)
print('KNN分类识别率: ' + repr(accur) + '%')
main()
(machine_learning) D:\CloudMusic\virtualenv\machine_learning\machine>python KNN.py
训练集样本量:83
测试集样本量:67
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0
, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.
0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0]
(自编脚本)KNN分类识别率: 98.50746268656717%
上面的代码是自己编程实现的KNN算法,下面我们再来直接调用scikit-learn库相关的代码来实现KNN,使用的数据集还是IRIS数据集。
###5.1、实现对鸢尾花数据集的分类
实现的脚本如下:
'''
使用Python的sklearn库进行KNN
KNeighborsClassifier(n_neighbors=5, weights='uniform',
algorithm='auto', leaf_size=30,
p=2, metric='minkowski',
metric_params=None, n_jobs=1, **kwargs)
n_neighbors: 默认值为5,表示查询k个最近邻的数目
algorithm: {‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’},指定用于计算最近邻的算法,auto表示试图采用最适合的算法计算最近邻
leaf_size: 传递给‘ball_tree’或‘kd_tree’的叶子大小
metric: 用于树的距离度量。默认'minkowski与P = 2(即欧氏度量)
n_jobs: 并行工作的数量,如果设为-1,则作业的数量被设置为CPU内核的数量
查看官方api:http://scikit-learn.org/dev/modules/generated/sklearn.neighbors.KNeighborsClassifier.html#sklearn.neighbors.KNeighborsClassifier
————————————————
'''
#划分训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(iris.data,
iris.target,
test_size = 0.5,
random_state=33)
# # 训练数据和测试数据进行归一化处理
# ss = preprocessing.MinMaxScaler()
# x_train = ss.fit_transform(x_train)
# x_test = ss.transform(x_test)
'''
KNN分类器的具体应用
'''
#建立一个模型对象
knc = KNeighborsClassifier(algorithm='auto',n_neighbors=5)
#输入训练数据建模
knc.fit(x_train, y_train)
#对测试数据进行预测
y_predict = knc.predict(x_test)
#打印对比预测结果和实际分类结果
print(y_predict+1 )
print(y_test+1)
x = range(1,len(y_predict)+1)
plt.scatter(x,y_predict+1,c='orange',edgecolor='k',label='KNN分类')
plt.scatter(x,y_test+1,c='k',edgecolor='r',label='实际分类')
plt.legend()
plt.show()
(machine_learning) D:\CloudMusic\virtualenv\machine_learning\machine>python KNN.py
训练集样本量:81
测试集样本量:69
(自编脚本)KNN分类识别率: 95.65217391304348%
scikit-learnj机器学习库分类准确率:98.66666666666667%
根据上述的的实验结果可以看出,自编脚本与scikit-learnj第三方库实现的结果基本一致,存在微小的差异。第三方库的准确率要高一点的主要原因,可能是近邻算法方面有所优化,knc = KNeighborsClassifier(algorithm=‘auto’,n_neighbors=5),参数algorithm='auto’表示自动选择最适合的算法计算最近邻。总的来说,差异不大。
###5.2、使用KNN算法进行回归分析并绘图
这里我们使用scikit-learn的make_regression生成数据集来进行实验,演示KNN算法在回归分析中的表现。
实验脚本如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
'''
基于邻居的回归可用于数据标签是连续的而不是离散的变量的情况。分配给查询点的标签是根据其最近邻居的标签的平均值计算的。
class sklearn.neighbors.KNeighborsRegressor(n_neighbors = 5,weights ='uniform',algorithm ='auto',
leaf_size = 30,p = 2,metric ='minkowski',metric_params = None,n_jobs = None,** kwargs )
n_neighbors:近邻个数,默认为5
weights:近邻权重函数,默认为'uniform','distance':weight points by the inverse of their distance.
in this case, closer neighbors of a query point will have a greater influence than neighbors which are further away.
algorithm:{'auto','ball_tree','kd_tree','brute'},可选,'auto'将尝试根据传递给fit方法的值来确定最合适的算法。
metric:默认度量标准是minkowski,p = 2等于标准欧几里德度量标准
'''
import matplotlib.pyplot as plt
import numpy as np
# 导入用于回归分析的KNN模型
from sklearn.neighbors import KNeighborsRegressor
# 导入数据集拆分工具
from sklearn.model_selection import train_test_split
# 导入随机回归数据集生成器
from sklearn.datasets.samples_generator import make_regression
# 这两句代码用来正确显示图中的中文字体,后续都要加上
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
'''
介绍一下sklearn.datasets.make_regression函数用于生成随机回归数据
sklearn.datasets.make_regression(n_samples=100, n_features=100, n_informative=10, n_targets=1,
bias=0.0, effective_rank=None, tail_strength=0.5, noise=0.0, shuffle=True, coef=False, random_state=None)
其中比较重要的参数为:
n_samples : int,可选(默认值= 100)样本数量。
n_features:样本特征维度,也就是X维度
n_informative : int,optional(默认值= 10),信息特征的数量,即用于构建用于生成输出的线性模型的特征的数量。
n_targets : int,optional(默认值= 1),也就是y输出向量的维数。
noise : float,optional(默认值= 0.0)应用于输出的高斯噪声的标准偏差。
random_state:None(默认),数据集随机种子
'''
# 生成样本数为100,
X,Y=make_regression(n_samples=100,n_features=1,n_informative=10,noise=50,random_state=8)
##生成KNN回归对象
reg = KNeighborsRegressor(n_neighbors=5,weights='uniform',algorithm='auto',p = 2)
#X作为训练数据并使用y作为目标值来拟合模型
reg.fit(X,Y)
# 将预测结果用图像进行可视化
z = np.linspace(-3,3,200).reshape(-1,1)
#预测所提供数据的目标
Y_predict = reg.predict(z)
#返回回归拟合优度
r2 = reg.score(X,Y)
print('拟合优度为:'+ repr(r2))
plt.scatter(X,Y,c='orange',edgecolor='k',label = '实际数据点')
plt.plot(z,Y_predict,c='k',Linewidth=3,label = 'KNN回归预测曲线')
plt.title("K近邻回归")
plt.legend()
plt.show()
脚本运行的输出结果如下:
(machine_learning) D:\CloudMusic\virtualenv\machine_learning\machine>python KNN_regression.py
拟合优度为:0.7721167832505298
回归效果对比图如下:
KNN算法的主要优点:
KNN算法的主要缺点:
适用条件: