import numpy as np
import operator
"""
函数说明:打开并解析文件,对数据进行分类
Parameters:
filename - 文件名
Returns:
returnMat - 特征矩阵
classLabelVector - 分类标签向量
Modify:
2019-03-02
"""
def file2matrix(filename):
# 打开文件
file = open(filename)
# 获取文件内容
arrayOfLines = file.readlines()
# 文件中数据的行数(即数据的条数)
numberOfLines = len(arrayOfLines)
# 创建一个numpy矩阵:numberOfLines行,3列,用“0”填充
returnMat = np.zeros((numberOfLines, 3))
# 存储分类标签的向量
classLabelVevtor = []
# 行索引
index = 0
# 扫描每一条数据,并做一些处理
for line in arrayOfLines:
# Python strip(rm)方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
# 注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。
line = line.strip()
listFromLine = line.split('\t')
returnMat[index, :] = listFromLine[0:3]
if (listFromLine[-1] == 'didntLike'):
classLabelVevtor.append(1)
elif (listFromLine[-1] == 'smallDoses'):
classLabelVevtor.append(2)
elif (listFromLine[-1] == 'largeDoses'):
classLabelVevtor.append(3)
index += 1
return returnMat, classLabelVevtor
"""
函数作用:KNN算法,分类器
Parameters:
inX - 用于分类的数据(测试集)
dataSet - 用于训练的数据(训练集)
labels - 分类标签
k - KNN算法参数,选择距离最小的k个点
Returns:
sortedClassCount[0][0] - 分类结果
Modify:
2019-03-02
"""
def classify0(inX, dataSet, labels, k):
# 训练集数据条数
dataSetSize = dataSet.shape[0]
# np.tile(data,(y,x)):以矩阵data为基础单元,形成一个y行x列的矩阵:
# |X Y|
# |X Y| -> |X Y|
# |X Y|
#
# |X Y| |x1 y1|
# |X Y| - |x2 y2|
# |X Y| |x3 y3|
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
# | ( X - x1 )**2 ( Y - y1 )**2 |
# | ( X - x2 )**2 ( Y - y2 )**2 |
# | ( X - x3 )**2 ( Y - y3 )**2 |
sqDiffMat = diffMat ** 2
# | ( X - x1 )**2 + ( Y - y1 )**2 |
# | ( X - x2 )**2 + ( Y - y2 )**2 |
# | ( X - x3 )**2 + ( Y - y3 )**2 |
sqDistance = sqDiffMat.sum(1)
# | sqr{ ( X - x1 )**2 + ( Y - y1 )**2 }|
# | sqr{ ( X - x2 )**2 + ( Y - y2 )**2 }|
# | sqr{ ( X - x3 )**2 + ( Y - y3 )**2 }|
distances = sqDistance ** 0.5
# 返回distances中所有元素从小到大排序的索引值
sortedDistIndices = distances.argsort()
# 字典classCount{标签1:次数 , 标签2:次数}
classCount = {}
# 统计前K个元素中各标签出现的次数
for i in range(k):
# 离(X ,Y)第i近的点的标签
voteIlabel = labels[sortedDistIndices[i]]
# 将该标签的数量+1
# (字典名.get( key ,x )) 获取字典中键名key的键值对的值,为如果字典中没有这个键名对应的键值对,则在字典中添加本键值对,且令其值为:x
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
# sorted( 可迭代序列 ,key ,是否逆序 ) key参数的值为一个函数,此函数只有一个参数且返回一个值用来进行比较
# operator.itemgetter(维度):函数的返回值是一个函数,这个函数的作用为返回某对象指定维度的数据
# 例:operator.itemgetter( x )([0,1,2,3,4,5,6,7,8,9])
# 返回元组中下标为x的元素
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
"""
函数说明:对数据进行归一化
Parameters:
dataSet - 特征矩阵
Returns:
normDataSet - 归一化后的特征矩阵
ranges - 数据范围
minVals - 数据最小值
Modify - 2019-03-03
"""
def autoNorm(dataSet):
# numpy数组.min()/max() :返回矩阵中所有元素的最小或最大值
# numpy数组.min(0)/max(0) :返回矩阵中每一列的最小或最大值
# numpy数组.min(1)/max(1) :返回矩阵中每一行的最小或最大值
# | 1 2 | npArray.min() == 0 npArray.max() == 7
# npArray = | 7 0 | npArray.min(0) == [ 1 0 ] npArray.max(0) == [ 7 6 ]
# | 5 6 | npArray.min(1) == [ 1 0 5 ] npArray.max(1) == [ 2 7 6 ]
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
# 最大值和最小值的差值
range = maxVals - minVals
# np.shape(矩阵)返回值:(矩阵行数,矩阵列数)
# np.zeros((矩阵行数,矩阵列数))返回值:以0填充的指定行数、列数的矩阵
normalDataSet = np.zeros(np.shape(dataSet))
# 训练集数据条数
m = dataSet.shape[0]
normalDataSet = dataSet - np.tile(minVals, (m, 1))
normalDataSet = normalDataSet / np.tile(range, (m, 1))
return normalDataSet, range, minVals
"""
函数说明:分类器测试函数
Parameters:
null
Returns:
normalDataSet - 数值归一后的特征矩阵
ranges - 数据范围(max-min)
minVals - 数据最小值
Modify:
2019-03-03
"""
def datingClassTest(k):
filename = "datingTestSet.txt"
# 获取特征矩阵和标签向量
datingDataMat, datingLabels = file2matrix(filename)
# 数值归一后的特征矩阵 数据范围 数据最小值
normalMat, ranges, minVals = autoNorm(datingDataMat)
# 特征矩阵行数
m = normalMat.shape[0]
# 测试数据占特征矩阵中数据的比例
hoRatio = 0.10
# 测试数据的条数
numTextVecs = int(m * hoRatio)
# 统计错误次数
errorCount = 0.0
for i in range(numTextVecs):
# 前numTextVecs条数据作为测试集,剩下的m-numtextVecs条数据作为训练集
classifierResult = classify0(normalMat[i, :], normalMat[numTextVecs:m, :], datingLabels[numTextVecs:m], k)
print("分类结果:%d\t真实类别:%d" % (classifierResult, datingLabels[i]))
if (classifierResult != datingLabels[i]):
errorCount += 1.0
print("错误率为:%f%%" % (errorCount / float(numTextVecs) * 100))
return errorCount / float(numTextVecs) * 100
"""
函数作用:main函数
Parameters:
null
Returns:
null
Modify:
2019-03-03
"""
if __name__ == '__main__':
# 存储k值从1到20时分类器的错误率
k_err = []
for k in range(20):
k_err.append(datingClassTest(k + 1))
print(k_err)
# python元组转为numpy数组
print(np.array(k_err, dtype=float))
# 返回numpy数组中元素从小到大排序后,元素的索引值
print(np.array(k_err, dtype=float).argsort())
print("k值最小设为", np.array(k_err, dtype=float).argsort()[0] + 1, "时分类器错误率能够达到最低。")
K-邻近算法示例:使用k-邻近算法改进约会网站的配对效果
猜你喜欢
转载自blog.csdn.net/qq_39514033/article/details/88088353
今日推荐
周排行