【K-近邻】
文章目录
全文代码及数据
提取码:27kp
1.难点说明
np.tile()
复制
>>>b = np.array([[1,2],[3,4]])
>>>np.tile(b, 2)
array([[1, 2, 1, 2],
[3, 4, 3, 4]])
>>> np.tile(b, (2, 1))
array([[1, 2],
[3, 4],
[1, 2],
[3, 4]])
argsort()
获取排序(有小到大)后的距离值的索引(序号)
字典(Dictionary)
dict.get() 函数
返回指定键的值,如果值不在字典中返回默认值
dict.get(key, # 字典中要查找的键
default=None # 如果指定键的值不存在时,返回该默认值值
)
dict.items()函数
dic.items() 将字典中的元素以列表形式显示出来
>>>dict={'A': 2, 'C': 3, 'B': 1}
>>>dict.items()
dict_items([('A', 2), ('C', 3), ('B', 1)])
sorted()
'''对字典按照 value 进行排序'''
sortedClassCount = sorted(classCount.items(), # classCount字典分解为元组列表
key=operator.itemgetter(1), # 按照第二个元素的次序对元组进行排序
reverse=True) # 是逆序
os.listdir()
用于返回指定的文件夹包含的文件或文件夹的名字的列表。这个列表以字母顺序
os.listdir(path)
2.伪代码
对未知类别属性的数据集中每个点依次执行以下的操作
- 计算已知类别数据集中的点与当前点之间的距离
- 按照距离递增次序排序
- 选取与当前点距离最小的k个点
- 确定前k个点所在类别的出现频率
- 返回前k个点出现频率最高的类别作为当前点的预测分类
3.实施kNN分类算法(kNN.py)
import numpy as np
import matplotlib.pyplot as plt
import operator # 导入运算模块
def createDataSet():
group=np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels=['A','A','B','B']
return group, labels
def plotknn(group, labels):
n = np.shape(group)[0]
xcord1 = [];ycord1 = []
xcord2 = [];ycord2 = []
for i in range(n):
if int(labels[i]=='A'):
xcord1.append(group[i,0]);ycord1.append(group[i,1])
else:
xcord2.append(group[i,0]);ycord2.append(group[i,1])
fig = plt.figure() # 生成一个新的图片
ax = fig.add_subplot(111) # 创建一个或多个子图(subplot)
ax.scatter(xcord1,ycord1,c='red', marker='s')
ax.scatter(xcord2,ycord2, c='green')
plt.legend(['A','B']) # 添加图例
plt.show()
def classify0(inX, dataSet, labels, K):
'''算法实现
@ inX 测试样本数据
@ 训练样本数据
@ 标签
@ K 选取的k 值
'''
dataSetSize = dataSet.shape[0] # 数据集的行(即数据大小)
# 将inX复制成dataSeSize行,计算与数据集dataSet间的距离
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
sqDiffMat = diffMat**2
sqdistances = sqDiffMat.sum(axis=1) # 每一行相加
distances = sqdistances**0.5 # 开根号得出距离
#获取排序(由小到大)后的距离值的索引(序号)
sortedDistIndicies = distances.argsort()
classCount={}
# 获取最近的K个点
for i in range(K):
# 获取该索引对应的样本标签
voteIlabel = labels[sortedDistIndicies[i]]
#累加几类标签出现的次数,构成键值对key/values并存于classCount中
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
# 对字典中的 values 进行反序排序(由大到小)
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1), reverse=True)
# 返回第一个元素(最高频率)的标签
return sortedClassCount[0][0]
if __name__=='__main__':
group, labels = createDataSet()
plotknn(group, labels)
print('[0,0]的类别是:',classify0([0,0], group,labels,3))
[0,0]的类别是: B
4.示例:k-近邻算法改进约会网站的匹配效果(kNN_1.py)
import numpy as np
import matplotlib.pyplot as plt
import kNN
def file2matrix(filename):
'''数据的读取'''
fr = open(filename)
arrayOLines = fr.readlines() # 读取文件的每一行,组成一个字符串列表
numberOLines = len(arrayOLines) # 得到文件的行
returnMat = np.zeros((numberOLines,3)) # 得到一个数组(n,3)
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip() #去掉字符串头尾的空格
listFromLine = line.split('\t') #分割
# listFromLine的前三个元素依次存入returnmat的index行的三列
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1])) # 标签
index += 1
return returnMat, classLabelVector
def autoNorm(dataSet):
'''归一化数据'''
minVals = dataSet.min(0)
maxVals = dataSet.max(0) # 每一列的最大值和最小值
ranges = maxVals - minVals
normDataSet = np.zeros(np.shape(dataSet)) # 创建与dataSet等大小的矩阵
m = dataSet.shape[0] # 数据的个数
normDataSet = dataSet - np.tile(minVals, (m,1)) # 将dataSet的每一行的对应列减去minVals中对应列的最小值
#归一化,公式newValue=(value-minvalue)/(maxVal-minVal)
normDataSet = normDataSet / np.tile(ranges, (m,1))
return normDataSet, ranges, minVals
def plotKnn_1(datingDataMat, datingLabels):
'''绘制图形'''
fig=plt.figure()
ax=fig.add_subplot(111)
# 直接绘制
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*np.array(datingLabels),15.0*np.array(datingLabels))
plt.show()
def datingClassTest():
'''分类器针对约会网站的测试代码'''
hoRatio = 0.10
# 获取数据
datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
# 归一化
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0] # 获取数据数
numTestVecs = int(hoRatio*m) # 测试样本数量
errorCount =0.0
for i in range(numTestVecs):
# 利用分类函数classify0获取测试样本数据分类结果
classifierResult = kNN.classify0(normMat[i,:], normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
print('预测结果为',classifierResult,'实际标签为',datingLabels[i])
if(classifierResult != datingLabels[i]):errorCount+=1.0
print('误差率为:',errorCount/float(numTestVecs))
def classifyPerson():
'''构建可手动输入系统'''
resultList = ['不喜欢','魅力一般','极具魅力'] # 定义预测结果
percentTats = float(input("玩视频游戏所耗时间百分比?"))
ffMiles = float(input("每年获取的分行常客里程数?"))
iceCream = float(input("每周消耗的冰淇淋公斤数?")) # 输入数据
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt') #读取数据
normMat,ranges,minValues=autoNorm(datingDataMat)
inArr = np.array([ffMiles,percentTats,iceCream]) # 输入数据放在数组中
classifierResult = kNN.classify0((inArr-minValues)/ranges, normMat, datingLabels, 3)
print("对这个人的评价:",resultList[classifierResult-1])
if __name__=='__main__':
datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
print(datingDataMat[0:5])
print(datingLabels[0:5])
plotKnn_1(datingDataMat, datingLabels)
normMat, ranges, minVals = autoNorm(datingDataMat)
print(normMat[0:20])
datingClassTest()
classifyPerson()
玩视频游戏所耗时间百分比?10
每年获取的分行常客里程数?10000
每周消耗的冰淇淋公斤数?0.5
对这个人的评价: 魅力一般
5.示例:手写数字识别系统(kNN_2.py)
trainingDigits 中大约有2000个例子
testDigits 中大约有900个例子
import numpy as np
import os
def img2vector(filename):
'''图像大小32*32,转为为1024向量'''
returnVec = np.zeros((1,1024))
fr = open(filename)
# 读取每一行内容
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVec[0,32*i+j] = int(lineStr[j])
return returnVec
def handwritingClassTest():
'''k-近邻算法识别手写数字'''
hwLabels = []
# 列出给定目录的文件名列表
trainingFileList = os.listdir('digits/trainingDigits')
m = len(trainingFileList) #获取列表的长度
trainingMat = np.zeros((m,1024)) # 创建一个矩阵用来存储训练数据
for i in range(m):
fileNameStr = trainingFileList[i] # 获取当前的字符串
fileStr=fileNameStr.split('.')[0] # 将字符串按照'.'分开,并将前一部分放于fileStr
classNumStr=int(fileStr.split('_')[0]) #将fileStr按照'_'分开,并将前一部分存于classNumStr
hwLabels.append(classNumStr) # 将每个标签值全部存入一个列表中
#解析目录中的每一个文件,将图像转化为向量,最后存入训练矩阵中
trainingMat[i,:] = img2vector('digits/trainingDigits/%s' %fileNameStr)
'''对测试集进行处理'''
testFileList = os.listdir('digits/testDigits')
errorCount=0.0
mTest=len(testFileList)
for i in range(mTest):
#获取第i行的文件名
fileNameStr = testFileList[i]
#将字符串按照'.'分开,并将前一部分放于fileStr
fileStr = fileNameStr.split('.')[0]
#将fileStr按照'_'分开,并将前一部分存于classNumStr
classNumStr = int(fileStr.split('_')[0])
#解析目录中的每一个文件,将图像转化为向量
vectorUnderTest = img2vector('digits/testDigits/%s' %fileNameStr)
classifierResult = kNN.classify0(vectorUnderTest,trainingMat,hwLabels,3) # 预测结果
print('预测结果:',classifierResult,'真实结果:',classNumStr)
if(classifierResult != classNumStr):errorCount+=1.0
print("\n整个错误数: %d" %errorCount)
print("\n整个错误率: %f" %(errorCount/float(mTest)))
if __name__=='__main__':
# testVector = img2vector('digits/testDigits/0_13.txt')
handwritingClassTest()
预测结果: 9 真实结果: 9
预测结果: 9 真实结果: 9
整个错误数: 10
整个错误率: 0.010571