机器学习 02- KNN算法

算法简介

KNN算法思想

K-近邻算法 (K Nearest Neighbor,简称KNN)。比如:根据你的"邻居"来推断出你的类别

简单来说:预测当前数据时,在已知数据中寻找出k个与其最相似的样本,这k个样本大多数属于某个类别的话,那么该样本也属于某个类别

所以,k的取值就很有考究,这里暂时提及,到后面会详细讲解。

样本相似性 :样本都是属于一个任务数据集 的。样本距离越近则越相似。

利用K近邻算法预测电影类型

例如: 使用KNN预测电影类别

在这里我们可以使用欧氏距离来计算预测数据的"邻居"

K值的选择

前面我们提到过,我们需要找到k个与其最相似的样本,那么这个k值的选择就十分重要。

k值过小 ,这种情况就是用较小的邻域去进行预测,那么该种方法就可能使得预测值易受异常点的影响(极端思维理解:若k取1的话,如果你的参考值是一个异常值,那么你预测的值就受到了该异常值的影响)。k值的减小也意味着整体模型会变得复杂进而导致过拟合 现象的产生

k值过大,这种情况就是用较大的邻域去进行预测,那么该种方法可能会产生样本均衡的问题(极端思维理解:如果k取n,那么无论你输入什么值,那么它只会按训练集中最多的类别去进行预测)。k值的增大也意味着其整体的模型会变得简单,容易发生欠拟合的现象。

KNN算法的应用

KNN算法解决问题:分类问题、回归问题

  • 回归问题的处理流程

    1.计算未知样本到每一个训练样本的距离

    2.将训练样本根据距离大小升序排列

    3.取出距离最近的 K 个训练样本

    4.进行多数表决,统计 K 个样本中哪个类别的样本个数最多

    5.将未知的样本归属到出现次数最多的类别

  • 回归问题的处理流程

    1.计算未知样本到每一个训练样本的距离

    2.将训练样本根据距离大小升序排列

    3.取出距离最近的 K 个训练样本

    4.把这个 K 个样本的目标值计算其平均值

    5.作为将未知的样本预测的值

注:不论是分类问题还是回归问题,其前期的处理策略都是相同的。

KNN算法API介绍

分类算法API

KNN分类API:

python 复制代码
sklearn.neighbors.KNeighborsClassifier(n_neighbors=5) 
复制代码
n_neighbors:int,可选(默认= 5),k_neighbors查询默认使用的邻居数,也就是我们所谓的 k的大小。

回归算法API

KNN分类API:

python 复制代码
sklearn.neighbors.KNeighborsRegressor(n_neighbors=5)
复制代码
n_neighbors:int,可选(默认= 5),k_neighbors查询默认使用的邻居数,也就是我们所谓的 k的大小。

相关代码

python 复制代码
#导包
import sklearn.neighbors

def demo01_class():
    #实例化
    c_estimator = sklearn.neighbors.KNeighborsClassifier(n_neighbors=1)

    #设置数据
    x = [[0], [1], [2], [3]]
    y = [0, 0, 1, 1]

    #训练
    c_estimator.fit(x, y)

    print(c_estimator.predict([[5]]))

def demo02_regressor():
    #实例化
    r_estimator = sklearn.neighbors.KNeighborsRegressor(n_neighbors=2)

    #设置数据
    x = [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]
    y = [0.1, 0.2, 0.3, 0.4]

    #训练
    r_estimator.fit(x, y)
    '''
    计算过程就是找到离预测值最近的两个邻居输出其平均值
    '''

    print(r_estimator.predict([[5, 6, 7]]))



if __name__ == '__main__':
    demo01_class()
    demo02_regressor()

运行结果:

距离计算方法

在前面我们仅提及了欧式距离的计算方法,但计算距离的公式有很多,在不同的情况下则使用不同的公式,所以我们需要了解下相关的距离计算公式。

欧式距离

欧氏距离就是我们常说的空间中两点之间的距离。

曼哈顿距离

曼哈顿距离也可以称之为城市街区距离,可以理解为网格中两点之间的距离,其结果就是两个点构成的长方形的边长和。

切比雪夫距离

棋子从a点到b点最少需要多少步,旗子可以朝向相邻的八个方向任意移动。

闵氏距离

闵可夫斯基距离 Minkowski Distance 闵氏距离,不是一种新的距离的度量方式。而是距离的组合 是对多个距离度量公式的概括性的表述

特征预处理

对特征值进行预处理也就是对其进行归一化标准化

原因:特征的单位或者大小相差较大,或者某特征的方差相比其他的特征要大出几个数量级容易影响(支配)目标结果,使得一些模型(算法)无法学习到其它的特征。

归一化

通过对原始数据进行变换把数据映射到【mi,mx】(默认为0,1)之间

注:(mx-mi)是进行值大小的缩放,+mi是进行值左右的位移

数据归一化的API实现

python 复制代码
sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)... )
#feature_range 缩放区间

注:

fit():只做一件事 ------计算传入数据的均值、标准差,并把这两个统计值保存到标准化器对象里。它不修改数据,只 "学习" 数据的分布参数。

transform():用对象里已经保存好的均值、标准差,按照公式 (x - 均值) / 标准差 对数据做标准化计算。它不重新计算统计量,只做变换。

fit_transform():等价于先执行 fit() 再执行 transform(),是一步到位的简写,只应该用在训练集上。

归一化受到最大值与最小值的影响,这种方法容易受到异常数据 的影响, 鲁棒性较差 ,适合传统精确小数据场景

如果出现异常点 影响了最大值和最小值 那么结果会明显的发生改变。

标准化

通过对原始数据进行标准化,转换为均值为0标准差为1的标准正态分布 的数据

数据标准化的API实现

python 复制代码
sklearn.preprocessing. StandardScaler()

调用 fit_transform(X) 将特征进行归一化缩放

适用于现代嘈杂大数据场景。

如果出现了异常点 由于数据量较大 少量的异常点对于平均值的影响并不大。

代码:

python 复制代码
#导包
import sklearn.preprocessing



def demo01_minmax():
    # 数据
    x = [[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]]

    #实例化
    tf = sklearn.preprocessing.MinMaxScaler()

    data = tf.fit_transform(x)

    print(data)

def demo02_ss():
    # 数据
    x = [[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]]

    # 实例化
    tf = sklearn.preprocessing.StandardScaler()

    data = tf.fit_transform(x)

    print(data)


if __name__ == '__main__':

    demo01_minmax()
    demo02_ss()

执行结果:

扩展(正态分布):

案例 - 鸢尾花分类

鸢尾花Iris Dataset数据集是机器学习领域经典数据集,鸢尾花数据集包含了150条鸢尾花信息,每50条取自三个鸢尾花中之一:Versicolour、Setosa和Virginica

处理流程:

获取数据集 - 数据基本处理 - 特征值处理 - 模型训练 - 模型评估

代码实现:

python 复制代码
## KNN_鸢尾花
# 1.导入工具包
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import sklearn.model_selection
import sklearn.metrics
import sklearn.preprocessing
import sklearn.neighbors

# 2.加载数据集
# 2.1 加载数据集
iris_data = sklearn.datasets.load_iris() #这里的数据 是 sklearn 封装的 Bunch 对象
# print(iris_data)
# print(iris_data.target)
# print(iris_data.feature_names)    # ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
# print(iris_data.target_names) # ['setosa' 'versicolor' 'virginica'] 三种花的类别

# 2.2 展示数据集
iris_df = pd.DataFrame(data=iris_data.data, columns=iris_data.feature_names)
iris_df['label'] = iris_data.target #花的类别
# print(iris_df)
# print(iris_data.feature_names)
# sns.lmplot(x='sepal length (cm)',y='sepal width (cm)',data = iris_df,hue='label', fit_reg=False ) #hue 按类别进行分类, fit_reg 关闭回归线拟合
# plt.show()

# 3.特征工程(预处理-标准化)
# 3.1 数据集划分
x_train, x_test, y_train, y_test = sklearn.model_selection.train_test_split(iris_data.data, iris_data.target, test_size = 0.3, random_state = 42) #test_size = 0.3 训练集和测试集比为7:3
# print(len(iris_data.data))
# print(len(x_train))

# 3.2 标准化
process = sklearn.preprocessing.StandardScaler()
x_train = process.fit_transform(x_train) #训练集需要计算
x_test = process.transform(x_test) #测试集无需计算

# 4.模型训练
# 4.1 实例化
model = sklearn.neighbors.KNeighborsClassifier() #分类
# 4.2 调用fit法
model.fit(x_train, y_train)

# 5.模型预测
x = [[5.1, 3.5, 1.4, 0.2]]
x = process.transform(x)
print(model.predict_proba(x)) # _proba 是每个分类的概率

# 6.模型评估(准确率)
# 6.1 直接计算准确率
acc = model.score(x_test, y_test) #用测试集计算模型的分类准确率
print(acc)

# 6.2 使用预测结果
y_predict = model.predict(x_test)
acc = sklearn.metrics.accuracy_score(y_test, y_predict)
print(acc)

运行结果:

超参数的选择

交叉验证

交叉验证是一种数据集的分割方法,将训练集划分为 n 份,其中一份做验证集、其他n-1份做训练集,其目的是为了得到更加准确可信的模型评分。

交叉验证法原理 :将数据集划分为 cv=10 份:

1.第一次:把第一份数据做验证集,其他数据做训练

2.第二次:把第二份数据做验证集,其他数据做训练

3... 以此类推,总共训练10次,评估10次。

4.使用训练集+验证集多次评估模型,取平均值做交叉验证为模型得分

5.若k=5模型得分最好,再使用全部训练集(训练集+验证集) 对k=5模型再训练一边,再使用测试集对k=5模型做评估

网格搜索

模型有很多超参数,其能力存在很大的差别,所以需要手动产生很多超参数组合来训练模型,每组超参数都采用交叉验证评估,最后选出最优参数组合建立模型。

网格搜做是模型调参的工具,我们只需要将若干参数传给网格搜索工具,它可以自动帮助我们完成不同超参数的组合、模型训练、模型评估,最终返回一组最优参数。

注:

超参数(Hyperparameter)是模型开始训练之前,由人工预先设定、用来控制模型结构 / 训练规则的参数。

它最关键的特点:不是模型通过 fit() 从数据里自动学习出来的,而是你提前定好的 "运行规则"。

目前我们正在学的 KNN 算法里,KNeighborsClassifier(n_neighbors=5) 中的 n_neighbors=5,就是最典型的超参数。

使用网格搜索+交叉验证的方法,可以形成一个模型参数调优的解决方案。

代码 鸢尾花分类(包含交叉验证流程):

python 复制代码
## 交叉验证+网格搜索
# 1.导入工具包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sklearn.metrics
import sklearn.preprocessing
import sklearn.neighbors
import sklearn.model_selection
from sklearn.metrics import accuracy_score

# 2.加载数据
data = sklearn.datasets.load_iris()

# 3.数据集划分
x_train, x_test, y_train, y_test = sklearn.model_selection.train_test_split(data.data, data.target, test_size = 0.2, random_state = 1)

# 4.特征预处理
demo = sklearn.preprocessing.StandardScaler() #标准化
x_train = demo.fit_transform(x_train)
x_test = demo.transform(x_test)

# 5.模型实例化+交叉验证+网格搜索
model = sklearn.neighbors.KNeighborsClassifier(n_neighbors=1)
para = {'n_neighbors': [1, 3, 5, 7, 9]}
# estimator = sklearn.model_selection.GridSearchCV(
#     estimator=model,   # 要调参的基础模型
#     param_grid=para,   # 超参数候选网格
#     cv=4               # 4折交叉验证 把训练集 x_train 平均分成 4 份,每次用 3 份做训练、1 份做验证,循环 4 次,取 4 次的平均得分作为这组参数的最终成绩。
# )
# estimator.fit(x_train,y_train)
#
# '''
# 这一行执行后,程序会自动完成一整套流程:
# 遍历每一组超参数(共 5 组 K 值);
# 对每组参数,都执行 4 折交叉验证,记录每一轮的验证集得分;
# 计算每组参数的平均验证得分,选出平均分最高的那一组作为最优超参数;
# 用最优超参数,在整个训练集上重新训练一个最终模型,保存在对象里。
# '''
#
# print(estimator.best_score_)
# print(estimator.best_estimator_)
# print(estimator.cv_results_)

#结果:
model = sklearn.neighbors.KNeighborsClassifier(n_neighbors=7)

# 6.模型训练
model.fit(x_train, y_train)
# x = [[5.1, 3.5, 1.4, 0.2]]
# x = demo.transform(x)

# 7.模型预测
y_predict = model.predict(x_test)

# 8.模型评估
print(sklearn.metrics.accuracy_score(y_test, y_predict))
相关推荐
fenglllle1 小时前
chromadb emmbedding 向量检索
人工智能·python·embedding
wabs6661 小时前
关于动态规划【力扣583.两个字符串的删除操作的思考】
算法·leetcode·动态规划
月光刺眼1 小时前
用LangChain 打造第一个 Agent:LLM 大脑与 Tool 手脚的完整闭环
javascript·人工智能·全栈
小林ixn1 小时前
手写AI编程Agent:从0到1复刻Trae/Cursor的核心能力
人工智能·aigc·ai编程
可编程芯片开发1 小时前
空气流量和空气压力参数解耦系统simulink建模与仿真
算法
冬哥聊AI1 小时前
腾讯三面:Claude Code 写书超过上下文长度怎么办?/compact 只是应急,五步架构才是正解
人工智能
饼干哥哥1 小时前
用Claude Code跑通跨境电商的5大场景,顶10个人的团队
人工智能·设计模式·正则表达式
ATA88881 小时前
数据库管理工具的数据安全机制对比:权限管控与审计
数据库·人工智能·数据分析·数据库管理
legendary_1631 小时前
SINK芯片:Type-C统一供电时代的小家电核心方案
c语言·开发语言·人工智能·智能手机