KNN算法

近邻算法与应用实践


"""
K最近邻算法
kNN算法的核心思想是:
存在一个样本数据集合,也称作训练样本集合,并且样本集中每个数据都存在标签,即
我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新数据
的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)
的分类标签。一般来说K是不大于20的整数。最后,选择最相似数据中出现次数最多的分类,作为新
数据的分类。
 
优点是:精度高、对异常值不敏感、无数据输入假定。
缺点:计算复杂度、空间复复杂度高
适用数据范围: 数值型和标称型
"""

from numpy import *
import operator

def creatDataSet():
group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels

group, labels = creatDataSet()
print('group')
print(group)
print('labels')
print(labels)



"""
KNN算法使用
对未知类别属性的数据集中的每个点一次执行以下操作:
(1)计算已知类别数据集中的点与当前点之间的距离;
(2)按照距离递增次序排序
(3)选取与当前点距离最小的k个点
(4)确定前K个点所在类别的出现频率
(5)返回前k个点出现频率最高的类别作为当前点的预测分类
"""

def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
# print(tile(inX, (dataSetSize, 1)).shape)
# print(dataSet.shape)
# 为了与dataSet的shape一样,所以需要扩充
diffMat = tile(inX, (dataSetSize, 1)) - dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis = 1)
distances = sqDistances**0.5
sortedDistIndicies = distances.argsort()
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
# print(type(classCount.items()))
# print(classCount.items())
# 注意python的dict去除了iteritems,而使用items返回一个(key, value)视图
sortedClassCount = sorted(classCount.items(),
key = operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]

classify0([0, 0], group, labels, 3)



"""
示例:在约会网站上使用k-近邻算法,根据未知标签数据进行分类
(1)收集数据:提供文本文件
(2)准备数据:使用Python解析文本文件
(3)分析数据:使用Matplotlib画二维扩散图
(4)训练算法:此步骤不适用于k-近邻算法
(5)测试算法:使用海伦提供的部分数据作为测试样本。“测试样本具有三种标签:不喜欢的人,魅力一般的人,极具魅力的人”。
测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类与实际类别的不同,则标记为一个错误。
(6)使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否为自己喜欢的类型。
"""

"""
将文本记录转换为NumPy的解析程序
数据格式如下
40920 8.326976 0.953952 largeDoses
含义是(从左往右):
每年获得的飞行常客里程数
玩视频游戏所消耗时间百分比
每周消费的冰淇淋公升数
"""

def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines)
returnMat = zeros((numberOfLines,3))
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index, :] = listFromLine[0:3]
# 这里的类型转换需要明白原始数据最后一列是否是整型数据
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat, classLabelVector

datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
print(type(datingDataMat), datingDataMat.dtype)
print(datingDataMat[0:5])
print(type(datingLabels))
print(datingLabels[0:5])



"""
分析数据:使用matplotlib创建散点图
"""
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt

# 创建一个图表
fig = plt.figure()
# 在图标中创建一个画板
ax = fig.add_subplot(111)
# 在相应的画板绘制数据点,使用列2和列3数据
ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2])
plt.show()



# 绘制不同大小和颜色的数据点,为了便于区分
 
# 创建一个图表
fig = plt.figure()
ax = fig.add_subplot(111)
# 在相应的画板绘制数据点,使用列2和列3数据
# x,y, 大小, 颜色
ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2], 15.0*array(datingLabels), 15.0*array(datingLabels))
plt.show()



# 绘制不同大小和颜色的数据点,使用其他列数据,发现更好区分了
 
# 创建一个图表
fig = plt.figure()
ax = fig.add_subplot(111)
# 在相应的画板绘制数据点,使用列2和列3数据
# x,y, 大小, 颜色
ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1], 15.0*array(datingLabels), 15.0*array(datingLabels))
plt.show()


# 数据中有3列数据值,他们都是不同的单位测出来的
# 如果使用sqrt((a1-b1)^2 + (a2-b2)^2 + (a3-b3)^2) 因为不同单位,决定距离的可能是某一个数值很大的列
# 所以在进行求距离前,需要对数据进行归一化
def autoNorm(dataSet):
# 0参数表示选取列的最小值
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m, 1))
normDataSet = normDataSet/tile(ranges,(m, 1))
return normDataSet, ranges, minVals

normMat, ranges, minVals = autoNorm(datingDataMat)
print(normMat)



"""
分类器针对约会网站的测试代码
"""
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('the classifier came back with: ', classifierResult, ' the real answer is: ', datingLabels[i])
if (classifierResult != datingLabels[i]): errorCount += 1.0
print('the total error rate is: ', (errorCount/float(numTestVecs)))

datingClassTest()


def classifyPerson():
resultList = ['not at all', 'in small doses', 'in large doses']
percentTats = float(input(\
"percentage of time spent playing video games? "))
ffMiles = float(input("frequent flier miles earned per year? "))
iceCream = float(input("liters of ice cream consumed per year? "))
datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
inArr = array([ffMiles, percentTats, iceCream])
# 传参数的时候顺便归一化
classifierResult = classify0((inArr-\
minVals)/ranges, normMat, datingLabels, 3)
print('You will probably like this person: ',\
resultList[classifierResult - 1])

classifyPerson()


"""
准备数据:将图像转换为测试向量
"""
 
def img2vector(filename):
returnVect = zeros((1, 1024))
# 一个文件是一个数字,一个数字是一个32 x 32的布尔型数字
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0, 32*i + j] = int(lineStr[j])
return returnVect

testVector = img2vector('digits/testDigits/0_13.txt')
testVector[0, 0:31]


testVector[0, 32:64]



"""
因为数字的样本特别多,即文件特别多。
这里用到了os模块中的listdir函数
"""
from os import listdir
 
def handwritingClassTest():
hwLabels = []
# 读入所有训练数据
trainingFileList = listdir('digits/trainingDigits')
m = len(trainingFileList)
trainingMat = zeros((m,1024))
for i in range(m):
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
trainingMat[i, :] = img2vector('digits/trainingDigits/{0}'.format(fileNameStr))
testFileList = listdir('digits/testDigits')
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector('digits/testDigits/{0}'.format(fileNameStr))
classifierResult = classify0(vectorUnderTest, \
trainingMat, hwLabels, 3)
# print('the classifier came back with: ', classifierResult, 'the real answer is: ', classNumStr)
if (classifierResult != classNumStr) : errorCount += 1.0
print("\nthe total number of errors is: ", errorCount)
print("\nthe total error rate is: ", errorCount/float(mTest))

handwritingClassTest()


"""
总结:
k-近邻算法是分类数据最简单最有效的方法,它的特点是:
1、k-近邻算法是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数据。
2、k-近邻算法必须保存全部数据集,如果训练数据集很大,必须使用大量的存储空间。
3、由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时。
4、无法给出任何数据的基础结构信息,我们也无法知晓平均实例样本和典型实例样本具有什么特征。
"""

参考《机器学习实战》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值