一、作业题目:
原生Python实现KNN分类算法,用鸢尾花数据集。
二、算法原理:
KNN算法是选择与输入样本在特征空间内最近邻的k个训练样本并根据一定的决策规则,给出输出结果 。
决策规则:
分类任务:输出结果为k个训练样本中占大多数的类 。
回归任务:输出结果为k个训练样本值的平均值 。
三、算法设计:
(1).数据准备
选择鸢尾花数据集(lris)每个样本x包含花萼长度(sepal length)、花萼宽度(sepal width)、花瓣长度(petal length)、花瓣宽度(petal width)四个特征。样本标签y共有三类,分别是Setosa,Versicolor和Virginica。Iris数据集总共包含150个样本,每个类别由50个样本。
数据data应用网上下载数据集。
data = pd.read_csv('iris.data', header=None)
data.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'species']
将三个类别的数据分别提取出来,setosa、versicolor、virginica分别用0、1、2来表示。将每个类别的所有样本分成训练样本(training set)、验证集(validation set)和测试样本(test set),各占所有样本的比例分别为60%,20%,20%。
表示两种类别不同特征的空间分布。选择sepal length和petal length两个特征,在二维平面上作图。
(2) kNN训练函数和预测函数
kNN的训练过程实际上是一种数据标类、数据存储的过程,不包含机器学习算法。首先我们需要定义一个类(class)来实现KNN算法模块。
kNN距离衡量一般有两种方式:L1距离和L2距离。
K值的选择:k值太小会使模型过于复杂,造成过拟合(overfitting);k值太大会使模型分类模糊,造成欠拟合(underfitting)。在KNearestNeighbor类中定义预测函数通过验证集来验证从而决定K值大小。
(3)训练和预测
创建KNearestNeighbor实例对象通过测试发现K=3时,验证集准确率最高。最后,把预测结果绘图表示。依然选择sepal length和petal length两个特征,在二维平面上作图。
四、源代码
import numpy as np import pandas as pd import matplotlib.pyplot as plt data = pd.read_csv('iris.data', header=None) data.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'species'] # 特征及类别名称 X = data.iloc[0:150, 0:4].values y = data.iloc[0:150, 4].values y[y == 'Iris-setosa'] = 0 # Iris-setosa 输出label用0表示 y[y == 'Iris-versicolor'] = 1 # Iris-versicolor 输出label用1表示 y[y == 'Iris-virginica'] = 2 # Iris-virginica 输出label用2表示 X_setosa, y_setosa = X[0:50], y[0:50] # Iris-setosa 4个特征 X_versicolor, y_versicolor = X[50:100], y[50:100] # Iris-versicolor 4个特征 X_virginica, y_virginica = X[100:150], y[100:150] # Iris-virginica 4个特征 plt.scatter(X_setosa[:, 0], X_setosa[:, 2], color='red', marker='o', label='setosa') plt.scatter(X_versicolor[:, 0], X_versicolor[:, 2], color='blue', marker='^', label='versicolor') plt.scatter(X_virginica[:, 0], X_virginica[:, 2], color='green', marker='s', label='virginica') #绘制图像
plt.xlabel('sepal length') plt.ylabel('petal length') plt.legend(loc = 'upper left') plt.show() # training set X_setosa_train = X_setosa[:30, :] y_setosa_train = y_setosa[:30] X_versicolor_train = X_versicolor[:30, :] y_versicolor_train = y_versicolor[:30] X_virginica_train = X_virginica[:30, :] y_virginica_train = y_virginica[:30] X_train = np.vstack([X_setosa_train, X_versicolor_train, X_virginica_train]) y_train = np.hstack([y_setosa_train, y_versicolor_train, y_virginica_train]) # validation set X_setosa_val = X_setosa[30:40, :] y_setosa_val = y_setosa[30:40] X_versicolor_val = X_versicolor[30:40, :] y_versicolor_val = y_versicolor[30:40] X_virginica_val = X_virginica[30:40, :] y_virginica_val = y_virginica[30:40] X_val = np.vstack([X_setosa_val, X_versicolor_val, X_virginica_val]) y_val = np.hstack([y_setosa_val, y_versicolor_val, y_virginica_val]) # test set X_setosa_test = X_setosa[40:50, :] y_setosa_test = y_setosa[40:50] X_versicolor_test = X_versicolor[40:50, :] y_versicolor_test = y_versicolor[40:50] X_virginica_test = X_virginica[40:50, :] y_virginica_test = y_virginica[40:50] X_test = np.vstack([X_setosa_test, X_versicolor_test, X_virginica_test]) y_test = np.hstack([y_setosa_test, y_versicolor_test, y_virginica_test]) #实现knn算法模块,定义训练函数
class KNearestNeighbor(object): def __init__(self): pass # 训练函数 def train(self, X, y): self.X_train = X self.y_train = y # 预测函数 def predict(self, X, k=1): # 计算L2距离 num_test = X.shape[0] num_train = self.X_train.shape[0] dists = np.zeros((num_test, num_train)) # 初始化距离函数 # because(X - X_train)*(X - X_train) = -2X*X_train + X*X + X_train*X_train, so d1 = -2 * np.dot(X, self.X_train.T) # shape (num_test, num_train) d2 = np.sum(np.square(X), axis=1, keepdims=True) # shape (num_test, 1) d3 = np.sum(np.square(self.X_train), axis=1) # shape (1, num_train) dist = np.sqrt(d1 + d2 + d3) # 根据K值,选择最可能属于的类别 y_pred = np.zeros(num_test) for i in range(num_test): dist_k_min = np.argsort(dist[i])[:k] # 最近邻k个实例位置 y_kclose = self.y_train[dist_k_min] # 最近邻k个实例对应的标签 y_pred[i] = np.argmax(np.bincount(y_kclose.tolist())) # 找出k个标签中从属类别最多的作为预测类别 return y_pred KNN=KNearestNeighbor() KNN.train(X_train, y_train) y_pred = KNN.predict(X_test, k=6) accuracy = np.mean(y_pred == y_test) print('测试集预测准确率:%f' % accuracy) # 训练集 plt.scatter(X_setosa_train[:, 0], X_setosa_train[:, 2], color='red', marker='o', label='setosa_train') plt.scatter(X_versicolor_train[:, 0], X_versicolor_train[:, 2], color='blue', marker='^', label='versicolor_train') plt.scatter(X_virginica_train[:, 0], X_virginica_train[:, 2], color='green', marker='s', label='virginica_train') # 测试集 plt.scatter(X_setosa_test[:, 0], X_setosa_test[:, 2], color='y', marker='o', label='setosa_test') plt.scatter(X_versicolor_test[:, 0], X_versicolor_test[:, 2], color='y', marker='^', label='versicolor_test') plt.scatter(X_virginica_test[:, 0], X_virginica_test[:, 2], color='y', marker='s', label='virginica_test') #绘制图像
plt.xlabel('sepal length')
plt.ylabel('petal length')
plt.legend(loc = 4)
plt.show()
五:调试运行过程:
- 三种类别不同特征的空间分布:
2)K=3验证集的准确率最高,选择k值后对测试集进行预测分析 ,测试准确率很高。
- 将测试结果绘制出来
六:总结:
k近邻算法是一种最简单最直观的分类算法,也很简单。kNN算法的本质是在训练过程中,它将所有训练样本的输入和输出标签(label)都存储起来。可以说KNN算法实际上是一种识记类算法。机器学习算法包括两个过程:训练过程和测试过程。训练过程通过使用机器学习算法在训练样本上迭代训练,得到较好的机器学习模型;测试过程是使用测试数据来验证模型的好坏,通过正确率来呈现。
我在网上学习过程中,学习到了用训练集,预测集以及测试集来来取得更好的k值,让算法正确率更高。