前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ML算法——KNN随笔【全国科技工作者日创作】【机器学习】

ML算法——KNN随笔【全国科技工作者日创作】【机器学习】

作者头像
来杯Sherry
发布2023-05-31 10:57:33
3910
发布2023-05-31 10:57:33
举报
文章被收录于专栏:第一专栏第一专栏
9、K-Nearest Neighbors (KNN)
9.1、理论部分

K最邻近算法

未知点的判断基于已知点的距离,选出最近的K个点,投票选出未知点的最大可能。

计算两个物体之间的距离/相似度?

欧氏距离

\sqrt{\sum_{i=1}^{n}(x_i^{} - x_i^{})^2}

其中,xi和xj是空间中的两个点,i和j表示维度。

点数K选取奇数的目的?

偶数更容易出现“平票”,奇数也不可避免地会出现平票(1:1:1)

使用 sklearn 实现,详见9.3。

选择合适的 k 对决策边界的影响?

决策边界:决定线性分类器、非线性分类器。

在这里插入图片描述
在这里插入图片描述

图中:

  • 线性
  • 非线性
  • 非线性【最陡峭】,过拟合。

KNN的决策边界举例:

在这里插入图片描述
在这里插入图片描述

边界越陡峭,越不稳定,希望得到平滑的边界,理论上,K↑,边界越平滑。

如何选择 K 值?

交叉验证:训练集进一步划分为训练集【train】+验证集【validation】

以常用的五折交叉验证为例,

在这里插入图片描述
在这里插入图片描述
  • 对 K= 1执行五次循环,取平均,作为 k= 1的成绩。
  • 换 K ,重复。
  • 千万不能用测试数据【X_test、y_test】来调参

在数据少时,可适当增加折数的合理性?

交叉验证可以通过增加折数来减少主观因素的影响,使得结果更加准确。

主观因素:主要指在进行数据分割的时候,因为某些人为因素导致分割不准确,进而对结果产生影响。比如,如果使用随机拆分数据的方式进行验证,因为随机拆分数据的时候存在不随机的情况,所以就会对验证效果产生影响。

KNN的优化方向

  • 时间复杂度 O(N),适合低维空间内使用,优化方向:KD-tree 在二维空间的优化、LSH(Locality Sensitivity Hashing)不再寻求完全准确的解,加快搜索。
  • 特征间的相关性处理,Mahalanobis Distance
9.2、实现
9.2.1、KNN 手写实现
代码语言:javascript
复制
from sklearn import datasets
from collections import Counter # 投票
from sklearn.model_selection import train_test_split
import numpy as np

def euc_dis(instance1, instance2):
    """
    计算欧氏距离
    :param instance1:样本1,array数组
    :param instance2: 样本2,array数组
    :return: 欧氏距离
    """
    d = np.sqrt(sum(instance1-instance2)**2)
    return d

def knn_classify(X , y, testInstance, k):
    """
    给未知点归类
    :param X: train——feature
    :param y: train——label
    :param testInstance:测试数据,array数组
    :param k:选择多少个 neighbors
    :return:最多元素
    """
    distances = [euc_dis(x, testInstance)for x in X]
    kneighbors = np.argsort(distances)[:k] #快排后,取前 k 个  || 优化?改用优先队列,维护前 k 个, O(NlogN)
    count = Counter(y[kneighbors]) # Counter([0,0,0,1,1,1,1,1,1])  -》 Counter({1: 6, 0: 3})
    return count.most_common()[0][0]   # [(1, 6), (0, 3)]  -》 1

#导入 iris 数据
iris = datasets.load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=50)

#预测结果
predictions = [knn_classify(X_train, y_train, data, 3) for data in X_test]
correct = np.count_nonzero((predictions == y_test) == True)
# acc
print("Accuaracy is :%.3f" %(correct/len(X_test)))
9.2.2、KNN sklearn 实现

鸢尾花【三分类问题

代码语言:javascript
复制
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

读取数据 X,y

代码语言:javascript
复制
data = datasets.load_iris()
X = data.data   #N*D:sample * Dimension
y = data.target #label:(0,1,2)

分为训练数据 & 测试数据 (默认比例: 3/4 : 1/4)

代码语言:javascript
复制
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=500)

构建KNN模型,K=3 & 训练

代码语言:javascript
复制
clf = KNeighborsClassifier(n_neighbors=3)
clf.fit(X_train, y_train)

计算准确率(二选一)

方法一

代码语言:javascript
复制
from sklearn.metrics import accuracy_score

acc  = accuracy_score(y_test,clf.predict(X_test))
print(acc)

方法二

代码语言:javascript
复制
import  numpy as np

correct = np.count_nonzero((clf.predict(X_test) == y_test) == True)
print(f'acc is {correct/len(X_test)}')

完整代码

代码语言:javascript
复制
#
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
#
data = datasets.load_iris()
X = data.data   #N*D:sample * Dimension
y = data.target #label:(0,1,2)
#
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=500)
#
clf = KNeighborsClassifier(n_neighbors=3)
clf.fit(X_train, y_train)
#
from sklearn.metrics import accuracy_score

acc  = accuracy_score(y_test,clf.predict(X_test))
print(acc)

KNN没有训练痕迹,那么 clf.fit() 在做什么?

它是机器学习中唯一一个不需要训练过程的算法,它在训练阶段只是把数据保存下来,训练时间开销为 0,等收到测试样本后进行处理。

knn 算法手写实现的意义?较 sklearn 实现的 knn 优势在哪里?

  1. 简单易理解:KNN算法非常简单,易于理解。通过自己实现该算法,可以更深入地了解KNN算法的工作原理。
  2. 可扩展性:自己实现KNN算法可以让你更好地了解如何扩展算法以适应不同的数据集和场景。例如,你可以尝试使用不同的距离度量(如曼哈顿距离或切比雪夫距离),或者调整K值以获得更好的性能。
  3. 性能优化:在大数据集上,KNN算法的计算复杂度较高。通过自己实现该算法,你可以对算法进行优化,例如使用KD树来加速搜索邻居。
  4. 无依赖:自己实现KNN算法可以让你更好地了解算法的内部工作原理,无需依赖外部库。

想更深入地了解KNN算法的工作原理,或者需要对算法进行定制和优化,自己实现KNN算法是有意义的。只是想快速应用到项目上,那么使用sklearn是更好的选择。

9.3、案例

二手车预测案例【回归问题】

代码语言:javascript
复制
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
#读取数据
df = pd.read_csv('data.csv')

#清洗数据
# 把颜色独热编码
df_colors = df['Color'].str.get_dummies().add_prefix('Color: ')
# 把类型独热编码
df_type = df['Type'].apply(str).str.get_dummies().add_prefix('Type: ')
# 添加独热编码数据列
df = pd.concat([df, df_colors, df_type], axis=1)
# 去除独热编码对应的原始列
df = df.drop(['Brand', 'Type', 'Color'], axis=1)
# 数据转换
matrix = df.corr()
f, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(matrix, square=True)
plt.title('Car Price Variables')

from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.preprocessing import StandardScaler
import numpy as np

X = df[['Construction Year', 'Days Until MOT', 'Odometer']]
y = df['Ask Price'].values.reshape(-1, 1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=41)

X_normalizer = StandardScaler() # N(0,1) 
X_train = X_normalizer.fit_transform(X_train)
X_test = X_normalizer.transform(X_test)

y_normalizer = StandardScaler()
y_train = y_normalizer.fit_transform(y_train)
y_test = y_normalizer.transform(y_test)

knn = KNeighborsRegressor(n_neighbors=2)
knn.fit(X_train, y_train.ravel())

#Now we can predict prices:
y_pred = knn.predict(X_test)
y_pred_inv = y_normalizer.inverse_transform(y_pred)
y_test_inv = y_normalizer.inverse_transform(y_test)

# Build a plot
plt.scatter(y_pred_inv, y_test_inv)
plt.xlabel('Prediction')
plt.ylabel('Real value')

# Now add the perfect prediction line
diagonal = np.linspace(500, 1500, 100)
plt.plot(diagonal, diagonal, '-r')
plt.xlabel('Predicted ask price')
plt.ylabel('Ask price')
plt.show()

print(y_pred_inv)
  • StandardScaler(),特征缩放函数
  • fit_transform(),根据给定数据集的特点来调整模型的参数,同时可以对数据进行转换
  • inverse_transform(),在scikit-learn中,转换回原始数据并不是通过计算数据中的协方差矩阵和特征向量来实现的

KNN如何解决回归问题的?

KNN用于回归问题时,模型从训练数据集中选择离该数据点最近的k个数据点,并且把这些数据的y值取均值,把求出的这个均值作为新数据点的预测值。【对应:分类中投票高者做结果】

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-05-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 9、K-Nearest Neighbors (KNN)
    • 9.1、理论部分
      • 9.2、实现
        • 9.2.1、KNN 手写实现
        • 9.2.2、KNN sklearn 实现
      • 9.3、案例
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档