Python实现kNN分类算法

# -*- 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 np
import operator

class 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 = path
		self.feats_num = feats_num
		self.if_norm = if_norm
		self.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 = True
		comments = '#'
		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_ndarray
	
	def get_classes_ndarray(self):
		''' 返回数据类别集合 '''
		# 为genfromtxt()函数设置属性
		names = ('class')
		delimiter = ','
		autostrip = True
		comments = '#'
		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_ndarray

	def 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_vector

	def get_min_feats_vector(self):
		''' 返回数据集中各列最小值构成的向量(一维数组) '''
		min_feats_vector = np.array(
			[min(cols) for cols in self.feats_ndarray.transpose()])
		return min_feats_vector

	def 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]] = 0
	for j in range(k):
		class_count[class_distance[j][0]] = class_count.get(
									class_distance[j][0]) + 1
	sorted_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_predict

if __name__ == '__main__':
	path_train = '你的训练集路径'
	path_predict = '你的待分类数据集路径'
	feats_num = 你的样本特征值数
	if_norm = 是否对数据进行规范化,0或1
	k = 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))
	
	

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值