Python实现kNN分类算法

来源:互联网 发布:惊艳的名字知乎 编辑:程序博客网 时间:2024/05/18 04:53
# -*- coding: UTF-8 -*-'''Created on 2014年5月26日@author: LiuJian用途:对数据进行分类原理:kNN分类法通过测量不同特征值之间的距离来对数据进行分类步骤:1.计算已知类别数据集中的点与当前点之间的距离2.按照距离升序排列数据集3.选取与当前点距离最小的k个点,即数据集中前k个观测值4.确定k个点中频率最高的类别5.返回该类别作为当前点的预测分类附注:1.采用欧氏距离测量数据点之间的差异2.采用最小-最大规范法对数据进行归一化,但该功能默认不启用3.训练数据集结构:每行一个样本,样本各特征值之间以逗号分隔,例如:    特征值1,特征值2,特征值3,特征值4,...,特征值n,类别4.预测数据集结构与训练数据集相同,但最后的类别值统一为问号“?”'''import numpy as npimport operatorclass DataSet(object):''' 数据集基类 DataSet对象包括6个属性:数据集存储路径path、数据样本总数size、数据集特征值个数feats_num、数据集类别集合classes_set、数据特征值数组feats_ndarray、是否规范化数据if_norm、样本类别数组classes_ndarray。'''def __init__(self, path, feats_num, if_norm):''' 初始化DataSet对象 '''self.path = pathself.feats_num = feats_numself.if_norm = if_normself.feats_ndarray = self.get_feats_ndarray()self.classes_ndarray = self.get_classes_ndarray()self.classes_set = self.get_classes_set()self.size = self.get_size()if if_norm:# 规范化数据集中所有特征值self.normalize_feats_ndarray()def get_feats_ndarray(self):''' 返回数据特征值数组 '''# 为genfromtxt()函数设置属性delimiter = ','autostrip = Truecomments = '#'dtype = np.float_usecols = tuple(range(self.feats_num))# 获取数据集中所有的特征值,返回二维数组feats_ndarray = np.genfromtxt(self.path, dtype=dtype, comments=comments, delimiter=delimiter, autostrip=autostrip,usecols=usecols)return feats_ndarraydef get_classes_ndarray(self):''' 返回数据类别集合 '''# 为genfromtxt()函数设置属性names = ('class')delimiter = ','autostrip = Truecomments = '#'dtype = np.str_convertfunc = lambda x: str(x)converters = {'class': convertfunc}usecols = -1# 获取数据集中的类别数据(最后一列),返回一维数组classes_ndarray = np.genfromtxt(self.path, dtype=dtype, names=names,comments=comments,delimiter=delimiter, converters=converters, autostrip=autostrip,usecols=usecols)return classes_ndarraydef get_classes_set(self):''' 返回数据集中所有存在的类别构成的列表 '''return list(set(self.classes_ndarray))def get_size(self):''' 获取数据集的大小 '''return self.feats_ndarray.shape[0]def get_feats_vector(self, index):''' 返回第index个样本的特征值向量(一维数组) '''return self.feats_ndarray[index]def get_class(self, index):''' 返回第index个样本所属的类别 '''return self.classes_ndarray[index]def get_max_feats_vector(self):''' 返回数据集中各列最大值构成的向量(一维数组) '''max_feats_vector = np.array([max(cols) for cols in self.feats_ndarray.transpose()])return max_feats_vectordef get_min_feats_vector(self):''' 返回数据集中各列最小值构成的向量(一维数组) '''min_feats_vector = np.array([min(cols) for cols in self.feats_ndarray.transpose()])return min_feats_vectordef normalize_feats_ndarray(self):''' 最小-最大规范法对数据进行归一化 '''# 分别根据最大值和最小值向量构造与原特征值矩阵相同形状的二维数组max_mat = np.repeat([self.get_max_feats_vector()], self.size, 0)min_mat = np.repeat([self.get_min_feats_vector()], self.size, 0)# 执行最小-最大规范法的运算self.feats_ndarray = (self.feats_ndarray-min_mat)/(max_mat-min_mat)def knn_classify_one(feats_predict, dataset_train, k):''' 对单个特征值向量的kNN分类器 '''# 计算待分类的特征值向量与训练集中所有特征值向量之间的距离distance_list = list()for i in range(dataset_train.size):# 计算两个特征值向量之间的距离,即差的范数distance = np.linalg.norm(feats_predict - dataset_train.get_feats_vector(i))distance_list.append(distance)# 构造class-distance元组对构成的列表class_distance = zip(list(dataset_train.classes_ndarray), distance_list)# 根据上面列表中的distance项对列表元组进行升序排序,并取得前k个元组class_distance.sort(key=lambda class_distance: class_distance[1])class_distance = class_distance[:k]# 计算上面大小为k的列表中最频繁出现的类别class_count = dict()for m in range(len(dataset_train.classes_set)):class_count[dataset_train.classes_set[m]] = 0for j in range(k):class_count[class_distance[j][0]] = class_count.get(class_distance[j][0]) + 1sorted_class_count = sorted(class_count.iteritems(),key=operator.itemgetter(1), reverse=True)return sorted_class_count[0][0]def knn_classify_all(path_train, path_predict, feats_num, if_norm, k):''' 对一组特征值向量的kNN分类器 '''dataset_train = DataSet(path_train, feats_num, if_norm)dataset_predict = DataSet(path_predict, feats_num, if_norm)# 为待分类数据集中每一个样本进行分类,并修改data_predict中的类别数组classification = list()for i in range(dataset_predict.size):classification.append(knn_classify_one(dataset_predict.get_feats_vector(i), dataset_train, k))dataset_predict.classes_ndarray = np.array(classification)return dataset_predictif __name__ == '__main__':path_train = '你的训练集路径'path_predict = '你的待分类数据集路径'feats_num = 你的样本特征值数if_norm = 是否对数据进行规范化,0或1k = k值dataset_predict = knn_classify_all(path_train, path_predict, feats_num, if_norm, k)for i in range(dataset_predict.size):print str(dataset_predict.get_feats_vector(i)), '--->', \str(dataset_predict.get_class(i))

0 0