这次分享的是第二章K-近邻算法
具体理论知识就不写出来了,关于k近邻算法的含义等可以直接去书上找,也可以直接百度
k-近邻算法采用测量不同特征值之间的距离方法进行分类
优点:精度高、对异常值不敏感、无数据输入假定。
缺点:计算复杂度高、空间复杂度高。
适用数据范围:数值型和标称型。
算法使用流程
(1) 收集数据:可以使用任何方法。
(2) 准备数据:距离计算所需要的数值,最好是结构化的数据格式。
(3) 分析数据:可以使用任何方法。
(4) 训练算法:此步骤不适用于k-近邻算法。
(5) 测试算法:计算错误率。
(6) 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输
入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
首先创建一个KNN.py文件,代码是k-近邻算法的实现代码,全部是用命令的方式启动的,可以直接在pycharm的终端中运行项目,也可以用cmd运行项目
编写基本通用函数
命令行中语句:
①
# 第一个是科学计算包NumPy;第二个是运算符模块
from numpy import *
import operator
def createDataSet():
group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels
在terminal中运行,下同
import KNN
group, labels = KNN.createDataSet()
group
labels
def classify0(inX, dataSet, labels, k):
# 距离计算
dataSetSize = dataSet.shape[0]
diffMat = 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]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
# 排序
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
KNN.classify0([0,0], group, labels, 3)
# 将文本记录转换为NumPy的解析程序
def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
# 打开文件,得到文件行数
numberOfLines = len(arrayOLines)
# 创建返回的Numpy矩阵,矩阵以0进行填充
returnMat = zeros((numberOfLines, 3))
classLabelVector = []
index = 0
# 解析文件数据到列表
for line in arrayOLines:
# 首先使用函数line.strip()截取掉所有的回车字符,
line = line.strip()
# 使用tab字符\t将上一步得到的整行数据分割成一个元素列表
listFormLine = line.split('\t')
# 我们选取前3个元素,将它们存储到特征矩阵中
returnMat[index, :] = listFormLine[0: 3]
# 将列表中元素存储为整型,否则会按照字符串进行处理
# 注意这里不是单纯的把字符串改为整型数据,而是改成表,网上找的别人的解释
labels = {'didntLike': 1, 'smallDoses': 2, 'largeDoses': 3} # 新增
classLabelVector.append(labels[listFormLine[-1]]) # 去掉了int
# classLabelVector.append(int(listFormLine[-1]))
index += 1
return returnMat, classLabelVector
import importlib
importlib.reload(KNN)
这里需要将数据导入项目中,因为要从datingTestSet.txt读取数据
完全按照书中的方式会出现错误,网上有人给出了方法
datingDataMat, datingLabels = KNN.file2matrix(‘datingTestSet.txt’)
datingDataMat
datingLabels[0: 20]
②分析数据:使用 Matplotlib 创建散点图
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
#Matplotlib库提供的scatter函数支持个性化标记散点图上的点
ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
plt.show()
from numpy import *
ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0array(datingLabels),15.0array(datingLabels))
更改scatter中的参数时,会出现array错误,此时将所需要的包导入进来即可
③
# 归一化特征值
def autoNorm(dataSet):
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
importlib.reload(KNN)
normMat, ranges, minVals = KNN.autoNorm(datingDataMat)
normMat
ranges
minVals
④
# 分类器针对约会网站的测试代码
def datingClassTest():
hoRatio = 0.10
# 从文件中读取数据并将其转换为归一化特征值
datingDataMat, datingLabels = file2matrix('datingTestSet.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: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
if classifierResult != datingLabels[i]:
errorCount += 1.0
# 计算错误率并输出结果
print("the total error rate is %f" % (errorCount / float(numTestVecs)))
importlib.reload(KNN)
KNN.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 = file2matrix2('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])
importlib.reload(KNN)
KNN.classifyPerson()
手写识别系统
①
# 将数据处理成分类器可以识别的格式
def img2vector(filename):
returnVect = zeros((1, 1024))
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
importlib.reload(KNN)
testVector = KNN.img2vector(‘testDigits/0_13.txt’)
testVector[0, 0:31]
testVector[0, 32:63]
②
# 函数handwritingClassTest()是测试分类器的代码
def handwritingClassTest():
hwLabels = []
# 将trainingDigits目录中的文件内容存储在列表中
trainingFileList = listdir('trainingDigits')
# 可以得到目录中有多少文件,并将其存储在变量m中
m = len(trainingFileList)
# 代码创建一个m行1024列的训练矩阵,该矩阵的每行数据存储一个图像
trainingMat = zeros((m, 1024))
# 从文件名解析分类数字
for i in range(m):
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
# 使用img2vector函数载入图像
trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)
testFileList = listdir('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('testDigits/%s' % fileNameStr)
# 使用classify0()函数测试该目录下的每个文件
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print("the classifer came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
if classifierResult != classNumStr:
errorCount += 1.0
print("\nthe total number of errors is: %d" % errorCount)
print("\nthe total error rate is: %f" % (errorCount / float(mTest)))
importlib.reload(KNN)
KNN.handwritingClassTest()
代码是跟着书上的敲的,书上使用的是python2,目前大家使用的是python3,我全部使用python3跑通了,有的直接指出来了,有的在代码里直接改了
看书,看书,看书。和同组的其他人相比,好菜啊,加油吧