机器学习_K近邻
分类算法-knn
K近邻(k-nearest neighbour, KNN)
概念
- K近邻(k-nearest neighbour, KNN)是一种基本分类方法,通过测量不同特征之间的距离进行分类,它的思路是:如果一个样本在特征空间中的K个最相似的样本中大多数属于某一个类别,则该样本也属于这个类别,其中K通常是不大于20的整数
- KNN算法中,所选择的邻居都是已经正确分类的对象
也可以根据距离的远近给定权重
如果是二分类的话 一般是K的选择是个奇数(少数服从多数
示例
-
图中 蓝色正方形和红色三角形分别属于两个类别,此时有一个绿色圆,那么这个 圆属于哪个类别呢
-
如果k=3,会选择最近的2个红色三角形和1个蓝色正方形,红色>蓝色,此时绿圆属于红色的类别
-
如果k=5, 会选择虚线圆中的3个蓝色正方形和2个红色三角形,蓝色>红色,此时绿圆属于蓝色的类别
所以,KNN的算法结果很大程度上取决于K的选择
KNN距离计算
KNN中,通过计算对象间距离来作为各个对象之间的非相似性指标,避免了对象之间的匹配问题,在这里距离一般使用欧氏距离或曼哈顿距离,常用的是欧式距离
公式中的x,y都是向量
$$
欧式距离:\quad d(x,y) = \sqrt{ \sum_{k=1}^{n} (x_k - y_k)^2}
$$
$$
曼哈顿距离:\quad d(x,y) = \sqrt{ \sum_{k=1}^{n} |x_k - y_k|}
$$
KNN算法过程
- 在训练集中的数据和标签都已知的情况下,输入测试数据,将测试数据的特征与训练集中对应的特征进行互相比较,找到训练集中与之最为相似的前K个数据,则该测试数据对应的类别是K个数据中出现次数最多的那个分类,其算法的描述为:
- 计算测试数据与各个训练数据之间的距离
- 按照距离的递增关系进行排序
- 选取距离最小的k个点
- 确定前k个点所在类别的出现频率
- 返回前K个点中出现频率最高的类别作为测试数据的预测分类
训练数据已经知道标签了
代码
import numpy as np
import pandas as pd
# 这里直接引入sklearn里的数据集,iris鸢尾花
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split # 切分数据集为训练集和测试集
from sklearn.metrics import accuracy_score # 计算分类预测的准确率
iris = load_iris()
# print(iris)
'''
irsis是一个字典数据,主要有4个key值,分别为
'data': array([[5.1, 3.5, 1.4, 0.2],.... [4.9, 3. , 1.4, 0.2],
'target': array([0, 0, 0, 0, 0, 0, ..1,1,1.......22222)]
'target_names': array(['setosa', 'versicolor', 'virginica'],
'feature_names': ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'],
data中是个二维数组,每个数据代表的是一个样本点,每个样本点有4个特征,也就是有4个x
target是就结果,就是 y
target_names 是每个target是什么品种
feature_names 每个特征具体代表什么
'''
"""
1 指定对应的数据和列名
2.增加一列结果集
3.最后根据结果集的0,1,2替换掉对应的target_name
"""
df = pd.DataFrame(data = iris.data, columns = iris.feature_names)
df['class'] = iris.target
df['class'] = df['class'].map({0: iris.target_names[0], 1: iris.target_names[1], 2: iris.target_names[2]})
# print(df.head(10))
# print(df.describe())
x = iris.data
# 一维数组转二维
y = iris.target.reshape(-1,1)
# print(x.shape, y.shape)
# (150, 4) (150, 1)
# 划分数据集 0.3 表示测试集 占30% 训练集占70%
# random_states随机数种子(指定之后每一次调用方法返回的结果都是一样的,保证测试的时候训练集和测试集是一样的)
# stratify=y 对y保持等比例的分成 (避免不能出现过多的其中一种y,因为数据量少才这么操作而已)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=35, stratify=y)
# print(x_train.shape, y_train.shape)
# print(x_test.shape, y_test.shape)
# (105, 4) (105, 1)s
# (45, 4) (45, 1)
# 定义距离函数
# 曼哈顿距离
# 这里面的 axis=1是对1轴进行sum
def l1_distance(a,b) :
return np.sum(np.abs(a-b), axis=1)
# 欧式距离
def l2_distance(a,b) :
return np.sqrt(np.sum((a-b) ** 2 , axis=1))
# 分类器实现
class kNN(object):
# 定义一个初始化方法,__init__ 是类的构造方法
# n_neighbors 是K值,默认为1
def __init__(self, n_neighbors=1, dist_func=l1_distance):
self.n_neighbors = n_neighbors
self.dist_func = dist_func
# 训练模型方法
def fit(self, x, y):
self.x_train = x
self.y_train = y
# 模型预测方法
def predict(self, x):
# 初始化预测分类数组
y_pred = np.zeros((x.shape[0], 1), dtype=self.y_train.dtype)
# 遍历输入的x数据点,取出每一个数据点的序号i和数据x_test
for i, x_test in enumerate(x):
# x_test跟所有训练数据计算距离
distances = self.dist_func(self.x_train, x_test)
# 得到的距离按照由近到远排序,取出索引值
nn_index = np.argsort(distances)
# 选取最近的k个点,保存它们对应的分类类别
nn_y = self.y_train[nn_index[:self.n_neighbors]].ravel()
# 统计类别中出现频率最高的那个,赋给y_pred[i]
y_pred[i] = np.argmax(np.bincount(nn_y))
# fou循环逐步解释
'''
dist_func 方法是测试点跟所有样本(向量)求一个距离,返回一个距离矩阵
例 distances = [ 3.87298335 22.22611077 11.40175425 26.17250466 3. 12.24744871 221.39783197 71.92357055 54.3783045 ]
np.argsort(distances) 是按照距离从小到大排列,但是返回的是 该距离的下标
例 nn_index =[4 0 2 5 1 3 8 7 6]
3是最小的,下标是4 3.8是第二小的 下标是0
self.y_train[nn_index[:self.n_neighbors]].ravel()
y_train =[[1],[2],[2],[3].[1]]
nn_index[:k]是指取出前K个值,K=3 即[4,0,,2]
y_train[[4,0,2]] 是指把下标为4,0,2的训练数据的y点拿出来
ravel是展开的意思
最终 nn_y=[1,1,2]
np.argmax(np.bincount(nn_y))
np.bincount(nn_y) 是统计出现的次数
输出是[0,2,1] 0是指0出现了0次 2是指1出现了2次 1是指2出现了1次
np.argmax取出最大的值 2 的下标 1
y_pred[i] = 1
'''
return y_pred
# 定义一个knn实例
knn = kNN(n_neighbors = 3)
# 训练模型 (训练集做训练)
knn.fit(x_train, y_train)
# 传入测试数据,做预测(测试集做测试)
y_pred = knn.predict(x_test)
print(y_test.ravel())
print(y_pred.ravel())
# 求出预测准确率
accuracy = accuracy_score(y_test, y_pred)
print("预测准确率: ", accuracy)
print("求不同取值k的结果")
# 定义一个knn实例
knn = kNN()
# 训练模型
knn.fit(x_train, y_train)
# 保存结果list
result_list = []
# 针对不同的参数选取,做预测
for p in [1, 2]:
knn.dist_func = l1_distance if p == 1 else l2_distance
# 考虑不同的k取值,步长为2
for k in range(1, 10, 2):
knn.n_neighbors = k
# 传入测试数据,做预测
y_pred = knn.predict(x_test)
# 求出预测准确率
accuracy = accuracy_score(y_test, y_pred)
result_list.append([k, 'l1_distance' if p == 1 else 'l2_distance', accuracy])
df = pd.DataFrame(result_list, columns=['k', '距离函数', '预测准确率'])
print(df)
结果
预测准确率: 0.9333333333333333
求不同取值k的结果
k 距离函数 预测准确率
0 1 l1_distance 0.933333
1 3 l1_distance 0.933333
2 5 l1_distance 0.977778
3 7 l1_distance 0.955556
4 9 l1_distance 0.955556
5 1 l2_distance 0.933333
6 3 l2_distance 0.933333
7 5 l2_distance 0.977778
8 7 l2_distance 0.977778
9 9 l2_distance 0.977778
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!