目录
概述
优点:精度高,对异常值不敏感,无数据输入假定
缺点:计算,空间,复杂度较高
适用于:数值型(连续型),标称型
简单来说:就是采用测量不同特征值之间的距离方法进行分类
一个简单的分类器
大致的作用:自己构建了四个点,为它们附上标签,让程序以这些为指标,判断不同的点应该对应A还是B
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):#(要判断的数据,原数据,原数据类型,前k个)
dataSetSize = dataSet.shape[0] #矩阵第一维的长度
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet #根据训练数据大小生成
sqDiffMat = diffMat**2 #二维特征相减后平方
sqDistances = sqDiffMat.sum(axis=1) ########沿着列(但不是很懂为啥)
distances = sqDistances**0.5 #累加开方
sortedDistIndicies = distances.argsort()#返回distances中元素从小到大排序后的索引值
classCount = {} #开一个记录类别次数的字典
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]
a=classify0([0,0],group,labels,3)
print(a)
示例:使用k-近邻算法改进约会网站的配对效果
(1)收集数据
此处有给定的一些数据,存放在同一个文件夹下ceshi1.txt文件中
(2)准备数据:用python解析,归一化数值
import numpy as np
import operator
def file2matrix(filename):
love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1}#字典定义三的类别
fr = open(filename)#打开文件
arrayOLines = fr.readlines() #逐行处理,readlines()方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for... in ... 结构进行处理。
numberOfLines = len(arrayOLines) #算行数
returnMat = np.zeros((numberOfLines, 3)) #初始化numpy型, numberOfLines*3大小的特征矩阵
classLabelVector = [] #初始化标签
index = 0 #行索引
for line in arrayOLines:
line = line.strip() #删空格
listFromLine = line.split('\t') #用空格分割 成列表
#没懂为啥是三个
returnMat[index, :] = listFromLine[0:3]
#如果是数字
if(listFromLine[-1].isdigit()):
#直接赋值到标签
classLabelVector.append(int(listFromLine[-1]))
else:
#如果是字符串,用love_dictionary转换
classLabelVector.append(love_dictionary.get(listFromLine[-1]))
index += 1 #索引的移动
return returnMat, classLabelVector
def autoNorm(dataSet):
#最大最小
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
#创建全0的初始矩阵
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
returnMat,classLabelVector=file2matrix('ceshi1.txt')
normDataSet,ranges,minVals=autoNorm(returnMat)
print(normDataSet)
print(ranges)
print(minVals)
(3)分析数据:使用Matplotlib创建散点图
import numpy as np
import operator
import matplotlib
import matplotlib.pyplot as plt
def file2matrix(filename):
love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1}
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]
if(listFromLine[-1].isdigit()):
classLabelVector.append(int(listFromLine[-1]))
else:
classLabelVector.append(love_dictionary.get(listFromLine[-1]))
index += 1
return returnMat, classLabelVector
a,b=file2matrix('ceshi1.txt')
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(a[:,1],a[:,2],15.0*np.array(b),15.0*np.array(b))
# 保证图片中输出的文字为中文
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 输出横纵坐标上的文字
plt.xlabel("玩游戏所耗时间百分比")
plt.ylabel("每周消耗的冰淇淋公升数")
plt.show()
(4)训练算法(此步骤不适合k-近邻算法)
(5)测试算法
import numpy as np
import operator
import matplotlib
import matplotlib.pyplot as plt
#读取数据
def file2matrix(filename):
love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1}#字典定义三的类别
fr = open(filename)#打开文件
arrayOLines = fr.readlines() #逐行处理,readlines()方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for... in ... 结构进行处理。
numberOfLines = len(arrayOLines) #算行数
returnMat = np.zeros((numberOfLines, 3)) #初始化numpy型, numberOfLines*3大小的特征矩阵
classLabelVector = [] #初始化标签
index = 0 #行索引
for line in arrayOLines:
line = line.strip() #删空格
listFromLine = line.split('\t') #用空格分割 成列表
#没懂为啥是三个
returnMat[index, :] = listFromLine[0:3]
#如果是数字
if(listFromLine[-1].isdigit()):
#直接赋值到标签
classLabelVector.append(int(listFromLine[-1]))
else:
#如果是字符串,用love_dictionary转换
classLabelVector.append(love_dictionary.get(listFromLine[-1]))
index += 1 #索引的移动
return returnMat, classLabelVector
#归一化处理
def autoNorm(dataSet):
#最大最小
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
#创建全0的初始矩阵
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
def classify0(inX, dataSet, labels, k):#(要判断的数据,原数据,原数据类型,前k个)
dataSetSize = dataSet.shape[0] #矩阵第一维的长度
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet #根据训练数据大小生成
sqDiffMat = diffMat**2 #二维特征相减后平方
sqDistances = sqDiffMat.sum(axis=1) ########沿着列(但不是很懂为啥)
distances = sqDistances**0.5 #累加开方
sortedDistIndicies = distances.argsort()#返回distances中元素从小到大排序后的索引值
classCount = {} #开一个记录类别次数的字典
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]
def datingClassTest():
#整个数据10%来测试
hoRatio = 0.1
datingDataMat, datingLabels = file2matrix('ceshi1.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)))
print(errorCount)
datingClassTest()
(6)使用算法
import numpy as np
import operator
import matplotlib
import matplotlib.pyplot as plt
#读取数据
def file2matrix(filename):
love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1}#字典定义三的类别
fr = open(filename)#打开文件
arrayOLines = fr.readlines() #逐行处理,readlines()方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for... in ... 结构进行处理。
numberOfLines = len(arrayOLines) #算行数
returnMat = np.zeros((numberOfLines, 3)) #初始化numpy型, numberOfLines*3大小的特征矩阵
classLabelVector = [] #初始化标签
index = 0 #行索引
for line in arrayOLines:
line = line.strip() #删空格
listFromLine = line.split('\t') #用空格分割 成列表
#没懂为啥是三个
returnMat[index, :] = listFromLine[0:3]
#如果是数字
if(listFromLine[-1].isdigit()):
#直接赋值到标签
classLabelVector.append(int(listFromLine[-1]))
else:
#如果是字符串,用love_dictionary转换
classLabelVector.append(love_dictionary.get(listFromLine[-1]))
index += 1 #索引的移动
return returnMat, classLabelVector
#归一化处理
def autoNorm(dataSet):
#最大最小
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
#创建全0的初始矩阵
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
def classify0(inX, dataSet, labels, k):#(要判断的数据,原数据,原数据类型,前k个)
dataSetSize = dataSet.shape[0] #矩阵第一维的长度
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet #根据训练数据大小生成
sqDiffMat = diffMat**2 #二维特征相减后平方
sqDistances = sqDiffMat.sum(axis=1) ########沿着列(但不是很懂为啥)
distances = sqDistances**0.5 #累加开方
sortedDistIndicies = distances.argsort()#返回distances中元素从小到大排序后的索引值
classCount = {} #开一个记录类别次数的字典
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]
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 = file2matrix('ceshi1.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
inArr = np.array([ffMiles, percentTats, iceCream, ])
classifierResult = classify0((inArr - \
minVals)/ranges, normMat, datingLabels, 3)
print("You will probably like this person: %s" % resultList[classifierResult - 1])
classifyPerson()
使用k-邻近算法识别手写数字
未完待续