KNN通过测量不同特征值之间的距离进行分类。大致思路:一个样本在k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别。那么该样本也属于这个类别。
参考书籍:《python经典学习实例》、《机器学习实战》
源码地址:https://github.com/Metatronxl/MachineLearning/tree/master/kNN
用图来举例子
算法实现
1.数据预处理
主要是将提供的数据集处理成函数可以处理的数据
def file2matrix(filename):
fr = open(filename)
arrayOfLines = fr.readlines()
numberOfLines = len(arrayOfLines)
returnMat = zeros((numberOfLines,3))
classLabelVector = []
index = 0
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
2.数据归一化
当多个维度的数据我们认为是同等重要的时候,通常采用的方法是将数值归一化,这样可以避免数字差值对计算结果造成的影响。
2.1归一化公式
newValue = (oldValue-min)/(max-min)
2.2 归一化(正则化)代码实现
## Normalization
def autoNorm(dataSet):
minVals = dataSet.min(0) ## 0 means 数组的第二维(纵列)
maxVals = dataSet.max(0)
ranges = maxVals-minVals
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0] #shape[1]为第二维的长度(横列),shape[0]为第一维的长度(纵列)
## newValue = (oldvalue-min)/(max-min)
normDataSet = dataSet - tile(minVals,(m,1))
normDataSet = normDataSet/tile(ranges,(m,1))
return normDataSet,ranges,minVals
需要注意的是,sklearn提供了函数,也可以直接调用sklearn的api
- L1正则化是指权值向量w中各个元素的绝对值之和,通常表示为||w||1
- L2正则化是指权值向量w中各个元素的平方和然后再求平方根(可以看到Ridge回归的L2正则化项有平方符号),通常表示为||w||2
from sklearn import preprocessing
returnMat,classLabel = file2Metrix("datingTestSet2.txt")
hoRatio = 0.10
num_neighbors = 3
normMat = preprocessing.normalize(returnMat,'l2')
3. KNN算法
算法的原理很简单就不赘述了,直接上代码吧
classify0()有四个输入参数:用于分类的输入向量inX,输入的训练样本集为dataSet,标签向量labels,最后的参数k表示选择最近邻居的数目
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize,1)) - dataSet
sqDiffMat = diffMat**2
# axis代表的是第几维的数组 0为1维,1为2维
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
# argsort()函数是将x中的元素从小到大排列,提取其对应的index(索引),然后输出到y
sortedDistIndicies = distances.argsort()
classCount={}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
采用sklearn的api实现kNN算法
from sklearn import neighbors
def testKNN():
returnMat,classLabel = file2Metrix("datingTestSet2.txt")
hoRatio = 0.10 ## 测试集的数量
num_neighbors = 3 ##选择k的数量
normMat = preprocessing.normalize(returnMat,'l2')
m = normMat.shape[0]
numTestVecs = int(m*hoRatio)
classifier = neighbors.KNeighborsClassifier(num_neighbors,weights='distance')
classifier.fit(returnMat[numTestVecs:,],classLabel[numTestVecs:])
### predict 来得到预测的结果
error_count = 0
for item,result in zip(returnMat[:numTestVecs],classLabel[:numTestVecs]):
#告诉模型这是一个example,而不是多个
test_value = item.reshape(1,-1)
predict_result = classifier.predict(test_value)[0]
print "predicted output:",classifier.predict(test_value)[0]
if predict_result != result:
error_count +=1
print "error_rate is %f" % (error_count/float(m*0.9))