1.什么是knn算法?
K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:在特征空间中,如果一个样本附近的k个最近(即特征空间中最邻近)样本的大多数属于某一个类别,则该样本也属于这个类别。
KNN算法是一种基于实例的学习算法,其基本思想是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。其中k通常是不大于20的整数。
KNN算法的工作流程如下:
1. 收集数据:收集训练样本集和测试样本集。训练样本集包含数据特征和类别标签。
2. 计算距离:使用欧式距离公式等方法,计算测试样本与每个训练样本的距离。
3. 选取最近的k个样本:按照距离的递增顺序排序,选择与测试样本最邻近的k个训练样本。
4. 统计类别:在选取的k个最近样本中,哪一类样本占多数,测试样本就属于该类别。
5. 返回类别:最后返回测试样本所属的类别。
2.算法公式
特征空间中两个实例点之间的距离是二者相似程度的反应,所以K近邻算法中一个重要的问题是计算样本之间的距离,以确定训练样本中哪些样本与测试样本更加接近。
在实际应用中,我们往往需要根据应用的场景和数据本身的特点来选择距离计算方法。当已有的距离方法不能满足实际应用需求时,还需要针对性地提出适合具体问题的距离度量方法。
当 p = 2 p = 2p=2,为欧氏距离(Euclidean Distance)
当 p = 1 p = 1p=1,为曼哈顿距离(Manhattan Distance)
当 p = ∞ p = ∞p=∞,为各个坐标距离的最大值
3.算法实例
这里我们使用sklearn.datasets.load_breast_cancer()加载内置的乳腺癌数据集。代码实现步骤如下
1. 加载乳腺癌数据集使用sklearn.datasets.load_breast_cancer()加载内置的乳腺癌数据集。
2. 划分训练集和测试集使用sklearn.model_selection.train_test_split将数据集划分为训练集和测试集,测试集大小为原始数据集的20%。
3. 自定义KNeighborsClassifier自定义了一个CustomKNeighborsClassifier,继承自原始的KNeighborsClassifier,添加了自定义的predict_proba方法。
4. 构建模型实例化自定义的CustomKNeighborsClassifier为knn。
5. 训练模型调用knn的fit方法,使用训练集数据X_train、y_train训练模型。
6. 评估模型- 首先尝试调用score方法计算训练集的评分,因为自定义的predict_proba方法可能会抛出AttributeError异常。- 然后计算测试集的评分。
7. 预测使用训练好的模型knn对测试集X_test进行预测,得到预测结果y_pred。
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
# 自定义 KNeighborsClassifier
class CustomKNeighborsClassifier(KNeighborsClassifier):
def predict_proba(self, X):
try:
return super().predict_proba(X)
except AttributeError:
return np.zeros((len(X), len(self.classes_)))
# 加载数据集
breast_cancer = load_breast_cancer()
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(breast_cancer.data, breast_cancer.target, test_size=0.2, random_state=42)
# 构建模型
knn = CustomKNeighborsClassifier()
# 训练模型
knn.fit(X_train, y_train)
# 评估模型
try:
print("训练集评分:", knn.score(X_train, y_train))
except AttributeError:
print("训练集评分:发生异常")
print("测试集评分:", knn.score(X_test, y_test))
# 预测
y_pred = knn.predict(X_test)
运行结果
4.遇到的错误及解决方法
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Untitled-1.ipynb Cell 1 line 1
15 knn.fit(X_train, y_train)
17 #评估模型
---> 18 print("训练集评分:", knn.score(X_train, y_train))
19 print("测试集评分:", knn.score(X_test, y_test))
21 #做预测File d:\1\conda\Lib\site-packages\sklearn\base.py:705, in ClassifierMixin.score(self, X, y, sample_weight)
680 """
681 Return the mean accuracy on the given test data and labels.
682
(...)
701 Mean accuracy of ``self.predict(X)`` w.r.t. `y`.
702 """
703 from .metrics import accuracy_score
--> 705 return accuracy_score(y, self.predict(X), sample_weight=sample_weight)File d:\1\conda\Lib\site-packages\sklearn\neighbors\_classification.py:249, in KNeighborsClassifier.predict(self, X)
245 if self.weights == "uniform":
246 if self._fit_method == "brute" and ArgKminClassMode.is_usable_for(
247 X, self._fit_X, self.metric
248 ):
--> 249 probabilities = self.predict_proba(X)
...
--> 646 config = get_config().split()
647 if config[0] == b"OpenBLAS":
648 return config[1].decode("utf-8")AttributeError: 'NoneType' object has no attribute 'split'
解决方法:
根据错误日志看,这里在调用 KNeighborsClassifier 的 score 方法时,内部调用了 predict 方法,而在 predict 内部又调用了 predict_proba 方法,在 predict_proba 中调用 threadpoolctl 的 get_config 时出现了与之前一样的 AttributeError 异常。这个可以通过同样的方式来处理:1. 自定义类继承 KNeighborsClassifier,重写 predict_proba 方法
python class CustomKNeighborsClassifier(KNeighborsClassifier): def predict_proba(self, X): try: return super().predict_proba(X) except AttributeError: # 返回默认值 return np.zeros((len(X), len(self.classes_)))
2. 使用自定义的类来构建模型
python knn = CustomKNeighborsClassifier()
这种方式可以避免从 predict 一直抛出到 score 方法的异常。另外,也可以不用重写 predict_proba,直接 try-except 在 score 方法中:
python # 评估模型 try: print("训练集评分:", knn.score(X_train, y_train)) except AttributeError: print("训练集评分: 发生异常") print("测试集评分:", knn.score(X_test, y_test))
适当处理异常可以使程序继续运行下去,而不是被一个异常直接终止
5.小结
KNN算法是一种简单而有效的算法,可以用于各种分类和回归问题。它的核心思想是找到距离测试数据最近的k个训练数据点,然后使用它们的标签或真实值来预测未知的标签或值。在KNN算法中,我们使用欧几里德距离来衡量数据点之间的距离。在处理大型数据集时,KNN分类和回归问题的计算复杂度比较高,因为需要计算测试数据与每个训练数据点的距离。但是,KNN算法的简单性和可解释性,以及良好的准确性,在实际应用中,使其成为一个重要的算法。