算法简介
理解KNN算法思想(近朱者赤,近墨者黑)
如果一个样本在特征空间中的k个最相似样本种的大多数属于某一个类别,那么该样本也属于这个类别
样本之间的相似性:样本都属于一个任务数据集,样本距离越近越类似
K值选择:(模型的简单还是复杂是相对的)
如果K值过大,会导致欠拟合(用较大邻域中的训练实例进行预测)
K值增大意味着整体模型变得简单,欠拟合
受到样本均衡的问题(极端案例K=N,N为所有样本,此时无论输入实例什么,只会按训练集中最多的类别进行预测)
如果K值过小,会导致过拟合(用较小邻域中的训练实例进行预测)
容易受到异常点的影响(数据量过小,可能会碰上异常值,从此来看异常值的影响变大)
K值的减小就意味着整体模型变得复杂(过度分析特征),容易发生过拟合
KNN算法思路分析:分类(标签不连续),回归(标签连续)
知道KNN分类流程:投票
进行多数表决,统计K个样本哪个类别的样本数最多,将未知的样本归属到出现次数最多的类别
知道KNN回归流程:均值
把K个样本的目标值计算其平均值,计算均值,就说明需要数值而非其他
API介绍
掌握KNN分类API
python
"""
KNN
原理:基于欧式距离计算测试集和每个训练集之间的距离,然后根据距离升序排列,找到最近的K个样本
基于K个样本投票,票数多的就作为最终预测结果-------->分类问题
基于K个样本计算平均值,作为最终预测结果----------->回归问题
K值的选择:K值过小,容易受噪声数据的影响,
K值过大,可能会把一些离群点考虑进来,导致预测结果不准确。
一般来说,K值的选择需要根据具体的数据集和问题进行调整,可以通过交叉验证等方法来选择最优的K值。
实现思路:
1,分类问题
适用于有特征有标签,且标签不连续
2,回归问题
适用于有特征有标签,且标签连续
KNN算法分类问题思路如下:
1,计算测试集与每个训练样本之间的距离
2,基于距离进行升序排序
3,找到最近的K个样本
4,K个样本进行投票
5,票数多的结果,作为最终的预测结果
代码实现思路:
1,导包
2,准备数据集
3,创建模型对象
4,模型训练
5,模型预测
"""
# 1,导包
from sklearn.neighbors import KNeighborsClassifier
# 2,准备数据集
x_train = [[0],[1],[2],[3]] # 特征可以有多个特征,所以是一个二维数组
y_train = [0,0,1,1] # 标签数据,因为标签是离散的,所以是一个一维数组
x_test = [[5]] # 测试集的特征数据,格式与训练集特征保持一致
# 3,创建模型对象
estimator = KNeighborsClassifier(n_neighbors=2)
# 4,模型训练
estimator.fit(x_train, y_train)
# 5,模型预测
y_pre = estimator.predict(x_test)
print(y_pre)
掌握KNN回归API
python
"""
KNN
原理:基于欧式距离计算测试集和每个训练集之间的距离,然后根据距离升序排列,找到最近的K个样本
基于K个样本投票,票数多的就作为最终预测结果-------->分类问题
基于K个样本计算平均值,作为最终预测结果----------->回归问题
K值的选择:K值过小,容易受噪声数据的影响,
K值过大,可能会把一些离群点考虑进来,导致预测结果不准确。
一般来说,K值的选择需要根据具体的数据集和问题进行调整,可以通过交叉验证等方法来选择最优的K值。
实现思路:
1,分类问题
适用于有特征有标签,且标签不连续
2,回归问题
适用于有特征有标签,且标签连续
KNN算法分类问题思路如下:
1,计算测试集与每个训练样本之间的距离
2,基于距离进行升序排序
3,找到最近的K个样本
4,K个样本标签,计算平均值
5,基于上述计算出来平均值,作为最终的预测结果
代码实现思路:
1,导包
2,准备数据集
3,创建模型对象
4,模型训练
5,模型预测
"""
# 1,导包
from sklearn.neighbors import KNeighborsRegressor
# 2,准备数据集
x_train = [[0,0,1],[1,1,0],[3,10,10],[4,11,12]] # 特征可以有多个特征,所以是一个二维数组
y_train = [0.1,0.2,0.3,0.4] # 标签数据,因为标签是离散的,所以是一个一维数组
x_test = [[3,11,10]] # 测试集的特征数据,格式与训练集特征保持一致
# 3,创建模型对象
estimator = KNeighborsRegressor(n_neighbors=3)
# 4,模型训练
estimator.fit(x_train, y_train)
# 5,模型预测
y_pre = estimator.predict(x_test)
print(y_pre)
距离度量
欧氏距离 = 对应维度差值平方和,开平方根(类似勾股定理)
欧氏距离:两点在空间中的距离
二维空间
对应维度:x和x相减,y与y相减
曼哈顿距离(特点:横平竖直)
曼哈顿距离:对应维度差值的绝对值,求和
二维空间
街区横平竖直,也就是说无法斜着行走
曼哈顿距离和欧氏距离可以互换
切比雪夫距离 *(国际象棋中的王可以向8个方向行走,那么从一个点到另一个点的最短的步数是多少 )
切比雪夫距离:对应维度差值的绝对值求最大值
注意到:走一步斜的,等同于走一步横再走一步纵,能尽量斜着行走就斜着行走
闵可夫斯基距离 *
当p=1时,为曼哈顿距离
当p=2时,为欧氏距离
当p=∞,为切比雪夫距离
特征与处理
1,知道为什么进行归一化
特征单位或大小相差较大,或者特征的方差必其他特征要大出几个数量级
2,应用归一化API处理数据(小数据集)
通过对原始数据进行变换把数据映射到min,max之间
弊端:使用归一化处理数据时,受到最大值和最小值的影响很大,如果最大值或者最小值为异常值,那么会导致非常大的误差
python
from sklearn.preprocessing import MinMaxScaler
x_train = [
[90,2,10,40],
[60,4,15,45],
[75,3,13,46]
]
# transfer = MinMaxScaler()
transfer =MinMaxScaler(feature_range=(0,1))# 在这里,feature_range表示生成范围,默认为[0,1],如果就是这个区间,参数可以缺省
x_train_new = transfer.fit_transform(x_train)
print(f"归一化后的数据集为:\n{x_train_new}")
3,应用标准化API处理数据(适用于大数据集的处理)
对原始数据标准化,转化为均值为0,标准差为1的标准正态分布的数据
mean表示特征平均值,σ表示特征标准差
正态分布:均值决定位置,标准差决定陡峭还是平缓;均值为0,标准差为1的正态分布是标准正态分布
无论是归一化还是标准化,目的都是为了解决因为量纲问题,导致模型评估较低的问题
4,使用KNN算法进行鸢尾花分类
python
"""
加载数据
数据预处理
特征工程(提取,预处理
模型训练
模型评估
模型预测
"""
from sklearn.datasets import load_iris # 加载鸢尾花测试集
from sklearn.model_selection import train_test_split # 划分数据集,对原始的数据集分割为训练集和测试集
from sklearn.neighbors import KNeighborsClassifier # KNN算法,分类
from sklearn.metrics import accuracy_score # 模型评估,准确率
from sklearn.preprocessing import StandardScaler # 数据预处理,标准化
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from torch.utils.data.datapipes import dataframe
# 加载数据集,并查看训练集和测试集
def dm01_loadiris():
#加载数据集
iris_data = load_iris()# 加载数据集
#查看数据集
# print(f"数据集: {iris_data}") #字典形态
# print(f"数据集类型: {type(iris_data)}") #
# print(f'数据集中所有的键: {iris_data.keys()}') #数据集的键
# print(f"前五条数据: {iris_data.data[:5]}") #数据集的具体数据
# print(f'前五条数据花的种类: {iris_data.target_names[iris_data.target[:5]]}')
# print(f'特征对应的名称:{iris_data.feature_names}')
# print(f'框架:{iris_data.frame}')
print(f"数据data: {iris_data.data}")
print(f'数据特征名feature_names: {iris_data.feature_names}')
print(f'数据标签target: {iris_data.target}')
print(f'数据标签名target_names: {iris_data.target_names}')
pass
# 定义函数,绘制数据集的散点图
def dm02_showiris():
# 加载数据集
iris_data = load_iris()
# 将数据集封装为DataFrame对象
iris_df = pd.DataFrame(iris_data.data, columns=iris_data.feature_names)
iris_df['label'] = iris_data.target
# print(iris_df['label'].head())
# 绘制散点图,第一个参数为数据框,x轴为sepal length (cm),y轴为sepal width (cm),不同的label用不同的颜色表示,fit_reg=False表示不绘制回归线
sns.lmplot(data=iris_df, x='sepal length (cm)', y='sepal width (cm)', hue='label',fit_reg=False)
# 设置标题
plt.title('Iris Dataset')
plt.tight_layout()# 调整布局,自动调整子图参数
plt.show()
pass
# 定义函数,切分训练集和测试集
def dm03_split_train_test():
# 加载数据集
iris_data = load_iris()
# 数据预处理:从150个特征和标签中,按照8:2的比例,划分为训练集和测试集
# 参数一:数据集特征,参数二:数据集标签,参数三:测试集占比,参数四:随机数种子
# 返回值:训练集特征,测试集特征,训练集标签,测试集标签
x_train, x_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, test_size=0.2, random_state=23)
print(f"训练集特征:\n{x_train},个数{len(x_train)}\n")
print(f"训练集标签:\n{y_train},个数{len(y_train)}\n")
print(f"测试集特征:\n{x_test},个数{len(x_test)}\n")
print(f"测试集标签:\n{y_test},个数{len(y_test)}\n")
pass
# 定义函数实现案例,加载数据,数据预处理,特征工程,模型训练,模型评估,模型预测
def dm04_iris_case():
# 加载数据
iris_data = load_iris()
# 数据预处理8:2划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, test_size=0.2, random_state=23)
# 特征工程:数据标准化
# 特征提取:元数据只有4个特征,直接使用,不需要提取
# 特征预处理:元数据特征差值不大,所以无需做特征预处理
# 创建标准化对象
# fit_transform()方法:先拟合数据(计算均值和标准差),再对数据进行转换(标准化),简言之,先训练再转换,一般对训练集进行标准化
# transform()方法:直接对数据进行转换(标准化),不计算均值和标准差,适用于已经拟合过的数据,简言之,直接转换,一般对测试集进行标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train) # 标准化训练集特征
x_test = transfer.fit_transform(x_test) # 标准化测试集特征
# 模型训练
model = KNeighborsClassifier(n_neighbors=3) # 创建KNN分类器对象,参数n_neighbors表示邻居数
model.fit(x_train, y_train) # 训练模型,参数一:训练集特征,参数二:训练集标签
# 模型评估
# 模型预测
# 1,对刚才切分的测试集进行测试
# 直接预测即可,获取到预测结果
y_pre = model.predict(x_test)
# 打印预测结果
print(f"预测结果:{y_pre}")
# 2,对新的数据集进行测试,元数据150条之外的数据
# 自定义测试数据集
my_data = [
[7.8,2.1,3.9,1.6]
]
# 对数据集进行标准化处理
my_data = transfer.transform(my_data)
y_pre_new = model.predict(my_data)
print(f"预测结果:{y_pre_new}")
# 查看上述数据集,每种分类的预测概率
y_prob = model.predict_proba(my_data)
print(f"预测概率:{y_prob}")
# 模型评估
# 直接评分
print('准确率:', model.score(x_test, y_test)) # 直接评分,参数一:测试集特征,参数二:测试集标签
# 基于测试集的标签和预测结果进行评分
print(f'准确率:{accuracy_score(y_test, y_pre)}') # 基于测试集的标签和预测结果进行评分,参数一:测试集标签,参数二:预测结果
pass
if __name__ == '__main__':
dm04_iris_case()
pass
超参数选择方法
超参数:手动传入的值
1,知道什么是交叉验证(多验证几回然后取均值)
数据集的分割方法,将训练集划为n份,拿一份做测试集,其他为训练集
就比如将数据集划分为1份训练集,9份数据集,就称为10折交叉验证,分为n折就是n折交叉验证,总共训练10次,评估10次
使用训练集和测试集多次评估,取平均值做交叉验证得到的得分就是模型得分
若某次评估得分最好,再使其测试集成为测试集,而训练集变为全体数据
2,知道什么是网格搜索
网格搜索是模型调参的有力工具,寻找最优超参的工具
交叉验证解决模型输入,从而得到更可靠的模型
网格搜索解决超参数的组合