k- 近邻算法
- 需要用到的模块:numpy,operator
1、定义函数
- 函数1:从文件中提取数据,形成numpy数组
- 函数2:归一化数据
- 函数3:分类器
- 函数4:检验分类器错误率
2、分类器步骤
- 定义距离(一般采用欧式距离)
- 按照距离排序
- 选取距离要分类的数据最近的k个点(距离最小)
- 确定这k个点类别频率
- 返回频率最高的类别作为预测分类
3、代码
from numpy import *
import operator
##从文本中提取信息
def filemat(filename):
file = open(filename)
lines = file.readlines()
lines_number = len(lines)
#创建一个与文本相同行,相同列的零矩阵
#列需要事前确定
zeromat = zeros((lines_number,3))
#空字典作为类别
class_label = []
index = 0
#提取文件数据
for line in lines:
line = line.strip()
line_list = line
list1 = line.split('\t')
#用文件中的数据替换零矩阵和空类别
zeromat[index,:] = list1[0:3]
class_label.append(list1[-1])
index+=1
return zeromat,class_label
## 归一化方法:(x-min)/range
def auto_norm(dataset):
# 选取每一列的最大最小值
min_value = dataset.min(0)
max_value = dataset.max(0)
ranges = max_value - min_value
# 形成一个与数据集相同的零矩阵
norm_dataset = zeros(shape(dataset))
shape0 = dataset.shape[0]
# 得到当前值与最小值的差值矩阵
norm_dataset = dataset - tile(min_value,(shape0,1))
norm_dataset = norm_dataset/tile(ranges,(shape0,1))
return norm_dataset,ranges,min_value
## 欧氏距离分类(注意需不需要事先将X归一化)
def classify(X,dataset,labels,k):
# shape函数的功能是读取矩阵的维度
# shape[0]代表一维中的元素数,二维中的行数
datasetsize = dataset.shape[0]
# 创建X与所有点的距离数组
diffMat = tile(X,(datasetsize,1))-dataset
sqdiffMat = diffMat**2
sqDistances = sqdiffMat.sum(axis=1)
distances = sqDistances **0.5
#从小到大排列所有点与X的距离
sortDisindex = distances.argsort()#列表
classCount={}
#选择前k个距离最近的点并统计这k个点的类别次数
for i in range(k):
klabel = labels[sortDisindex[i]]
classCount[klabel] = classCount.get(klabel,0)+1
#将k个点的类别出现次数进行排序,取最高出现次数的类别
sortclasscount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
# 返回分类结果
return sortclasscount[0][0]
## 检测分类器错误率(自分类为测试集和训练集)
def classify_test(data_mat,data_labels,ratio=0.1):
line_num = data_mat.shape[0]
test_num = int(ratio*line_num)
error_count = 0.0
for i in range(test_num):
classify_result = classify(data_mat[i,:],data_mat[test_num:line_num,:],\
data_labels[test_num:line_num],k=3)
if (classify_result != data_labels[i]) : error_count+=1
error_rate = float(error_count)/(float(test_num))
return error_rate
4、example
from os import listdir
import numpy as np
import operator
import kNN
## 读取文件
def imagex(filename):
f = open(filename)
# 形成一个1024维的行向量
return_vector = zeros((1,1024))
for i in range(32):
line_str = f.readline()
for j in range(32):
return_vector[0,32*i+j] = int(line_str[j])
return return_vector
def handwritingtest():
hwlabels=[]
# 将文件夹下所有文件名提出,需要与代码在同一文件夹
training_list = listdir('trainingDigits')
test_list = listdir('testDigits')
train_num = len(training_list)
test_num = len(test_list)
train_mat = zeros((train_num,1024))
# 训练集—将所有文件中的数据放入一个numpy数组
for i in range(train_num):
filename = training_list[i]
file = filename.split('.')[0]
class_number = int(file.split('_')[0])
hwlabels.append(class_number)
train_mat[i,:] = imagex('trainingDigits/%s'%filename)
error_count0 =0.0
# 测试集进行测试
for i in range(test_num):
filename = test_list[i]
file = filename.split('.')[0]
class_number = int(file.split('_')[0])
test_vector = imagex('testDigits/%s'%filename)
class_result = classify(test_vector,train_mat,hwlabels,k=3)
if (class_result != class_number):error_count0+=1
error_rate = float(error_count0)/(float(test_num))
return error_rate
if __name__=="__main__":
rate = handwritingtest()
print(rate)