3 sklearn调用KNeighborsClassifier
总结
前言
读者可看此文章,为复现的knn算法
python实现KNN算法_AGuiRong的博客-CSDN博客
该文章为针对复现的knn算法进行优化。
一、KNN重要的参数
KNN(k-nearest neighbors)算法是一种基于实例的监督学习算法,其中最重要的参数包括:
-
k 值:k 值表示在预测阶段选择的最近邻居的数量。较小的 k 值会使模型更加敏感,容易受到噪声的影响,而较大的 k 值则可能忽略类别之间的细微差异。选择合适的 k 值需要根据具体问题进行调优。
-
距离度量方法:KNN 根据实例之间的距离来计算最近邻。常用的距离度量方法包括欧式距离、曼哈顿距离、闵可夫斯基距离等。不同的距离度量方法对结果可能会有影响,因此需要根据数据特点和问题选择合适的距离度量方法。
-
特征权重:在计算距离时,可以为不同的特征赋予不同的权重。这个权重可以根据特征的重要性来设定,以便更好地区分样本。
-
决策规则:当确定了最近邻的标签后,需要决定最终的预测标签。常见的决策规则包括多数表决法、加权表决法等。在多数表决法中,选择最近邻中出现次数最多的类别作为预测结果;在加权表决法中,根据最近邻的距离,对每个样本赋予不同的权重来进行表决。
除了上述参数外,还有一些其他的参数可以调整,如数据预处理方法、特征选择方法等,这些也会对 KNN 算法的性能产生影响。
需要注意的是,KNN 算法对于异常值敏感,对数据集规模和维度要求较高。因此在使用 KNN 算法时,需要根据具体情况仔细选择参数,同时进行数据预处理和特征工程,以获得更好的性能。
在本文中考虑的参数为K值和距离度量方法。
二、使用步骤
1.优化KNN算法
class KNN():
def __init__(self,k=2,ord=2):
self.k = k
self.ord = ord
def plot_ord(self,ord=-1): # 固定参数ord,KNN 模型准确率随 k 值变化的曲线
if ord==-1:
ord=self.ord
plt.plot(self.k_range, self.accuracy_scores[ord,:])
plt.xlabel('k')
plt.ylabel('准确率')
plt.title('ord={} k值变化的曲线'.format(ord))
plt.show()
def plot_k(self,k=-1): # 固定参数k,KNN 模型准确率随 ord 值变化的曲线
if k==-1:
k=self.k
plt.plot(self.ord_range, self.accuracy_scores[:,k])
plt.xlabel('ord')
plt.ylabel('准确率')
plt.title('k={} 准确率随ord 值变化的曲线'.format(k))
plt.show()
def sub_train_test(self,train_index,test_index):
sub_x_train = self.x_train[train_index,:]
sub_y_train = self.y_train[train_index,:]
sub_x_test = self.x_train[test_index,:]
sub_y_test = self.y_train[test_index,:]
return sub_x_train,sub_y_train,sub_x_test,sub_y_test
def get_Optimal_k_ord(self):
self.accuracy_scores = np.zeros((len(self.ord_range),len(self.k_range)))
skf = StratifiedKFold(n_splits=10, shuffle=True, random_state=3220822)
for i,ord in enumerate(self.ord_range):
self.ord = ord
for j,k in enumerate(self.k_range):
self.k = k
scores = []
for indexk,(train_index, test_index) in enumerate(skf.split(self.x_train, self.y_train)):
sub_x_train,sub_y_train,sub_x_test,sub_y_test = self.sub_train_test(train_index, test_index)
sub_predict = self.predict(sub_x_test,sub_x_train,sub_y_train)
accuracy = accuracy_score(sub_y_test, sub_predict)
scores.append(accuracy)
self.accuracy_scores[i][j] = np.mean(scores)
max_index = np.argmax(self.accuracy_scores)
row_index, col_index = np.unravel_index(max_index, self.accuracy_scores.shape)
self.ord = self.ord_range[row_index]
self.k = self.k_range[col_index]
def fit(self,x_train,y_train,k_range=[1,2,3, 5, 7, 9, 11],ord_range=[1,2,3,4,5,10]):
self.x_train = x_train
self.y_train = y_train
self.k_range = k_range
self.ord_range = ord_range
# 涉及到的操作都是numpy类型
if type(self.x_train) != np.ndarray:
self.x_train = np.array(self.x_train)
if type(self.y_train) != np.ndarray:
self.y_train = np.array(self.y_train)
if len(self.y_train.shape)==1: # 维度进行延伸
self.y_train = np.expand_dims(self.y_train, axis=1)
# 采用方法,确定最优k值,ord值
self.get_Optimal_k_ord()
# 计算的是data2中每一行数据与data1所有数据之间的各种距离,且用distances保存
# data2:k行m列
# data1:n行m列
# distances:k行n列
def calculate_distances(self,dataset1,dataset2,ord): # 默认使用欧式距离
distances = np.zeros((len(dataset2), len(dataset1))) # 初始化距离矩阵
for i in range(len(dataset2)):
distances[i] = np.linalg.norm(dataset1 - dataset2[i], axis=1,ord=ord)
return distances
def predict(self,x_test,x_train="",y_train=""):
# 若是仅传递预测集,则采取的训练集的私有变量self.x_train
if len(x_train) == 0:
x_train = self.x_train
if len(y_train) == 0:
y_train = self.y_train
if type(x_test) != np.ndarray:
x_test = np.array(x_test)
distances = self.calculate_distances(x_train,x_test,self.ord) # 获取距离矩阵
partitioned_indexes = np.argpartition(distances, self.k, axis=1)[:, :self.k] # 找到每行最小的前k个值的索引位置
# 即获取距离最近得前k个样本
sub_labels = y_train[partitioned_indexes, -1] # 获取选定得最近前k个样本对应的标签
modes, counts = mode(sub_labels, axis=1,keepdims=False) # 获取每行的众数以及出现次数
return modes # 即为预测数
2.数据预处理
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 加载燕尾花数据集
iris = load_iris()
# 获取特征数据和标签数据
X = iris.data
y = iris.target
# 将数据集切分为训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=3220822)
# 打印切分后的数据集大小
print("训练集大小:", x_train.shape[0])
print("测试集大小:", x_test.shape[0])
3 sklearn调用KNeighborsClassifier
from sklearn.neighbors import KNeighborsClassifier
# 创建 KNN 模型对象
knn = KNeighborsClassifier(n_neighbors=3,)
# 训练模型
knn.fit(x_train, y_train)
# 进行预测
y_pred = knn.predict(x_test)
# 评估模型
accuracy = accuracy_score(y_test, y_pred)
print("准确率:", accuracy)
可以看到结果已经是很好的了
4 调用封装好的优化knn类
MYknn = KNN()
print("默认的k值与ord值:",MYknn.k,MYknn.ord)
# 训练模型
MYknn.fit(x_train, y_train,k_range=[1,2,3,4,5,6,7,8,9,10,11],ord_range=[1,2,3,4,5,6,7,8,9,10])
print("训练后选择的k值与ord值:",MYknn.k,MYknn.ord)
# 进行预测
y_pred = MYknn.predict(x_test)
# 评估模型
accuracy = accuracy_score(y_test, y_pred)
print("准确率:", accuracy)
可以通过注释知道,在训练模型的时候,我们可以传入参数k和ord的范围。之后会基于给定的训练集进行10折运算,选取最优的k与ord值。其结果输出如下
5 进行可视化
我们可以通过封装好类中的内置函数plot_k和plot_ord进行可视化。
其中plot_k(k="默认为训练后最优k值"),表示k值固定后,可视化准确率随ord 值变化的曲线。
并且plot_k(k="可选取k_range中任意值"),进行可视化
plot_ord是一样的使用方法
总结
对KNN算法采取了10折运算原理,在给定的参数范围内选取最优参数值,并给出了可视化效果。