import csv
import random
import numpy as np
import operator
import datetime
#KNN算法的操作
#KNN算法的鸢尾花
#python具有五种数据类型 数字 字符串 列表 元组 字典 类型
def open_file(file_name):
"""
打开数据集,进行数据处理
:param file_name: 数据集的路径
:return: 返回数据集的 特征、标签、标签名
"""
#打开CSV文件
with open(file_name) as csv_file:
data_file = csv.reader(csv_file) #读取CSV文件 CSV中将读取的数据转化成list类型
# temp读取的是csv文件的第一行,相当于表头
temp = next(data_file)
# 数据集中数据的总数量 在csv文件中 temp存储了数据的总量 使用列表
n_samples = int(temp[0])
# 数据集中特征值的种类个数 第一行第二个变量存储特征值的种类个数
n_features = int(temp[1])
# 标签名 对列表进行切片
# 输出从第三个开始至列表末尾的所有元素
# https://blog.csdn.net/sinat_28576553/article/details/89047893
# np.array返回指定的array对象
labels_names = np.array(temp[2:])
# 特征集,行数为数据集数量,列数为特征值的种类个数
#https://www.jianshu.com/p/8c4a45137145
#根据给定的shape和数据类型dtype返回一个一维或者多维的数组 数组元素不为空 为随机产生的数据
#这里返回了 行数为数据总数量 列数为特征值的种类个数
features = np.empty((n_samples, n_features))
# 标签集,行数为数据集数量,1列,数据格式为int
labels = np.empty((n_samples,), dtype=np.int)
#enumerate函数的作用就是将一个二维列表拆分成 1:[1,2,3] 2:[1,2,3]的形式 前者为i,后者为j
for i, j in enumerate(data_file):
# 将数据集中的将数据转化为矩阵,数据格式为float
# 将数据中从第一列到倒数第二列中的数据保存在data中
#-1的意思是反向索引 实现了从第一列 到最后一列数据的保存
features[i] = np.asarray(j[:-1], dtype=np.float64)
#print(j)
# 将数据集中的将数据转化为矩阵,数据格式为int
# 将数据集中倒数第一列中的数据保存在target中
#同上 最后一个参数为dtype
labels[i] = np.asarray(j[-1], dtype=np.int)
# 返回 数据,标签 和标签名
#实现了对csv数据的处理 将 csv数据拆分成列表 并实现了对数据的初步处理
return features, labels, labels_names
def random_number(data_size):
"""
该函数使用shuffle()打乱一个包含从0到数据集大小的整数列表。因此每次运行程序划分不同,导致结果不同
:param data_size: 数据集大小
:return: 返回一个列表
"""
number_set = []
#range 生成从0~data_size的数 当data_size=5时, 生成的数字为 0,1,2,3,4
for i in range(data_size):
#append追加单个参数到list的尾部
number_set.append(i)
#shuffle实现了将序列中所有元素随机排序
random.shuffle(number_set)
return number_set
#函数功能:将数据划分成测试机和数据集
def split_data_set(features_set, labels_set, rate=0.20):
"""
分割数据集,默认数据集的20%是测试集
:param features_set: 数据集
:param labels_set: 标签数据
:param rate: 测试集所占的比率
:return: 返回训练集数据、训练集标签、测试集数据、测试集标签
"""
# 计算训练集的数据个数
train_size = int((1-rate)*len(features_set))
# 调用random_number获得随机数据索引
data_index = random_number(len(features_set))
# 分隔数据集
# x是自变量,即输入(分类特征);y是因变量,即输出(分类结果)
#进行切片操作,将数据切成一片一片的小区间
x_train = features_set[data_index[:train_size]]
x_test = features_set[data_index[train_size:]]
#这里使用 data_index的原因就是随机取训练数据和测试数据 因为 data_index是一个从0~datasize-1的随机数 根据随机数切片 划分列表
y_train = labels_set[data_index[:train_size]]
y_test = labels_set[data_index[train_size:]]
#返回训练集数据、训练集标签、测试集数据、测试集标签
return x_train, x_test, y_train, y_test
def data_distance(x_test, x_train):
"""
:param x_test: 测试集
:param x_train: 训练集
:return: 返回计算的距离
"""
#利用numpy自带的公式计算距离 sum求和 sqrt开方
distances = np.sqrt(sum((x_test - x_train) ** 2))
return distances
#KNN主函数 接受参数 返回预测结果
def knn(x_train, y_train, x_test, k):
"""
:param x_train: 训练集特征数据
:param y_train: 训练集标签数据
:param x_test: 测试集特征数据
:param k: 邻居数
:return: 返回一个列表包含预测结果
"""
# 预测结果列表,用于存储测试集预测出来的结果
predict_result_set = []
# 训练集的长度
train_set_size = len(x_train)
# 创建一个全零的矩阵,长度为训练集的长度
distances = np.array(np.zeros(train_set_size))
# 计算每一个测试集与每一个训练集的距离
for x in x_test:
for index in range(train_set_size):
# 计算数据之间的距离
distances[index] = data_distance(x, x_train[index])
# 排序后的距离的下标(从小到大)
sorted_dist = np.argsort(distances)
class_count = {}
# 取出k个最短距离
for j in range(k):
# 获得下标所对应的标签值
sort_label = y_train[sorted_dist[j]]
# 将标签存入字典之中并存入个数 sort_laber 对应的键中存储了计数值
class_count[sort_label] = class_count.get(sort_label, 0) + 1
# 对标签进行排序 函数实现的功能是对字典类型的数据进行排序 reverse为true标志 逆序
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
# 将出现频次最高的放入预测结果列表
predict_result_set.append(sorted_class_count[0][0])
# 返回预测结果列表
return predict_result_set
def predict_score(predict_result_set, y_test):
"""
:param predict_result_set: 预测结果列表
:param y_test: 测试集标签数据
:return: 返回测试精度
"""
count = 0
#比较predict_result_set列表中的值和实际上test数据的集 是否相等 相等 则表示预测正确
for i in range(0, len(predict_result_set)):
if predict_result_set[i] == y_test[i]:
count = count + 1
accuracy = count / len(predict_result_set)
return accuracy
if __name__ == "__main__":
# 1.读入数据
customer_data_set = open_file("D:\\customer.csv")
# 2.分割训练集和测试集
x_train, x_test, y_train, y_test = split_data_set(customer_data_set[0], customer_data_set[1])
# 3.调用KNN算法
start_time = datetime.datetime.now()
result = knn(x_train, y_train, x_test, 8)
end_time = datetime.datetime.now()
# 4.准确率
acc = predict_score(result, y_test)
print("正确标签:", y_test)
print("预测结果:", np.array(result))
print("准确率:" + str(acc * 100) + "%")
# print("测试集的精度:%.2f" % acc)
print("用时:" + str((end_time - start_time).microseconds / 1000) + 'ms')
KNN算法实现预测 根据已经存在的顾客信息,预测顾客是否会成为优秀顾客。