# -*- 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))
Python实现kNN分类算法
最新推荐文章于 2024-08-29 15:54:17 发布