实现KNN算法
原生Python实现KNN分类算法,用鸢尾花数据集。
K最近邻(k-Nearest Neighbor,KNN)的思路:K近邻如果一个样本在特征空间中与k个实例最为相似(即特征空间中最邻近),那么这k个实例中大多数属于哪个类别,则该样本也属于这个类别。其中,计算样本与其他实例的相似性一般采用距离衡量法。离得越近越相似,离得越远越不相似。
如上图所示,k=3,距离绿色样本最近的3个实例中(圆圈内),有两个是红色三角形(正类)、一个是蓝色正方形(负类)。则该样本属于红色三角形(正类)。
k近邻算法的本质:我们知道,一般机器学习算法包括两个过程:训练过程和测试过程。训练过程通过使用机器学习算法在训练样本上迭代训练,得到较好的机器学习模型;测试过程是使用测试数据来验证模型的好坏,通过正确率来呈现。kNN算法的本质是在训练过程中,它将所有训练样本的输入和输出标签(label)都存储起来。测试过程中,计算测试样本与每个训练样本的距离,选取与测试样本距离最近的前k个训练样本。然后对着k个训练样本的label进行投票,票数最多的那一类别即为测试样本所归类。
实现的主要函数:
class KNNClassifier:
def fit(self, X_train, y_train):
"""根据训练数据集X_train和y_train训练kNN分类器"""
def predict(self, X_predict):
"""给定待预测数据集X_predict,返回表示X_predict的结果向量"""
def _predict(self, x):
"""给定单个待预测数据x,返回x的预测结果值"""
求距离
距离排序
def train_test_split(X,y,test_ratio=0.2,seed=None):
"""将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test"""
采用切片方式
①KNN.py文件
import numpy as np
from math import sqrt
from collections import Counter
class KNNClassifier:
def __init__(self, k):
"""初始化kNN分类器"""
assert k >= 1, "k must be valid"
self.k = k
self._X_train = None
self._y_train = None
def fit(self, X_train, y_train):
"""根据训练数据集X_train和y_train训练kNN分类器"""
assert X_train.shape[0] == y_train.shape[0], \
"the size of X_train must be equal to the size of y_train"
assert self.k <= X_train.shape[0], \
"the size of X_train must be at least k."
self._X_train = X_train
self._y_train = y_train
return self
def predict(self, X_predict):
"""给定待预测数据集X_predict,返回表示X_predict的结果向量"""
assert self._X_train is not None and self._y_train is not None, \
"must fit before predict!"
assert X_predict.shape[1] == self._X_train.shape[1], \
"the feature number of X_predict must be equal to X_train"
y_predict = [self._predict(x) for x in X_predict]
return np.array(y_predict)
def _predict(self, x):
"""给定单个待预测数据x,返回x的预测结果值"""
assert x.shape[0] == self._X_train.shape[1], \
"the feature number of x must be equal to X_train"
distances = [sqrt(np.sum((x_train - x) ** 2))
for x_train in self._X_train]
nearest = np.argsort(distances) #升序排列 argsort()这个函数的作用很简单,
# 就是把向量中每个元素进行排序,
# 而它的结果是元素的索引形成的向量例子如下:
#distance------([1,4,3])
#经过distance.argsort()之后的结果是([0,2,1]
topK_y = [self._y_train[i] for i in nearest[:self.k]]
votes = Counter(topK_y)
return votes.most_common(1)[0][0]
def __repr__(self):
return "KNN(k=%d)" % self.k
②model_selection.py文件
import numpy as np
def train_test_split(X,y,test_ratio=0.2,seed=None):
"""将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test"""
assert X.shape[0]==y.shape[0], \
"the size of X must be equal to the size of y"
assert 0.0<=test_ratio<=1.0, \
"test_ration must be valid"
if seed:
np.random.seed(seed)
shuffle_indexes = np.random.permutation(len(X))
test_size = int(len(X)*test_ratio)
test_indexes = shuffle_indexes[:test_size]
train_indexes = shuffle_indexes[test_size:]
X_train = X[train_indexes]
y_train = y[train_indexes]
X_test = X[test_indexes]
y_test = y[test_indexes]
return X_train,X_test,y_train,y_test
test.py文件
from sklearn.model_selection import train_test_split
import pandas as pd
'''载入鸢尾花数据集'''
'''①导入包'''
#from sklearn import datasets
# iris=datasets.load_iris()
# X=iris.data
# y=iris.target
'''②导入文件'''
iris = pd.read_csv('iris.data', header=None)
X = iris.iloc[0:150, 0:4].values
y = iris.iloc[0:150, 4].values
X_train, X_test, y_train, y_test = train_test_split(X,y)
from KNN import KNNClassifier
my_knn_clf=KNNClassifier(k=3)
my_knn_clf.fit(X_train,y_train)
y_predict=my_knn_clf.predict(X_test)
print(sum(y_predict==y_test))
"""预测准确率"""
print(sum(y_predict==y_test)/len(y_test))
测试用例:
test.py文件
from sklearn.model_selection import train_test_split
import pandas as pd
'''载入鸢尾花数据集'''
'''①导入包'''
#from sklearn import datasets
# iris=datasets.load_iris()
# X=iris.data
# y=iris.target
'''②导入文件'''
iris = pd.read_csv('iris.data', header=None)
X = iris.iloc[0:150, 0:4].values
y = iris.iloc[0:150, 4].values
X_train, X_test, y_train, y_test = train_test_split(X,y)
from KNN import KNNClassifier
my_knn_clf=KNNClassifier(k=3)
my_knn_clf.fit(X_train,y_train)
y_predict=my_knn_clf.predict(X_test)
print(sum(y_predict==y_test))
"""预测准确率"""
print(sum(y_predict==y_test)/len(y_test))
调试:
运行结果:
在这次用Python实现Knn算法的过程中,还挺波折的,由于对python的掌握还不是很熟练,知道KNN的思路,但不知道怎么开始,就在网上搜了相关代码,学习了一下代码中所使用的python有关方法,刚开始只实现了距离计算和排序等功能,将所有测试集当做训练集,然后发现还需要将训练集和测试集分割的功能,在其中使用了python中的切片方法和随机种子,还有预测模型准确率的功能,最后在测试用例中,刚开始导入数据是使用的是导入包方式,最后采用了把鸢尾花数据集下载下来,刚开始导入数据一直出错,然后使用了pandas的方法读入。在这个过程中,虽然刚开始啥都不知道的过程很痛苦,但是问题一个一个解决时,就收获很多。