#-*-coding:utf-8-*-
from numpy import *
import operator
from os import listdir
"""
KNN算法的原理:
存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据
与所属分类的对应关系。输人没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,
然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最
相似的数据,这就是 k 近邻算法中k的出处 , 通常k是不大于 20 的整数。最后,选择 k个最相似数据中
出现次数最多的分类,作为新数据的分类。
构造数据集 -> 归一化特征值 -> 分类 -> 测试错误率(调整k值) -> 投入使用
"""
#构造数据集
def createDataSet():
group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels = ['A','A','B','B']
return group,labels
#-------------------------------------------使用k近邻算法改进约会网站的配对效果-----------------------------------------------
"""
------calssify0()------
------inX: 用于分类的输入向量
------dataSet: 输入的训练样本集
------labels: 标签向量(标签向量的元素数目==dataSet的行数)
------k: 用于选择最近邻居的数目
"""
#用KNN进行预测
def classify0(inX,dataSet,labels,k):
# array.shape返回一个元组(行数,列数),shape[0]表示的是行数
dataSetSize = dataSet.shape[0]
#计算距离,使用的是欧氏距离公式
"""
----------------tile()--------------------
函数格式tile(A,reps)
A和reps都是array_like
A的类型众多,几乎所有类型都可以:array, list, tuple, dict, matrix以及基本数据类型int, string, float以及bool类型。
reps的类型也很多,可以是tuple,list, dict, array, int, bool.但不可以是float, string, matrix类型。
例如:
>>> b=[1,3,5]
>>> tile(b,[2,3])
array([[1, 3, 5, 1, 3, 5, 1, 3, 5],
[1, 3, 5, 1, 3, 5, 1, 3, 5]])
"""
diffMat = tile(inX,(dataSetSize,1)) - dataSet
sqDiffMat = diffMat ** 2
"""
----------------mat.sum()--------------------
a1=mat([[1,1],[2,3],[4,2]]);
a2=a1.sum(axis=0);//列和,这里得到的是1*2的矩阵
a3=a1.sum(axis=1);//行和,这里得到的是3*1的矩阵
a4=sum(a1[1,:]);//计算第一行所有列的和,这里得到的是一个数值
"""
sqDistances = sqDiffMat.sum(axis = 1) #行和,这里得到的是4*1的矩阵
distances = sqDistances ** 0.5
#选择距离最小的k个点
"""
----------------array.argsort()--------------------
argsort函数返回的是数组值从小到大的索引值
>>> x = np.array([3, 1, 2])
>>> np.argsort(x)
array([1, 2, 0])
"""
sorteDistIndicies = distances.argsort()
#定义一个字典
classCount = {}
for i in range(k):
voteIlabel = labels[sorteDistIndicies[i]]
"""
----------------dict.get()--------------------
Python 字典 get() 方法和 setdefault() 方法类似,返回指定键的值,如果键不在字典中,返回一个指定值,默认为None。
key -- 字典中要查找的键。
default -- 可选参数,如果指定键的值不存在时,返回该值,默认为 None。
"""
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
#排序
"""
----------------sorted()--------------------
sorted(iterable[, cmp[, key[, reverse]]])
sorted() 函数对所有可迭代的对象进行排序操作。
sort 与 sorted 区别:
sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个
新的 list,而不是在原来的基础上进行的操作。
# sorted()可以利用参数reverse=True进行反向排序
>>>list=[3,4,2,6,1]
>>>sorted(list)
[1, 2, 3, 4, 6]
>>>sorted(list, reverse=True)
[6, 4, 3, 2, 1]
"""
"""
----------------dict.items()--------------------
字典(Dictionary) items() 函数以列表返回可遍历的(键, 值) 元组数组。
返回可遍历的(键, 值) 元组数组。
"""
"""
----------------operator.itemgetter()--------------------
operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号),下面看例子。
a = [1,2,3]
>>> b=operator.itemgetter(1) //定义函数b,获取对象的第1个域的值
>>> b(a)
2
要注意,operator.itemgetter函数获取的不是值,而是定义了一个函数,通过该函数作用到对象上才能获取值。
"""
sortedClassCount = sorted(classCount.items(),
key = operator.itemgetter(1),
reverse = True)
#返回k个最近邻居出现频率最高的类别,作为当前inX的预测分类
return sortedClassCount[0][0]
#将文本记录转换为Numpy的解析程序
def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()#将每一行内容作为一个元素,共同组成一个列表
numberOfLines = len(arrayOLines)#列表长度,即列表成员个数
returnMat = zeros((numberOfLines,3))#用0填充一个(numberOfLines*3)的矩阵
classLabelVector = []#用于存储每条数据所对应的类别
index = 0
for line in arrayOLines:
"""
----------------str.strip()--------------------
Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)。
语法:str.strip([chars]);
"""
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat, classLabelVector
# 归一化特征值
def autoNorm(dataSet):
"""
----------------mat.min()--------------------
a = np.array([[1,5,3],[4,2,6]])
print(a.min()) #无参,所有中的最小值
print(a.min(0)) # axis=0; 每列的最小值 ,得到1*3的矩阵
print(a.min(1)) # axis=1;每行的最小值 ,得到2*1的矩阵
"""
minVals = dataSet.min(0)#得到1*3的矩阵
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))#shape(矩阵),返回一个元组(行数,列数)
m = dataSet.shape[0]#矩阵的行数
normDataSet = dataSet - tile(minVals,(m,1))
normDataSet = normDataSet/tile(ranges,(m,1))
return normDataSet, ranges, minVals
'''
----------------datingClassTest()------------------
用于测试knn预测结果的错误率
首先把数据集datingDataMat分为两部分:测试集(0-numTestVecs)和训练集(numTestVecs-m)
'''
def datingClassTest():
# hoRatio 是测试集占数据集的比例
hoRatio = 0.1
datingDataMat,datingLabels = file2matrix('datingData.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)))
#约会网站预测函数
"""
每年获得的飞行常客里程数 玩视频游戏所耗时间百分比 每周消费的冰激凌公升数 分类
7-10 7-10 1-3 极具魅力的人
4-6 4-6 4-6 魅力一般的人
1-3 1-3 7-10 不喜欢
"""
def classifyPerson():
resultList = ['in large doses','in small doses','not at all']
"""
-----------------input()----------------------
python2.x 用的是 raw_input()
python3.x 用的是 input()
"""
percentTats = float(input(\
'percentage of time spent playing video games:'))
ffMiles = float(input(\
'frequent flier miles earned per years:'))
iceCream = float(input(\
'liters of ice cream consumed per year:'))
datingDataMat,datingLabels = file2matrix('datingData.txt')
normMatm,ranges,minVals = autoNorm(datingDataMat)
inArr = array([ffMiles,percentTats,iceCream])
classifierResult = classify0((inArr-minVals)/ranges,\
normMatm,datingLabels,3)
print('You will probably like this person:%s'\
% resultList[classifierResult - 1])
#----------------------------------------------------使用 k-近邻算法 识别手写数字---------------------------------------------------
"""
--------------------img2vector()-------------------------
该函数创建1×1024的NumPy数组,然后打开给定的文件,循环读出文件的前32行,
并将每行的头32个字符值存储在NumPy数组中,最后返回数组
"""
def img2vector(filename):
returnVect = zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0,32*i+j] = int(lineStr[j])
return returnVect
"""
--------------------handwritingClassTest()-------------------------
手写数字识别系统的测试代码
"""
def handwritingClassTest():
hwLabels = []
trainingFileList = listdir('digits//trainingDigits')
m = len(trainingFileList)
trainingMat = zeros((m,1024))
for i in range(m):
#该目录下的文件按照规则命名,如文件9_45.txt的分类是9,它是数字9的第45个实例
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
trainingMat[i,:] = img2vector('digits//trainingDigits//%s' % fileNameStr)
testFileList = listdir('digits//testDigits')
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector('digits//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
print('the total number of errors is: %d' % (errorCount))
print('the total error rate is: %f' % (errorCount / float(mTest)))