《机器学习实战》第二章学习笔记1(knn算法)
程序员文章站
2022-07-14 19:42:12
...
一、k-近邻分类算法
1.1 工作原理
存在一个样本数据集合,也称作训练样本集,并且样本集的每个数据都存在标签,即我们知道样本集的每一数据与所属分类的对应关系。输入没有标签的新数据后, 将新数据的每个特征与样本集的数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
1.2 一般流程
- 收集数据:可以使用任何方法。
- 准备数据:距离计算所需要的数值,最好是结构化的数据格式。
- 分析数据:可以使用任何方法。
- 训练算法:此步驟不适用于k-近邻算法。
- 测试算法:计算错误率。
- 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
1.3 优缺点及适用范围
- 优点:精度高、对异常值不敏感、无数据输入假定。
- 缺点:计算复杂度高、空间复杂度高。
- 适用数据范围:数值型和标称型。
二、使用k-近邻算法改进约会网站的配对效果
2.1 利用k-近邻算法实现分类器
代码示例:
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 12 21:23:22 2018
将该文件保存为kNN.py文件
@author: lizihua
"""
import numpy as np
import operator
import matplotlib.pyplot as plt
#k-近邻算法
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0] #获取行数
#计算欧式距离
#将inX扩维,使其与dataSet形状一致,以便实现获得X-dataSet数组
diffMat = np.tile(inX, (dataSetSize,1))-dataSet
sqdiffMat = diffMat**2
sqDisatances = sqdiffMat.sum(axis=1)
distances=sqDisatances**0.5
#argsort返回distance从小到大的排序索引,此时,distance并没有改变
sortedDistIndicies=np.argsort(distances)
classCount={}
for i in range(k):
#voteIlabel是按照distance从小到大排序的label
voteIlabel = labels[sortedDistIndicies[i]]
#计算前k个数中,各类出现的频率
classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
#对字典进行排序,并返回列表
#key=operator.itemgetter(1)代表按照第二个元素对字典排序,reversed=True代表从大到小排序
#返回列表形式,例如:[('B', 2), ('A', 1)]
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
#输入文件名,输出训练样本矩阵和类标签向量
def file2matrix(filename):
fr = open(filename)
arrayOfLines = fr.readlines()
numberOfLines = len(arrayOfLines)
#样本有三个特征
returnMat = np.zeros((numberOfLines,3))
classLabelVector = []
index = 0
for line in arrayOfLines:
line = line.strip()
listFormLine = line.split('\t')
#训练样本矩阵
returnMat[index,:] = listFormLine[0:3]
#类标签向量
classLabelVector.append(int(listFormLine[-1]))
index +=1
return returnMat,classLabelVector
#归一化特征值
#newValue = (oldValue - min)/(max-min)
def autoNorm(dataSet):
#求每一个特征的最小值、最大值及其差值
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = np.zeros(dataSet.shape)
m = dataSet.shape[0]
normDataSet = dataSet -np.tile(minVals,(m,1))
normDataSet = normDataSet/np.tile(ranges,(m,1))
return normDataSet, ranges, minVals
#测试
if __name__=="__main__":
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
normMat, ranges, minVals =autoNorm(datingDataMat)
print("归一化后的数据:",normMat)
print("三个特征的最大最小差值:",ranges)
print("三个特征的最小值:",minVals)
resultList = ['not at all','in small does','in large does']
inArr=np.array([10000,10,0.5])
resultindex = classify0(inArr,normMat,datingLabels,3)
print("你喜欢这个人的可能性:",resultList[resultindex])
#飞行常客里程数与视频游戏百分比之间的散点图
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],
15.0*np.array(datingLabels),15.0*np.array(datingLabels))
#飞行常客里程数与每周冰淇淋公斤数之间的散点图
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.scatter(datingDataMat[:,0],datingDataMat[:,2],
15.0*np.array(datingLabels),15.0*np.array(datingLabels))
#视频游戏百分比与每周冰淇淋公斤数之间的散点图
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
ax2.scatter(datingDataMat[:,1],datingDataMat[:,2],
15.0*np.array(datingLabels),15.0*np.array(datingLabels))
结果显示:
飞行常客里程数与视频游戏百分比之间的散点图:
飞行常客里程数与每周冰淇淋公斤数之间的散点图:
视频游戏百分比与每周冰淇淋公斤数之间的散点图:
2.2 验证分类器
代码示例:
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 12 20:25:41 2018
将该文件保存为kNN_test.py
@author: lizihua
"""
from kNN import file2matrix,autoNorm,classify0
def datingClassTest():
hoRatio = 0.10
datingDataMat,datingLabels =file2matrix('datingTestSet2.txt')
normMat, ranges, minVals =autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m*hoRatio)
errorCount = 0.0
for i in range(numTestVecs):
classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
print("预测结果:%d,实际结果:%d"%(classifierResult,datingLabels[i]))
if classifierResult!=datingLabels[i]:
errorCount +=1
print("错误率:",errorCount/numTestVecs)
#测试
if __name__=="__main__":
datingClassTest()
部分结果显示:
三、利用sklearn模块中的knn算法
代码示例:
# -*- coding: utf-8 -*-
"""
Created on Fri Apr 13 17:08:14 2018
@author: Administrator
"""
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
#输入文件名,输出训练样本矩阵和类标签向量
def file2matrix(filename):
fr = open(filename)
arrayOfLines = fr.readlines()
numberOfLines = len(arrayOfLines)
#样本有三个特征
returnMat = np.zeros((numberOfLines,3))
classLabelVector = []
index = 0
for line in arrayOfLines:
line = line.strip()
listFormLine = line.split('\t')
#训练样本矩阵
returnMat[index,:] = listFormLine[0:3]
#类标签向量
classLabelVector.append(int(listFormLine[-1]))
index +=1
return returnMat,classLabelVector
#归一化特征值
#newValue = (oldValue - min)/(max-min)
def autoNorm(dataSet):
#求每一个特征的最小值、最大值及其差值
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = np.zeros(dataSet.shape)
m = dataSet.shape[0]
normDataSet = dataSet -np.tile(minVals,(m,1))
normDataSet = normDataSet/np.tile(ranges,(m,1))
return normDataSet, ranges, minVals
#测试
if __name__=="__main__":
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
normMat, ranges, minVals =autoNorm(datingDataMat)
print("归一化后的数据:",normMat)
print("三个特征的最大最小差值:",ranges)
print("三个特征的最小值:",minVals)
hoRatio = 0.10
m = normMat.shape[0]
numTestVecs = int(m*hoRatio)
resultList = ['not at all','in small does','in large does']
#n_neighbors就是knn算法中的k,调用knn
neigh = KNeighborsClassifier(n_neighbors=3)
#训练:neigh.fit(X,y)//X是训练集,y是训练集对应的目标集,即分类标签
neigh.fit(normMat[numTestVecs:m], datingLabels[numTestVecs:m])
#预测回归结果:predict_proba(X)//X是测试集,返回预测回归结果(值)
#预测分类结果:neigh.predict(X)//X是测试集,返回预测的分类结果(分类值)
pred=neigh.predict(normMat[:numTestVecs])
#计算准确率
diff=pred-datingLabels[:numTestVecs]
acc=np.sum(diff==0)/numTestVecs
print("准确率:",acc)
结果显示: