第一篇文章,在机器学习的道路上,希望能够与大家共勉。
K-近邻(Knn,K-Nerest-Neighbor)算法是所接触到的第一个机器学习算法,也是所有机器学习介绍的第一种分类算法。
KNN算法的工作原理:
存在一个样本数据集合,也称作训练样本集,并且样本集中的每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据所对应的每个特征进行比较,然后算法提取样本集中与新数据特征最相似(最近邻)数据的分类标签。一般来说,我们只选择样本数据集中前 k 个最相似的数据,这就是k-近邻算法中 k 的出处,通常 k 是不大于20的整数。最后,选择 k 个最相似数据中出现次数最多的分类,作为新数据的分类。
案例概述:
有如下一组数据(展示前三组数据,原始数据有1000行):
第一行的特征分别为“每年获得的飞行常客里程数”,“玩游戏所耗时间百分比”,“每周消费的冰激淋公升数”以及“喜欢程度”。这个数据样本集表现了择偶方对于对方的喜欢程度是由前三个特征数据综合决定的,因此,我们需要根据这些已有数据建立模型,实现“输入对方的三个特征值,输出喜爱程度”,在Liking_degree中,1为最喜欢,3为不喜欢,2程度居中。
Flight_mileage Percentage_time Ice_cream_liter Liking_degree
40920 8.326976 0.953952 3
14488 7.153469 1.673904 2
26052 1.441871 0.805124 1
下面,我们开始对上面的数据进行预处理,去掉首行字符。
1、读取文件,解析数据。
def filematrix(filename):
fr = open(filename)#打开文件
arrayOfLines = fr.readlines() #读取文件内容至列表中
numberOfLines = len(arrayOfLines) #读数据行数
returnMat = np.zeros((numberOfLines,3)) #创建0矩阵,用于存放文件数据
classLabelVector = [] #创建数组,用与存放标签labels
index = 0 #控制变量,每一个for循环读取一行数据
for line in arrayOfLines: #逐行读取数据
line = line.strip() #删除空格
listFromLine = line.split("\t") #在删除空格的位置加入一个空格
#此举目的是因为源数据文件可能不规范,空行、空格影响文件的读取
returnMat[index,:] = listFromLine[0:3] #读取index行,前三列的数据
classLabelVector.append(int(listFromLine[-1])) #读取最后一列的标签列
index += 1
return returnMat,classLabelVector #返回数据数组和标签数组
fr.readlines()函数所读取文件,方式为逐行逐字符读取
2、现在已经从文本文件中导入了数据,并将其格式化为我们所需要的格式,接下来,我们需要了解这些数据的真实含义。直接浏览文本文件的方式可不太友好,我们下面采用图形化的方式直观地展示数据。
首先,我们使用Matplotlib制作原始数据的散点图
datingDataMat,datingLabels = filematrix('datingTestSet.txt')
#导入数据
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*np.array(datingLabels),15.0*np.array(datingLabels))
#取第二列和第三列数据进行对比,分别表示特征值
# "玩游戏所耗时间百分比”和“每周所消耗冰激淋公升数”
plt.show()
如图所示,两个特征
根据这两个特征值,无法从散点图中分析出有效的信息,因此,我们更换特征值进行尝试。
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],\
15*np.array(datingLabels),15*np.array(datingLabels))
x = ax.set_xlabel("Flight_mileage",)
y = ax.set_ylabel("Percentage_time")
#取第二列和第三列数据进行对比,分别表示特征值
# "玩游戏所耗时间百分比”和“每周所消耗冰激淋公升数”
plt.show()
取第二列和第三列数据进行对比,分别表示特征值,"玩游戏所耗时间百分比”和“每周所消耗冰激淋公升数”
3、归一化数据, a = (Xn-Xmin)/(Xmax-Xmin)∈(0,1)
消除大量级数据对分类结果的影响。
def autoNorm(dataSet):
minValue = dataSet.min(0) #每一列的最小值
maxValue = dataSet.max(0) #每一列的最大值
range = maxValue - minValue
normMat = np.zeros(np.shape(dataSet)) #shape(dataSet)返回dataSet矩阵行列数
m = dataSet.shape[0] #返回行数
up = dataSet - np.tile(minValue,(m,1)) #归一化公式的分子,Xn-Xmin
down = np.tile(range,(m,1)) #归一化公式的分母,Xmax-Xmin
normMat = up/down # a = (Xn-Xmin)/(Xmax-Xmin)
return normMat,minValue,maxValue
归一化后的数据:
原数据:
4、KNN算法代码
def classify(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = np.tile(inX,(dataSetSize,1)) - dataSet
sqDiffMat = diffMat ** 2
sqDistance = sqDiffMat.sum(axis = 1)
distance = sqDistance ** 0.5
sortAsDistance = distance.argsort()
classCount = {}
for i in range(k):
voteIlabel = labels[sortAsDistance[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) +1
sortDeclassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortDeclassCount[0][0]
5、测试算法,我们提取10%的数据进行测试,剩余90%的数据来作训练样本
def datingTest():
j = 0.1
datingDataMat,datingLabels = filematrix('datingTestSet.txt')
normMat ,minValue,maxValue= autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m*j)
errorCount = 0
for i in range(numTestVecs):
classifyResult = classify(normMat[i,:],normMat[numTestVecs:m,:],\
datingLabels[numTestVecs:m],3)
print("预测值为:%d, 实际值为:%d" % (classifyResult,datingLabels[i]))
if(classifyResult != datingLabels[i]):
errorCount += 1
errors = float(1-errorCount/numTestVecs)
print("正确率:",errors)
print("错误数量:",errorCount)
附分类标签为字符串的代码
import numpy as np
import operator
def loadDataSet(fileName):
fr = open(fileName)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines)
returnMat = np.zeros((numberOfLines,3))
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] =listFromLine[0:3]
classLabelVector.append(listFromLine[-1])
index += 1
return returnMat, classLabelVector
def classify(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
#dataSetSize = np.shape(dataSet)[0]
#dataSetSize = len(dataSet)
diffMat = np.tile(inX,(dataSetSize,1)) - dataSet
sqDiffMat = diffMat **2
sqDistances = sqDiffMat.sum(axis = 1)
distances = sqDistances ** 0.5
sortedDistances = distances.argsort()
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistances[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) +1
sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)
return sortedClassCount[0][0]
def autoNorm(dataSet):
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = np.zeros(np.shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - np.tile(minVals,(m,1))
normDataSet = normDataSet/(np.tile(ranges,(m,1)))
return normDataSet, range, minVals
def datingTest():
j = 0.1
datingDataMat,datingLabels = loadDataSet('datingTestSet.txt')
normMat ,minValue,maxValue= autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m*j)
errorCount = 0
for i in range(numTestVecs):
classifyResult = classify(normMat[i,:],normMat[numTestVecs:m,:],\
datingLabels[numTestVecs:m],3)
print("预测值为:%s, 实际值为:%s" % (classifyResult,datingLabels[i]))
if(classifyResult != datingLabels[i]):
errorCount += 1
errors = float(errorCount/numTestVecs)
print("错误率:",errors)
print("错误数量:",errorCount)
def datingClassTest():
hoRatio = 0.1
dataSet,labelSet = loadDataSet('datingTestSet.txt')
normMat,ranges,minVals = autoNorm(dataSet)
m = normMat.shape[0]
numTestVecs = int(m*hoRatio)
errorCount = 0.0
errorMat = []
for i in range(numTestVecs):
classifierResult = classify(normMat[i,:],normMat[numTestVecs:m,:],labelSet[numTestVecs:m],3)
if classifierResult != labelSet[i]:
errorCount += 1.0
errorMat.append([classifierResult,labelSet[i]])
errorRate = errorCount/float(numTestVecs)
num = len(errorMat)
errorMat = np.mat(errorMat)
for i in range(num):
print("预测:%s,真实:%s" % (errorMat[i,0],errorMat[i,1]))
print("错误率:%.2f%%" % errorRate)
data,label = loadDataSet('datingTestSet.txt')
normMat,minValue,maxValue = autoNorm(data)
datingClassTest()
输出结果:
预测:largeDoses,真实:smallDoses
预测:largeDoses,真实:didntLike
预测:largeDoses,真实:didntLike
预测:smallDoses,真实:largeDoses
预测:largeDoses,真实:didntLike
错误率:0.05%