import numpy as np
import pandas as pd
#读取数据集,header参数来指定参数标题的行,默认为0,第一行,如果没有标题使用None
data = pd.read_csv('iris.csv',header=0)
#对文本进行处理,将Species列的文本映射成数值类型
data['Species'] = data['Species'].map({'Iris-virginica':0,'Iris-setosa':1,'Iris-versicolor':2})
#data.head(20)
#显示末尾行数
# data.tail(20)
#随机显示,默认为1条
data.sample(10)
#删除不需要的列
data.drop("id",axis=1,inplace=True)
#重复值检查,any(),一旦有重复值,就返回True
data.duplicated().any()
#删除重复的数据
data.drop_duplicates(inplace=True)
#查看各类别的数据条数
data['Species'].value_counts()
data
#编写KNN类
class KNN:
"""使用python实现K近邻算法"""
def __init__(self,k):
"""初始化方法
Parameters:
----
k:int
邻居的个数
"""
self.k = k
def fit(self, X, y):
"""训练方法
Parameters
----
X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
y:类似数组类型,形状为[样本数量]
每个样本的目标值,也是就是标签
"""
#将X转换成ndarray类型,如果X已经是ndarray则不进行转换
self.X = np.asarray(X)
self.y = np.asarray(y)
def predict(self, X):
"""根据参数传递的样本,对样本数据进行预测,返回预测之后的结果
Parameters
----
X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
Return
----
result:数类型,预测的结果。
"""
#将测试的X转换为ndarray结构
X = np.asarray(X)
result = []
for x in X:
#ndarray相减为对应元素相减,测试的X的每一行与self.X 相减
#求欧氏距离:每个元素都取平方值
dis = np.sqrt(np.sum((x - self.X) ** 2,axis = 1))
#求最近的k个点的距离,sort()排序不适用,因为排序后打乱了顺序
#argsort(),返回每个元素在排序之前原数组的索引
index = dis.argsort()
#取前k个元素,距离最近的k的元素
index = index[:self.k]
#返回数组中每个元素出现的次数,元素必须是非负整数
count = np.bincount(self.y[index])
#返回ndarray之最大的元素的索引,该索引就是我们判定的类别
result.append(count.argmax())
return np.asarray(result)
def predict2(self, X):
"""根据参数传递的样本,对样本数据进行预测(考虑权重,使用距离的倒数作为权重),返回预测之后的结果
Parameters
----
X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
Return
----
result:数类型,预测的结果。
"""
#将测试的X转换为ndarray结构
X = np.asarray(X)
result = []
for x in X:
#ndarray相减为对应元素相减,测试的X的每一行与self.X 相减
#求欧氏距离:每个元素都取平方值
dis = np.sqrt(np.sum((x - self.X) ** 2,axis = 1))
#求最近的k个点的距离,sort()排序不适用,因为排序后打乱了顺序
#argsort(),返回每个元素在排序之前原数组的索引
index = dis.argsort()
#取前k个元素,距离最近的k的元素
index = index[:self.k]
#返回数组中每个元素出现的次数,元素必须是非负整数,【使用weight考虑权重,权重为距离的倒数】
count = np.bincount(self.y[index],weights=1/dis[index])
#返回ndarray之最大的元素的索引,该索引就是我们判定的类别
result.append(count.argmax())
return np.asarray(result)
#数据集拆分成训练集和测试集
#1、提取每个类别鸢尾花的数量
t0 = data[data['Species']==0]
t1 = data[data['Species']==1]
t2 = data[data['Species']==2]
#打乱顺序,random_state ,记住打乱的顺序
t0 = t0.sample(len(t0),random_state=0)
t1 = t1.sample(len(t1),random_state=0)
t2 = t2.sample(len(t2),random_state=0)
train_X = pd.concat([t0.iloc[:40,:-1],t1.iloc[:40,:-1],t2.iloc[:40,:-1]],axis=0)
train_Y = pd.concat([t0.iloc[:40,-1],t1.iloc[:40,-1],t2.iloc[:40,-1]],axis=0)
test_X = pd.concat([t0.iloc[40:,:-1],t1.iloc[40:,:-1],t2.iloc[40:,:-1]],axis=0)
test_Y = pd.concat([t0.iloc[40:,-1],t1.iloc[40:,-1],t2.iloc[40:,-1]],axis=0)
#进行训练与测试
knn = KNN(k=3)
#进行训练
knn.fit(train_X,train_Y)
#进行测试
result = knn.predict(test_X)
# display(result)
# display(test_Y)
#查看预测结果
display(np.sum(result == test_Y))
#对计算结果进行可视化展示
import matplotlib as mpl
import matplotlib.pyplot as plt
#设置matplotlib 支持中文显示
mpl.rcParams['font.family'] = 'SimHei' #设置字体为黑体
mpl.rcParams['axes.unicode_minus'] = False #设置在中文字体是能够正常显示负号(“-”)
#设置画布大小
plt.figure(figsize=(10,10))
#挑选维度进行散点图显示
#绘制训练集的散点图'Iris-virginica':0,'Iris-setosa':1,'Iris-versicolor':2
plt.scatter(x=t0['SepalLengthCm'][:40],y=t0['PetalLengthCm'][:40],color='r',label='Iris-virginica')
plt.scatter(x=t1['SepalLengthCm'][:40],y=t1['PetalLengthCm'][:40],color='g',label='Iris-setosa')
plt.scatter(x=t2['SepalLengthCm'][:40],y=t2['PetalLengthCm'][:40],color='b',label='Iris-versicolor')
#绘制测试集数据,使用不同的图案显示预测正确和错误的结果
right = test_X[result == test_Y]
wrong = test_X[result != test_Y]
plt.scatter(x=right['SepalLengthCm'],y=right['PetalLengthCm'],color='c',marker='x',label='right')
plt.scatter(x=wrong['SepalLengthCm'],y=wrong['PetalLengthCm'],color='m',marker='>',label='wrong')
#显示额外信息
plt.xlabel("花萼长度")
plt.ylabel("花瓣长度")
plt.title("KNN分类显示结果")
plt.legend(loc="best")
plt.show()