文章目录
实验
一、示例:KNN改进约会网站配对
海伦女士一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的人选,但她没有从中找到喜欢的人。经过一番总结,她发现曾交往过三种类型的人:
不喜欢的人
魅力一般的人
极具魅力的人
尽管发现了上述规律,但海伦依然无法将约会网站推荐的匹配对象归入恰当的分类。她觉得可以在周一到周五约会那些魅力一般的人,而周末则更喜欢与那些极具魅力的人为伴,海伦希望我们的分类软件可以更好地帮助她将匹配对象划分到确切的分类中。此外海伦还收集了一些约会网站未曾记录的数据信息,她认为这些数据更有助于匹配对象的归类。
海伦收集约会数据有了一段时间,她把这些数据存放在文本文件datingTestSet.txt中,每个样本数据占据一行,总共有1000行。海伦的样本主要包含以下3种特征:
每年获得的飞行常客里程数
玩视频游戏所耗时间百分比
每周消费的冰淇淋公升数
(datingTestSet.txt这个文本自己上网找哈,挺多的)
二、实验过程
1.准备数据:从文本文件中解析数据
import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator
def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines) #得到文本行数
returnMat = np.zeros((numberOfLines,3)) #创建返回的NumPy二维矩阵
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
# line.split()截取掉所有回车字符 用tab字符\t将上一步得到的整行数据分割成一个元素列表
listFromLine = line.split('\t')
# 选取前面三个元素,存储到特征矩阵中
returnMat[index,:] = listFromLine[0:3]
# 使用索引值-1为表示列表中最后一列元素
if listFromLine[-1] == 'didntLike': #文本内收集的数据
classLabelVector.append(1)
elif listFromLine[-1] == 'smallDoses':
classLabelVector.append(2)
elif listFromLine[-1] == 'largeDoses':
classLabelVector.append(3)
index += 1
return returnMat, classLabelVector
if __name__ == '__main__':
#打开的文件名
filename = "datingTestSet.txt"
# 打开并处理数据
datingDataMat, datingLabels = file2matrix(filename)
print(datingDataMat)
print(datingLabels)
结果:
2.分析数据:使用Matplotlib创建散点图
import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator
def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines) #得到文本行数
returnMat = np.zeros((numberOfLines,3)) #创建返回的NumPy二维矩阵
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
# line.split()截取掉所有回车字符 用tab字符\t将上一步得到的整行数据分割成一个元素列表
listFromLine = line.split('\t')
# 选取前面三个元素,存储到特征矩阵中
returnMat[index,:] = listFromLine[0:3]
# 使用索引值-1为表示列表中最后一列元素
if listFromLine[-1] == 'didntLike': #文本内收集的数据
classLabelVector.append(1)
elif listFromLine[-1] == 'smallDoses':
classLabelVector.append(2)
elif listFromLine[-1] == 'largeDoses':
classLabelVector.append(3)
index += 1
return returnMat, classLabelVector
if __name__ == '__main__':
#打开的文件名
filename = "datingTestSet.txt"
# 打开并处理数据
datingDataMat, datingLabels = file2matrix(filename)
print(datingDataMat)
print(datingLabels)
# 数据可视化
fig = plt.figure()
ax = fig.add_subplot(111) # 111,参数111的意思是:将画布分割成1行1列,图像画在从左到右从上到下的第1块
ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2])
plt.show()
结果:
3.准备数据:归一化数值
import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator
def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines) #得到文本行数
returnMat = np.zeros((numberOfLines,3)) #创建返回的NumPy二维矩阵
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
# line.split()截取掉所有回车字符 用tab字符\t将上一步得到的整行数据分割成一个元素列表
listFromLine = line.split('\t')
# 选取前面三个元素,存储到特征矩阵中
returnMat[index,:] = listFromLine[0:3]
# 使用索引值-1为表示列表中最后一列元素
if listFromLine[-1] == 'didntLike': #文本内收集的数据
classLabelVector.append(1)
elif listFromLine[-1] == 'smallDoses':
classLabelVector.append(2)
elif listFromLine[-1] == 'largeDoses':
classLabelVector.append(3)
index += 1
return returnMat, classLabelVector
# 归一化特征值
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
if __name__ == '__main__':
#打开的文件名
filename = "datingTestSet.txt"
# 打开并处理数据
datingDataMat, datingLabels = file2matrix(filename)
print(datingDataMat)
print(datingLabels)
#归一化特征值
normDataSet, ranges, minVals = autoNorm(datingDataMat)
print(normDataSet)
print(ranges)
print(minVals)
结果:
4.测试算法:作为完整程序验证分类器(写入KNN分类器函数classify0)
import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator
# 在文本文件中解析数据
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet # 距离计算
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistIndices = distances.argsort()
classCount = {}
# 选择距离最小的K个点 把classCount分解为元组列表
for i in range(k):
voteIlabel = labels[sortedDistIndices[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
# itemgetter为排序 为逆序,即按照最大到最小的次序
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines) #得到文本行数
returnMat = np.zeros((numberOfLines,3)) #创建返回的NumPy二维矩阵
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
# line.split()截取掉所有回车字符 用tab字符\t将上一步得到的整行数据分割成一个元素列表
listFromLine = line.split('\t')
# 选取前面三个元素,存储到特征矩阵中
returnMat[index,:] = listFromLine[0:3]
# 使用索引值-1为表示列表中最后一列元素
if listFromLine[-1] == 'didntLike': #文本内收集的数据
classLabelVector.append(1)
elif listFromLine[-1] == 'smallDoses':
classLabelVector.append(2)
elif listFromLine[-1] == 'largeDoses':
classLabelVector.append(3)
index += 1
return returnMat, classLabelVector
# 归一化特征值
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
#测试算法:作为完整程序验证分类器
def datingClassTest():
filename = "datingTestSet.txt"
datingDataMat, datingLabels = file2matrix(filename)
hoRatio = 0.10
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], 4)
print("分类结果:%d\t真实类别:%d" % (classifierResult, datingLabels[i]))
if classifierResult != datingLabels[i]:
errorCount += 1.0
print("错误率:%f%%" % (errorCount / float(numTestVecs) * 100))
if __name__ == '__main__':
#打开的文件名
filename = "datingTestSet.txt"
# 打开并处理数据
datingDataMat, datingLabels = file2matrix(filename)
print(datingDataMat)
print(datingLabels)
#归一化特征值
normDataSet, ranges, minVals = autoNorm(datingDataMat)
print(normDataSet)
print(ranges)
print(minVals)
#测试算法
datingClassTest()
结果:
5.使用算法:构建完整可用系统
import numpy as np
# 数据可视化
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy import *
import operator
# 在文本文件中解析数据
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet # 距离计算
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistIndices = distances.argsort()
classCount = {}
# 选择距离最小的K个点 把classCount分解为元组列表
for i in range(k):
voteIlabel = labels[sortedDistIndices[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
# itemgetter为排序 为逆序,即按照最大到最小的次序
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines) #得到文本行数
returnMat = np.zeros((numberOfLines,3)) #创建返回的NumPy二维矩阵
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
# line.split()截取掉所有回车字符 用tab字符\t将上一步得到的整行数据分割成一个元素列表
listFromLine = line.split('\t')
# 选取前面三个元素,存储到特征矩阵中
returnMat[index,:] = listFromLine[0:3]
# 使用索引值-1为表示列表中最后一列元素
if listFromLine[-1] == 'didntLike': #文本内收集的数据
classLabelVector.append(1)
elif listFromLine[-1] == 'smallDoses':
classLabelVector.append(2)
elif listFromLine[-1] == 'largeDoses':
classLabelVector.append(3)
index += 1
return returnMat, classLabelVector
# 归一化特征值
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
#测试算法:作为完整程序验证分类器
def datingClassTest():
filename = "datingTestSet.txt"
datingDataMat, datingLabels = file2matrix(filename)
hoRatio = 0.10
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], 4)
print("分类结果:%d\t真实类别:%d" % (classifierResult, datingLabels[i]))
if classifierResult != datingLabels[i]:
errorCount += 1.0
print("错误率:%f%%" % (errorCount / float(numTestVecs) * 100))
# 约会网站预测函数
def classifyPerson():
resultList = ['讨厌','有些喜欢','非常喜欢']
precentTats = float(input("玩视频游戏所耗时间百分比:"))
ffMiles = float(input("每年获得的飞行常客里程数:"))
iceCream = float(input("每周消费的冰激淋公升数:"))
filename = "datingTestSet.txt"
datingDataMat, datingLabels = file2matrix(filename)
normMat, ranges, minVals = autoNorm(datingDataMat)
inArr = np.array([precentTats, ffMiles, iceCream])
norminArr = (inArr - minVals) / ranges
classifierResult = classify0(norminArr, normMat, datingLabels, 3)
print("你可能%s这个人" % (resultList[classifierResult - 1]))
# 数据可视化
if __name__ == '__main__':
#打开的文件名
filename = "datingTestSet.txt"
# 打开并处理数据
datingDataMat, datingLabels = file2matrix(filename)
print(datingDataMat)
print(datingLabels)
#归一化特征值
normDataSet, ranges, minVals = autoNorm(datingDataMat)
print(normDataSet)
print(ranges)
print(minVals)
#测试算法
datingClassTest()
# 约会网站预测函数
classifyPerson()
结果:(数据自己输入,随意的)
总结
用的是pycharm编译软件,目录如下
海伦通过收集的数据得到一个非线性的散点图,为了得到准确的分类器,海伦把三个特征值(即每年获得的飞行常客里程数,玩视频游戏所耗时间百分比,每周消费的冰淇淋公升数)选取其中两个为最小特征值(minVals)还有最大特特征值(maxVals),通过权重来计算结果。文本中,只有90%作为训练样本训练,10%去测试分类器,然后测试分类器的效果,如果分类器的正确率满足要求,则海伦能拿着这个软件处理约会网站的约会名单了。