k 近邻法(K-nearest neighbor)是一种基本的分类方法
基本思路:
给定一个训练数据集,对于新的输入实例,在训练数据集中找到与该实例最邻近的k个实例,这k个实例多数属于某个类别,就把输入实例分为这个类。
算法:
输入:训练数据集 (T={(x_{1},y_{1}),(x_{2},y_{2}),...,(x_{n},y_{n})}) 其中 (x_{i}) 是训练集实例的特征向量(features vectors),(y_{i}) 是训练集实例的类别,(i=1,2,3,cdotcdotcdot,N) (N 代表的是训练集实例的数量)
输出:训练数据集实例的列别(y)
模型:
三个基本要素:距离度量(欧几里得距离),k值的选择,分类决策规则(多数表决 )
- 距离度量:首先特征向量是(n)维,(x_{i})是训练数据集中的特征向量,(x_{j})是输入实例的特征向量。
其中(x_{i}=(x_{i}^{(1)},x_{i}^{(2)},...,x_{i}^{(n)}), x_{j}=(x_{j}^{(1)},x_{j}^{(2)},...,x_{j}^{(n)})).
两者之间的距离定义为:(L_{p}(x_{i},x_{j})=(sum_{t=1}^{n}{|x_{i}^{(t)}-x_{j}^{(t)}|^{p}})^{1/p}).
在这里(pgeq1), 当(p=2)时,我们称之为欧氏距离(Euclidean distance),即(L_{p}(x_{i},x_{j})=(sum_{t=1}^{n}{|x_{i}^{(t)}-x_{j}^{(t)}|^{2}})^{1/2});
当p=1 时,我们称之为曼哈顿距离(Manhattan distance)即(L_{p}(x_{i},x_{j})=sum_{t=1}^{n}{|x_{i}^{(t)}-x_{j}^{(t)}|}). 使用不同的距离度量方法会产生不同的结果。 - k值得选择问题:会采取交叉验证的方法选择合适k值
- 分类决策规则:多数表决
在电影分类中的KNN算法
import numpy as np
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
group,labels=createDataSet()
def classify0(inx, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = np.tile(inx, (dataSetSize,1)) - dataSet # tile
sqDiffMat = diffMat ** 2 #**乘方
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances ** 0.5
sortedDistIndicies = distances.argsort()# argsort
classCount={}#dic
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0)+1 #get
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) # sorted &items()
return sortedClassCount[0][0]
classify0([0,0],group,labels,3)
在这里我们是自己实现了一个KNN的分类器,我们也可以使用sklearn 中的KNeighborsClassifier 去直接分类,参考这里中的实例
对代码中的基础知识进行总结:
shape( ):numpy
>>> C = np.array([[1,1],[1,2],[1,3],[1,4]])
>>> C.shape()
>>> (4,2)
>>> C.shape[0]
>>> 4
>>> C.shape[1]
>>> 2
tile( ): 重复某个数组(numpy)
>>>A=[1,2,3]
>>>np.tile(A,3)
>>>array([1, 2, 3, 1, 2, 3, 1, 2, 3])
>>>np.tile(A,(3,1))
>>>array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
>>>np.tile(A,(3,2))
>>>array([[1, 2, 3, 1, 2, 3],
[1, 2, 3, 1, 2, 3],
[1, 2, 3, 1, 2, 3]])
argsort( )
- 对于一维数组来讲:
>>>x=np.array([3,1,2])
>>>np.argsort(x)
>>>array([1,2,0]) #把索引从小到大列了出来
>>>np.argsort(-x) #按照降序排列
>>>array([0,2,1])
>>>x[np.argsort(x)] #重新排序之后的数组
>>>array([1,2,3])
- 对于二维数组来说
>>> x=np.array([[0,3],[2,2]])
>>>np.argsort(x,axis=0) #按列排序
>>> array([[0, 1],
[1, 0]])
>>>np.argsort(x,axis=1)#按行排序
>>>array([[0, 1],
[0, 1]])
Dictionary get( ):
dict.get(key,default=None) 字典的get()函数返回指定键的值,如果键或者值不存在,返回默认值
sorted( ):
- sort 和 sorted 的区别
sort 是应用在list上的方法,sorted是可以对所有可迭代的对象进行排序操作的函数
sort是作用在列表本身,改变原列表 sorted是生成一个新的可迭代的对象
- sorted用法
sorted(iterable, key=None, reverse=False)
对由tuple组成的list排序:
>>> students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
#使用key函数
>>> sorted(students, key=lambda student : student[2]) # sort by age
>>>[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)] #返回由tuple组成的list
#用 operator 函数来加快速度
>>> sorted(students, key=itemgetter(2))
#用 operator 函数进行多级排序
>>> sorted(students, key=itemgetter(1,2)) # sort by grade then by age
>>>[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
对由字典排序 ,返回由tuple组成的List,不再是字典
>>> d = {'data1':3, 'data2':1, 'data3':2, 'data4':4}
>>> sorted(d.items(), key=itemgetter(1), reverse=True)
>>>[('data4', 4), ('data1', 3), ('data3', 2), ('data2', 1)]
items( )
dict.items():
>>>dict = {'Google': 'www.google.com', 'Runoob': 'www.runoob.com', 'taobao': 'www.taobao.com'}
>>>dict.items()
>>>dict_items([('Google', 'www.google.com'), ('Runoob', 'www.runoob.com'), ('taobao', 'www.taobao.com')]) #返回的是一个列表
在约会网站使用KNN算法
#对TXT文件中的数据进行处理
import numpy as np
def file2matrix(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(' ') #
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1])) #
index +=1
return returnMat,classLabelVector
datingDataMat, datingLabels = file2matrix('datingTestSet.txt')
read( ) & readline( ) & readlines( ):
>>>f=open('test_read()&readlines().txt')
>>>f.read()
>>>'Monday
Tuesday
Wednesday
Thursday
Friday
Saturaday
Sunday' #一次性读取文本中全部的内容,以字符串的形式返回结果
>>>f.readline()
>>>'Monday
' #只读取文本第一行的内容,以字符串的形式返回结果
>>> f.readlines()
>>>['Tuesday
', 'Wednesday
', 'Thursday
', 'Friday
', 'Saturday
', 'Sunday
'] #读取文本所有内容,并且以数列的格式返回结果,一般配合for in使用
strip( ):
strip() 用于移除字符串头尾指定的字符,默认为空格
>>>str = "0000000 Runoob 0000000";
>>>print str.strip( '0' ); # 去除首尾字符 0
>>>str2 = " Runoob "; # 去除首尾空格
>>>print str2.strip();
>>> Runoob
>>>Runoob
split( ):
>>>str = "Line1-abcdef
Line2-abc
Line4-abcd";
>>>print (str.split( ));
>>>print (str.split(' ', 1 ));
>>>['Line1-abcdef', 'Line2-abc', 'Line4-abcd']
>>>['Line1-abcdef', '
Line2-abc
Line4-abcd']
归一化特征值
在K-means的方法中,我们采取的是欧几里得距离。我们观察特征值的大小发现不同特征值在数值上差别很大,这就导致某一个特征值发生一点变化之后,导致欧几里得距离发生很大的变化,所以为了避免这种情况的出现我们决定归一化数据。
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, ranges, minVals
normMat,ranges,minVals = autoNorm(datingDataMat)
normMat
min( ):numpy
>>>a=np.array([[1,5,3],[4,2,6]])
>>>print(a.min()) #无参数,所有值中的最小值
>>>1
>>>print(a.min(0))#axis=0,每列中的最小值
>>>[1 2 4]
>>>print(a.min(1))#axis=1,每行中的最小值
>>>[1 2]
测试代码
def datingClassTest():
hoRatio = 0.1
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
print('the total error rate is : %f ' % (errorCount/float(numTestVecs)))
datingClassTest()
构建完整的可用系统
def classifyperson():
resultList = ['not at all','in small doses','in large doses']
percenTats = 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 = np.array([ffMiles,percenTats,iceCream])
classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
print('you will probbably like this person: ',resultList[classifierResult -1])
classifyperson()