分类:机器学习、Python、分类算法
一:KNN算法原理及常见问题
1. KNN算法的背景和应用场景
KNN(K-Nearest Neighbors)算法是一种常用的监督学习算法,属于分类算法。它的基本思想是通过测量样本之间的距离来判断它们的相似性,然后选择与新样本最相似的 K 个样本作为邻居,根据这些邻居的类别来确定新样本的类别。
KNN 算法在图像识别、文本分类、推荐系统等领域都有广泛的应用。例如,在图像识别中,可以使用 KNN 算法对图像进行分类;在推荐系统中,可以使用 KNN 算法对用户进行相似性度量,从而推荐相似用户喜欢的物品。
2. KNN 算法的主要优点
- 简单易懂:KNN 算法的思想非常简单,容易理解和实现。
- 无需训练:KNN 算法是一种基于实例的学习方法,不需要对数据进行训练。
- 对数据分布没有假设:KNN 算法对数据的分布没有任何假设,因此可以处理各种类型的数据。
- 适用于非线性问题:KNN 算法可以处理非线性问题,因为它不依赖于数据的线性可分性。
3. KNN 算法的主要缺点
- 计算量大:在处理大规模数据时,计算所有样本与新样本的距离可能会非常耗时。
- 需要存储所有训练数据:KNN 算法需要存储所有的训练数据,以便在进行预测时可以计算距离。
- 对噪声敏感:KNN 算法对噪声非常敏感,因为噪声样本可能会影响邻居的选择。
- 选择合适的 K 值:选择合适的 K 值对于 KNN 算法的性能非常重要,但选择合适的 K 值并不容易。
4.如何选择K值
K值是KNN算法中重要的超参数,会影响算法的性能。以下是一些选择 K 值的常用方法:
- 手动选择:根据经验或试验来选择 K 值。
- 交叉验证:使用交叉验证来选择最佳的 K 值。
- 肘部法则:通过绘制不同 K 值下的错误率曲线,选择错误率开始下降的点作为最佳的 K 值。
5.常用的距离度量
- 欧几里得距离(Euclidean distance):是最常用的距离度量之一,它度量两个样本在空间中的距离。
d ( x , y ) = ( x 1 − y 1 ) 2 + ( x 2 − y 2 ) 2 d(x,y)=\sqrt{(x_1-y_1)^2+(x_2-y_2)^2} d(x,y)=(x1−y1)2+(x2−y2)2 - 曼哈顿距离(Manhattan distance):是另一种常见的距离度量,它度量两个样本在空间中的曼哈顿距离。
d ( x , y ) = ∣ x 1 − y 1 ∣ + ∣ x 2 − y 2 ∣ d(x,y)=|x_1-y_1| + |x_2-y_2| d(x,y)=∣x1−y1∣+∣x2−y2∣
二:Python 实现 KNN 算法进行鸢尾花分类(sklearn)
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 加载数据
X, y = load_iris(return_X_y=True)
# 切分数据
X_train,X_test,y_train,y_test = train_test_split(X, y, test_size=0.2, random_state=0)
# 构建模型
my_knn = KNeighborsClassifier(n_neighbors=5)
# 训练模型
my_knn.fit(X_train,y_train)
# 预测模型
y_pred = my_knn.predict(X_test)
acc = (y_pred == y_test).mean() * 100
print(f"准确率为:{acc:.2f}%" )
三:Python 实现 KNN 算法(手动)
import numpy as np
from collections import Counter
class MyKNeighborsClassifier:
# 初始化函数,设置k(n_neighbors)的值为5
def __init__(self,n_neighbors=5):
self.n_neighbors = n_neighbors
def fit(self , X ,y):
# 数据类型转换
X = np.array(X)
y = np.array(y)
# 参数校验
if X.ndim != 2 or y.ndim != 1 or X.shape[0] != y.shape[0]:
raise ValueError("输入数据错误")
self.X = X
self.y = y
def pridect(self, X):
X = np.array(X)
if X.ndim != 2 or X.shape[1] != self.X.shape[1]:
raise ValueError("输入数据错误")
result = []
# 计算欧氏距离并根据距离排序,选择前k个最近的点
for x in X:
distances = np.square(((x-self.X)**2).sum(axis = 1))
index = np.argsort(distances)[:self.n_neighbors]
lables = self.y[index]
# 统计列表中索引出现的次数,取最高频率的值
aim = Counter(lables).most_common(1)[0][0]
result.append(aim)
return np.array(result)
四:小功能实现
1.train_test_split 数据切分功能(部分)手动实现
def my_train_test_split(X,y,test_size=None):
import numpy as np
y = np.array([[i] for i in y])
datas = np.concatenate((X,y),axis = 1)
np.random.shuffle(datas)
X = datas[:,0:4]
y = []
for i in datas[:,4:]:
y.append(int(i[0]))
y = np.array(y)
if test_size == None:
test_size = 0.4
else:
test_num = int(X.shape[0] * test_size)
train_num = int(X.shape[0] - test_num)
X_train = X[:train_num]
X_test = X[:test_num]
y_train = y[:train_num]
y_test = y[:test_num]
return X_train,X_test,y_train,y_test
2.Python计数器collections.Counter返回索引功能实现
def myCounter(lables):
"""
返回给定列表中出现次数最多的元素
eg:lables = [1,1,1,1,2]
return 1
"""
count_dict = {}
for element in lables:
if element in count_dict:
count_dict[element] += 1
else:
count_dict[element] = 1
max_count = max(count_dict.values())
for key,value in count_dict.items():
if value == max_count:
return key