实验内容 1 K-近邻算法概述
实验程序代码(含详细注释):
实验结果(展示实验细节):
1、使用Python导入数据;
# 导入数据函数
def createDataSet():
group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) # 数组中,前两个是接近1的数据集,后两个是接近0的数据集
labels = ['A','A','B','B'] # 标签表示接近1的是A类,接近0的是B类
return group, labels # 将数据集和分类标签返回
2、实施kNN分类算法;
# K邻近法则算法
def classify0(inX, dataSet, labels, k): #inX为输入向量,dataSet为训练数据集,labels为标签,k为最近邻居的数目
dataSetSize = dataSet.shape[0] #读取dataset矩阵第一维度的长度 即矩阵第一行的数据个数
diffMat = tile(inX, (dataSetSize,1)) - dataSet #tile(inX, (dataSetSize,1))表示向下复制dataSetSize次数的inX,这里计算输入向量与训练集中每个点的差
sqDiffMat = diffMat**2 #这个差值取平方
sqDistances = sqDiffMat.sum(axis=1) # 横向相加所有差值平方得出欧式距离的平方
distances = sqDistances**0.5 #取开放得出欧式距离
sortedDistIndicies = distances.argsort() #将distance从小到大排序,取出排序后该数据在distance中的索引值形成新的数组
classCount={}
for i in range(k): #循环k次
voteIlabel = labels[sortedDistIndicies[i]] #将改索引值在labels中对应的标签取出
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #该标签:出现次数 放入classCount字典中
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) #根据出现次数排序
return sortedClassCount[0][0] #返回频率最高的“键”,即标签
3、如何测试分类器?简述其基本思想。
书上说的是错误率是常用的评估方法,主要用于评估分类器在某个数据集上的执行效果,完美分类器的错误率为0,最差的分类器错误率为1。
经过各方面查资料,评估分类器的方法除了错误率,还有,准确率、召回率、由准确率和召回率曲线构成的面积AUC的值。准确率是:在分类器中,预测为正类的所有值中,真正为正类的值与预测为正类的比值。召回率是:在分类器中预测为正类与所有数据中为正类的比值。AUC:假正例率与真正例率形成的图,若学习器A曲线能完全包住学习器B,那么学习器A就比B更加好。
实验内容 2 使用k-近邻算法改进约会网站的配对效果
1、 从文本文件中解析数据;
实验程序(含详细注释):
# 读取datingTestSet.txt中的数据
# 数据为约会网站的数据,每列分别是每年获得的飞行常客里程数,玩视频游戏所消耗时间百分比,每周雄安飞的冰淇淋公升数
# 并返回给numpy矩阵
def file2matrix(filename):
fr = open(filename) #打开文件
numberOfLines = len(fr.readlines()) #读取文件行数
returnMat = zeros((numberOfLines,3)) #构造文件行数,3列的矩阵,矩阵所有元素都是0
classLabelVector = [] #每行数据存储标签用的列表
fr = open(filename)
index = 0 #index作为returnMat矩阵的索引值
for line in fr.readlines(): # 按照行读取文件内容
line = line.strip() # 去掉所有的回车
listFromLine = line.split('\t') # 将\t作为切割标志,将每行数据切分成列表
returnMat[index,:] = listFromLine[0:3] #将每行数据构成的列表中的元素,给矩阵returnMat
classLabelVector.append(float(listFromLine[-1])) #将最后一列喜欢程度值,给classLabelVector列表
index += 1 #给矩阵下一行添加数据
return returnMat,classLabelVector #将 returnMat 矩阵和、classLabelVector喜欢程度 返回
实验结果(展示实验细节)
2、使用Matplotlib创建散点图;
实验程序(含详细注释):
from numpy import *
import kNN
import matplotlib.pyplot as plt
fig = plt.figure() # 创建一个640*480的窗体
ax = fig.add_subplot(111) # 创建子图,将画布分为一行一列,ax在从左往右从上往下数第一个子图
datingDataMat,datingLabels = kNN.file2matrix('datingTestSet2.txt') #调用kNN模块中的file2matrix函数读取数据
#ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), array(datingLabels))
#x轴为完视频游戏所消耗时间百分比,y轴每周所消费的冰淇淋的公升数,
# 第三个参数形参为s,表示点的权重大小,第四个参数形参为c,如果传入的向量,那么会根据向量中的标签将不同类别的颜色分开
# 其中大的黄色的点表示特别喜欢,绿色中等大小的点表示一般喜欢,紫色很小的点表示不喜欢
ax.axis([-2,25,-0.2,2.0])
plt.xlabel('Percentage of Time Spent Playing Video Games') #x轴坐标名称 玩游戏时间
plt.ylabel('Liters of Ice Cream Consumed Per Week') #y轴坐标名称 多少公升冰淇淋
plt.show() #显示图像
实验结果(展示实验细节):
对于ax.scatter这个函数更改参数发现图不一样,其中发现形参s表示点的大小,形参c传入的是向量的话,会根据不同列表标记不同的颜色,下图是,s和c都没有传入参数、传入s参数、传入s和c参数的不同效果的图,最后一个图几乎将不同类别的人已经区分的比较明显了,轮廓也非常明显。
最后散点图
样本数据集的分布情况(每年飞的里程数与身上纹身面积的规律)
实验程序(含详细注释):
from numpy import *
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
n = 1000 #number of points to create
xcord1 = []; ycord1 = [] #不喜欢类 xcord1飞行里数 ycord1电玩玩的时间
xcord2 = []; ycord2 = [] #一般喜欢类
xcord3 = []; ycord3 = [] #非常喜欢类
markers =[]
colors =[]
fw = open('testSet.txt','w') #用写入的方式打开testSet.txt文件
for i in range(n): #循环一千次
[r0,r1] = random.standard_normal(2) # 创建一行二列的随机数列表
myClass = random.uniform(0,1) # 创建一个0-1之间的均匀分布浮点随机数
if (myClass <= 0.16): #如果这个myClass随机数小于0.16
fFlyer = random.uniform(22000, 60000) #创建一个22000,60000之间的均匀分布浮点随机数给fFlyer
tats = 3 + 1.6*r1
markers.append(20) #把myClass <= 0.16的markers标记成20
colors.append(2.1) #这个类的颜色数值为2.1
classLabel = 1 #'didntLike'
xcord1.append(fFlyer); ycord1.append(tats)
elif ((myClass > 0.16) and (myClass <= 0.33)): #如果这个myClass随机数在0.16-0.33之间
fFlyer = 6000*r0 + 70000
tats = 10 + 3*r1 + 2*r0
markers.append(20) #把myClass 在0.16-0.33之间的markers标记成20
colors.append(1.1) #这个类的颜色数值为1.1
classLabel = 1 #'didntLike'
if (tats < 0): tats =0
if (fFlyer < 0): fFlyer =0
xcord1.append(fFlyer); ycord1.append(tats)
elif ((myClass > 0.33) and (myClass <= 0.66)): #如果这个myClass随机数在0.33-0.66之间
fFlyer = 5000*r0 + 10000
tats = 3 + 2.8*r1
markers.append(30) #把myClass 在0.33-0.66之间的markers标记成30
colors.append(1.1) #这个类的颜色数值为1.1
classLabel = 2 #'smallDoses'
if (tats < 0): tats =0
if (fFlyer < 0): fFlyer =0
xcord2.append(fFlyer); ycord2.append(tats)
else: #如果这个myClass随机数大于0.66
fFlyer = 10000*r0 + 35000
tats = 10 + 2.0*r1
markers.append(50) #把myClass 大于0.66的markers标记成50
colors.append(0.1) #这个类的颜色数值为0.1
classLabel = 3 #'largeDoses'
if (tats < 0): tats =0
if (fFlyer < 0): fFlyer =0
xcord3.append(fFlyer); ycord3.append(tats)
fw.close()
fig = plt.figure()
ax = fig.add_subplot(111)
#ax.scatter(xcord,ycord, c=colors, s=markers)
type1 = ax.scatter(xcord1, ycord1, s=20, c='red') # x坐标为xcord1,y坐标ycord1,点大小为20,颜色为红色
type2 = ax.scatter(xcord2, ycord2, s=30, c='green') # x坐标为xcord2,y坐标ycord2,点大小为30,颜色为绿色
type3 = ax.scatter(xcord3, ycord3, s=50, c='blue') # x坐标为xcord3,y坐标ycord3,点大小为50,颜色为蓝色
ax.legend([type1, type2, type3], ["Did Not Like", "Liked in Small Doses", "Liked in Large Doses"], loc=2) #图像小标题
ax.axis([-5000,100000,-2,25])
plt.xlabel('Frequent Flyier Miles Earned Per Year') #横坐标名称
plt.ylabel('Percentage of Time Spent Playing Video Games') #纵坐标名称
plt.show()
实验结果(展示实验细节):
样本数据集的分布情况(每年飞的里程数与华仔电玩游戏的时间之间的规律)
# coding=utf-8
'''
Created on Oct 6, 2010
@author: Peter
'''
from numpy import *
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
n = 1000 #number of points to create
xcord = zeros((n)) #创建一个1*1000的矩阵,矩阵中数值都是0
ycord = zeros((n)) #创建一个1*1000的矩阵,矩阵中数值都是0
markers =[] # 用于散点图点大小的列表
colors =[] #散点图的颜色
fw = open('testSet.txt','w') #用写入的方式打开testSet.txt文件
for i in range(n): #循环一千次
[r0,r1] = random.standard_normal(2) # 取两个随机数
myClass = random.uniform(0,1) #取0-1之间的随机数
if (myClass <= 0.16):
fFlyer = random.uniform(22000, 60000) #取22000-60000随机数
tats = 3 + 1.6*r1
markers.append(20) # 小于0.16的点大小为20
colors.append(2.1) # 小于0.16的点颜色值为2.1
classLabel = 1 #'didntLike'
# print ("%d, %f, class1") % (fFlyer, tats)
print(fFlyer, tats, "class1")
elif ((myClass > 0.16) and (myClass <= 0.33)):
fFlyer = 6000*r0 + 70000
tats = 10 + 3*r1 + 2*r0
markers.append(20) # 大于0.16小于0.33点大小为20
colors.append(1.1) # 大于0.16小于0.33点颜色值为1.1
classLabel = 1 #'didntLike'
print(fFlyer, tats, "class1")
elif ((myClass > 0.33) and (myClass <= 0.66)):
fFlyer = 5000*r0 + 10000
tats = 3 + 2.8*r1
markers.append(30) # 大于0.33小于0.66的点大小为30
colors.append(1.1) # 大于0.33小于0.66的点颜色值为1.1
print(fFlyer,tats,"class2")
else:
fFlyer = 10000*r0 + 35000
tats = 10 + 2.0*r1
markers.append(50) # 大于0.66的点大小为50
colors.append(0.1) # 大于0.66的点颜色值为0.1
classLabel = 3 #'largeDoses'
print(fFlyer, tats, "class3")
if (tats < 0): tats =0
if (fFlyer < 0): fFlyer =0
xcord[i] = fFlyer; ycord[i]=tats
fw.write("%d\t%f\t%f\t%d\n" % (fFlyer, tats, random.uniform(0.0, 1.7), classLabel))
fw.close()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xcord,ycord, c=colors, s=markers)
type1 = ax.scatter([-10], [-10], s=20, c='red')
type2 = ax.scatter([-10], [-15], s=30, c='green')
type3 = ax.scatter([-10], [-20], s=50, c='blue')
ax.legend([type1, type2, type3], ["Class 1", "Class 2", "Class 3"], loc=2)
#ax.axis([-5000,100000,-2,25])
plt.xlabel('Frequent Flyier Miles Earned Per Year')
plt.ylabel('Percentage of Body Covered By Tatoos')
plt.show()
测试算法
def autoNorm(dataSet):
minVals = dataSet.min(0) #取数据集最小值
maxVals = dataSet.max(0) #取数据集最大值
ranges = maxVals - minVals #取最大值和最小值的差值
normDataSet = zeros(shape(dataSet)) #建立一个都是0的行列数与数据集一样的矩阵
m = dataSet.shape[0] #读取数据集的行数
normDataSet = dataSet - tile(minVals, (m,1)) # 数据集减去最小值矩阵
normDataSet = normDataSet/tile(ranges, (m,1)) # 归一化处理
return normDataSet, ranges, minVals
# 数据测试
def datingClassTest():
hoRatio = 0.50
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #读取datingTestSet2.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)
#执行classify0分类器,将分类结果给classifierResult
print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
# 如果分类器的结果和标签不一样,就errorCount+1
if (classifierResult != datingLabels[i]): errorCount += 1.0
print("the total error rate is: %f" % (errorCount/float(numTestVecs)))
print(errorCount)#打印出错误率
使用算法构建完整系统
实验内容 3 手写识别系统
实验程序(含详细注释):
def img2vector(filename):
returnVect = zeros((1,1024)) #创建一个1*1024的一维向量
fr = open(filename) #打开文件
for i in range(32): #嵌套循环,将图像按照行读出,一共32行
lineStr = fr.readline()
for j in range(32): # 将图像每行的数据一个个读出,每行一共32个数据
returnVect[0,32*i+j] = int(lineStr[j]) #将每行的每个数据依次存到一维向量中
return returnVect # 返回处理好的向量,这个时候就把图像装欢为一维向量了
实验结果(展示实验细节):
def handwritingClassTest():
hwLabels = [] # 构建空的测试集的标签列表
trainingFileList = listdir('trainingDigits') #读取文件夹trainingDigits列表
m = len(trainingFileList) #返回文件夹个数
trainingMat = zeros((m,1024)) #构建元素都是0的,训练数据个数*1024大小的矩阵,每行存一个图像
for i in range(m):
fileNameStr = trainingFileList[i] #获取文件的名字
fileStr = fileNameStr.split('.')[0] #获取文件名,把后缀名去掉
classNumStr = int(fileStr.split('_')[0]) #从文件名中获取类名
hwLabels.append(classNumStr) # 将获得的类别标签添加到hwLabels列表中
trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr) #将每个文件的1*1024数据存储到这个文件trainingDigits/fileNameStr中
testFileList = listdir('testDigits') #iterate through the test set
errorCount = 0.0
mTest = len(testFileList) #测试数据的个数
#将文件名中的类名取出,并进行分类测试
for i in range(mTest):
fileNameStr = testFileList[i] #获取文件的名字
fileStr = fileNameStr.split('.')[0] #take off .txt
classNumStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)#获得测试集的向量
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3) # 获得预测结果
print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
if (classifierResult != classNumStr): errorCount += 1.0 #如果预测结果和真实结果不符合,错误数+1
print("\nthe total number of errors is: %d" % errorCount)
print("\nthe total error rate is: %f" % (errorCount/float(mTest)))