一、部分说明
----------------------------------------------------------------
1、本文代码是《机器学习实战》这本书的例程。点击下载
2、运行环境为:window10+python3.2+各种python机器学习库。
安装可参考:点击打开链接
3、本文注重代码的实现过程,其基本知识请参考《机器学习实战》和一些知名博客。
4、本人属于初学者,有些注释部分可能不对,还请指正。
5、(1)、本代码从原来的python2.x改为python3.x;
(2)、加入详细的注释,方便理解;
(3)、还有加入自己想要实现的一些功能。
----------------------------------------------------------------
二、重点回顾
1、kNN算法的伪代码:
(1)、计算当前的将分类的点和其他已知类别点的距离;
(2)、按照距离从小到大排序(从近到远);
(3)、从(2)中排好序列中,选取前k个点(及离当前点最近的k个点);
(4)、统计这k个点各个类别的个数;
(5)、这k个点中属于哪个类别最多,就认为当前前就属于这个类别,并返回这个类别标签;
2、个人理解
越近的点其相似度越高,越远的点相似度越低;即一个点的类别至于自己周围点的关系比较大,故大概只选取k个最近的点的意思,有些人可能会问直接取最近的那个点的类别作为当前点的类别不就可以了?这样的话,如果当前点是一个噪声点,不就不对了嘛,还有参与训练的点的分布是否均匀等,都会导致分类的效果的不好。最好的就是统计这k个的类别关系,降低偶然等因素对分类的影响。
3、数据归一化
数据每个维度的权重应该一样,否则KNN算法就会失效。why?假如某个类X用[x1,x2,x3]表示;其中,0
三、源代码
'''***********************************************************
#欢迎访问主页:http://blog.csdn.net/u013634684/article/details/49634953
Copyright (C), 2015-2020, cyp Tech. Co., Ltd.
FileName: KNN算法.cpp
Author: cyp
Version : v1.0
Date: 2015-10-21 晚上21:02
Description:
主要有两方面:
1、构成的强分类对病马死亡率预测
2、分类性能指标如ROC曲线及AUC
Function List:
1. createDataSet: 构造简单的数据集
2. classify: 分类函数
3. file2mat: 文件转化数组
4. normalizationData: 数组归一化
5. datingTestClassify: 约会测试
6. classifyPerson: 判断某个人的感兴趣程度
7. img2vector: 图像变数组
8. handwritingClassAndTest:手写的测试
9. main: 相当于主函数
***********************************************************'''
'''***********************************************************
需要导入的模块
***********************************************************'''
from numpy import *
import operator
import copy
import math
import matplotlib.pyplot as plt
import numpy as np
from os import listdir
'''***********************************************************
Function: createDataSet
Description: 创建一个简单的数据集
Calls:
Called By:
Input: 无
Return: group:构造简单的数据集
label:数据集对应的标签
************************************************************'''
def createDataSet():
group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
label = ['A','A','B','B']
return group,label
'''***********************************************************
Function: classify
Description: KNN分类核心算法
Calls:
Called By:
Input: 1、input :将分类的一组数
2、dataSet:训练的数据集
3、label :训练数据集对应的标签
4、k :取前k个统计比较
Return: 分类的结果
************************************************************'''
def classify(input,dataSet,label,k):
dataSetSize = dataSet.shape[0] #训练样本数
diffMat = tile(input,(dataSetSize,1))-dataSet
#求将分类向量与各样本之间的差
sqDiffMat = diffMat**2 #差的平方
sqDistance = sqDiffMat.sum(axis=1)
distance = sqDistance**0.5 #求的与每个样本的距离
sortedIndex = distance.argsort() #按距离从小到大排列
classCount = {}
for i in range(k): #对于前k个值
classInstance = label[sortedIndex[i]]
#统计各个类的个数
classCount[classInstance] = classCount.get(classInstance,0)+1
#排列,返回与将分类数据有最多数目同类型的类
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
'''***********************************************************
Function: file2mat
Description: 读取数据,以数组的形式返回
Calls:
Called By: 1、datingTestClassify
2、classifyPerson
3、handwritingClassAndTest
Input: 1、filename :文件名
Return: 1、group: 数据集
2、label: 标签
************************************************************'''
def file2mat(filename):
input = open(filename)
allLine = input.readlines() #载入所有数据
numberLine = len(allLine) #多少数据
line = allLine[0]
line = line.strip()
line = line.split()
numberFeatureVector = len(line) #每行的数据个数
group = zeros([numberLine,(numberFeatureVector-1)])
#存储样本集
label = zeros([1,numberLine]) #存储样本类别
index = 0
for line in allLine:
line = line.strip()
line = line.split()
group[index,:] = line[0:-1] #前n-1为样本特征
label[0,index] = line[-1] #最后为样本的类别
index = index + 1
return group,label #返回数据集,及标签
'''***********************************************************
Function: normalizationData
Description: 归一化数据
Calls:
Called By: 1、datingTestClassify
2、classifyPerson
Input: 1、dataSet: 欲归一化的数据
Return: 1、normData: 归一化后的数据
2、min_value:每一维数据的最小值
3、ranges: 每一维数据的范围
************************************************************'''
def normalizationData(dataSet):
data = copy.deepcopy(dataSet) #数据的复制
min_value = data.min(0) #每一维特征的最小值
max_value = data.max(0) #每一维特征的最大值
ranges = max_value-min_value #特征值范围
rows = data.shape[0] #样本数
normData = zeros(data.shape) #归一化数据,同输入数据同大小
#全部隐射到0-1
normData = data-tile(min_value,(rows,1))
normData = normData/tile(ranges,(rows,1))
return normData,min_value,ranges
'''***********************************************************
Function: datingTestClassify
Description: 读取数据,按比例选取数据训练及测试
Calls:
1、file2mat
2、normalizationData
3、classify
Called By: 1、main
Input: 无
Return: 无
************************************************************'''
def datingTestClassify():
th0 = 0.1 #拿来测试的数据的比例
cwd = "C:/Users/cyp/Documents/sourcecode/"
filename = cwd + "/machinelearning/my__code/chapter2/dataTestSet2.txt"
group,label= file2mat(filename) #从指定路径读取数据
group,temp1,temp2 = normalizationData(group)#数据的归一化
m = group.shape[0] #数据的样本数
n = int(th0*m) #测试样本数
errorCount =0.0 #测试错误个数,其余参与训练
for i in range(n): #分类
classify_result = classify(group[i,:],group[n:,:],label[0,n:],10)
if classify_result!=label[0,i]: #分类错误
errorCount += 1.0 #加1
print("the classifier come back with:%d,the real answer\
is:%d"%(classify_result,label[0,i]))
#输出特使错误率
print ("the total error rate is :%f"%(errorCount/n))
'''***********************************************************
Function: classifyPerson
Description: 根据约会数据训练模型,根据模型判断一个是否
感兴趣
Calls: 1、file2mat
2、normalizationData
3、classify
Called By: 1、main
Input: 无
Return: 无
************************************************************'''
def classifyPerson():
#三种结果,一点儿也不感兴趣,有点儿感兴趣,非常感兴趣
resultList=["not at all","in small doses","in large doses"]
#输入一个的每年的飞行距离
flymile=float(input("frequent flier miles earned per year?"))
#输入打游戏的时间百分比
percentage=float(input("percentage of time spent playing video games?"))
#每年消耗的冰淇淋的数目
icecream=float(input("liters of ice cream consumed per year?"))
cwd = 'C:/Users/cyp/Documents/sourcecode/machinelearning/'
filename =cwd+"my__code/chapter2/dataTestSet2.txt"
group,label= file2mat(filename) #读取训练数据
group,min_value,ranges = normalizationData(group) #训练数据的归一化
#测试数据的归一化
input_value = ([flymile,percentage,icecream]-min_value)/ranges
classify_result = classify(input_value,group[:,:],label[0,:],3)#训练并分类
#输出分类结果
print("You will probably like this person:",(resultList[int(classify_result-1)]))
'''***********************************************************
Function: img2vector
Description: 手写体图片是以文本的形式存储的,次函数就是将图片变为数组
Calls:
Called By: 1、handwritingClassAndTest
Input: filename: 文件名
Return: data_vect: 生成的数组
************************************************************'''
def img2vector(filename):
fr = open(filename) #打开文件
allLine = fr.readlines() #多少行数据
data_vect = []
for line in allLine:
line1 = line[0:-1] #前n-1为样本特征
for c in line1:
data_vect.append(int(c))#添加标签
return data_vect #返回数组
'''***********************************************************
Function: handwritingClassAndTest
Description: 手写体分类
Calls: 1、img2vector
2、classify
Called By: 1、main
Input: filename: 文件名
Return: data_vect: 生成的数组
************************************************************'''
def handwritingClassAndTest():
labels = []
#训练数据样本问价夹,一个txt文件哎,一个样本
trainingfiledir = "C:/Users/cyp/Documents/sourcecode/machinelearning"
trainingfiledir = trainingfiledir+"/my__code/chapter2/digits/trainingDigits"
#获取样本文件名
trainingFileList = listdir(trainingfiledir)
#样本的数目
rows = len(trainingFileList)
#每个样本的数据个数
cols = len(img2vector(trainingfiledir+"/"+trainingFileList[0]))
trainingData = zeros((rows,cols))
for i in range(rows):#对于每个样本
filenameStr = trainingFileList[i] #读取样本文件名
labels.append(int(filenameStr.split('_')[0]))#样本对应标签
trainingData[i,:] = img2vector(trainingfiledir+"/"+filenameStr)[:]#样本变数据
testfiledir = "C:/Users/cyp/Documents/sourcecode/machinelearning"
testFiledir = testfiledir+"/my__code/chapter2/digits/testDigits"
#测试样本文件夹
testFileList = listdir(testFiledir) #获取文件名
test_rows = len(testFileList) #测试样本数
errorcount = 0.0 #错误的个数
for i in range(test_rows):
filenameStr = testFileList[i] #获取指定样本文件名
label = int(filenameStr.split('_')[0]) #读取标签
test_input = img2vector(testFiledir+"/"+filenameStr) #读取样本数据
#分类
classResult = classify(np.array(test_input),np.array(trainingData),np.array(labels),4)
print("the classifier come back with %d,the real answer is :%d"%(classResult,label))
if(classResult!=label):#分类错误
errorcount += 1 #错误计数加1
#输出总测试出错个数
print("the total number of errors is :%d"%errorcount)
#输出总错误率
print("the total error rate is:%f"%(errorcount/float(test_rows)))
'''***********************************************************
Function: main
Description: 主函数
Calls:
1、datingTestClassify
2、classifyPerson
3、handwritingClassAndTest
Called By:
************************************************************'''
if __name__=='__main__':
print ("read start!")
#dating and person test start
datingTestClassify() #约会特使
sign=1
while(sign): #循环测试
classifyPerson() #判断约会对象是否感兴趣
sign=input("is continue?")
if(sign=="Y"): #输入y(不分大小写)继续
sign = 1
elif(sign=="y"):
sign = 1
else: #否则结束
sign = 0
#handwritingClassAndTest start
handwritingClassAndTest() #手写体测试
#handwritingClassAndTest end
四、结果展示
1、数据点类被预测实验
2、约会网站预测实验结果:
3、手写体数字识别实验:
注:本人菜鸟一枚,如有不对的地方还请指正,同时欢迎一起交流。