文章目录
一、算法概念
什么是KNN?
K-近邻 (KNN) 是一种监督算法。KNN 背后的基本思想是在训练空间中找到距离新数据点最近的 K 个数据点,然后根据 k 个最近数据点中多数类别对新数据点进行分类,类似于"物以类聚"的思想,将一个样本的类别归于它的邻近样本。K-近邻算法是一种惰性学习模型(lazy learning),也称为基于实例学习模型,这与勤奋学习模型(eager learning)不一样。
勤奋学习模型在训练模型的时候会很耗资源,它会根据训练数据生成一个模型,在预测阶段直接带入数据就可以生成预测的数据,所以在预测阶段几乎不消耗资源。
惰性学习模型在训练模型的时候不会估计由模型生成的参数,他可以即刻预测,但是会消耗较多资源,例如KNN模型,要预测一个实例,需要求出与所有实例之间的距离。
K-近邻算法是一种非参数模型,参数模型使用固定的数量的参数或者系数去定义模型,非参数模型并不意味着不需要参数,而是参数的数量不确定,它可能会随着训练实例数量的增加而增加,当数据量大的时候,看不出解释变量和响应变量之间的关系的时候,使用非参数模型就会有很大的优势,而如果数据量少,可以观察到两者之间的关系的,使用相应的模型就会有很大的优势。
存在一个样本集,也就是训练集,每一个数据都有标签,也就是我们知道样本中每个数据与所属分类的关系,输入没有标签的新数据后,新数据的每个特征会和样本集中的所有数据对应的特征进行比较,算出新数据与样本集其他数据的欧几里得距离,这里需要给出K值,这里会选择与新数据距离最近的K个数据,其中出现次数最多的分类就是新数据的分类,一般k不会大于20。
KNN在做回归和分类的主要区别,在于最后做预测时候的决策不同。在分类预测时,一般采用多数表决法。在做回归预测时,一般使用平均值法。
多数表决法:分类时,哪些样本离我的目标样本比较近,即目标样本离哪个分类的样本更接近。
平均值法: 预测一个样本的平均身高,观察目标样本周围的其他样本的平均身高,我们认为平均身高是目标样本的身高。
这里就运用了KNN的思想。KNN方法既可以做分类,也可以做回归,这点和决策树等算法相同。
由上图KNN分类算法可以发现,数据分为蓝色和绿色两个类别,当有一个新的数据点(红色)出现,并且 K = 5时,可以看到红色点有 3 个绿色近邻样本和 2个蓝色近邻样本,这说明蓝点将被归类为绿色类,因为多数投票为 3。同样,当 K 值变化时,圆内的近邻样本数量会增加,新的数据点被归类到其对应的多数投票类中。
在 KNN 回归中,因变量是连续的,分布在整个特征空间中。当有新的数据点红色点出现时,会使用某种距离度量(如欧几里得距离)找到最接近的新数据点的 K 个近邻样本。找到这些邻居后,新数据点的预测值通过计算这些邻居的因变量值的平均值来确定。
例如,假设我们想预测学生的考试成绩,而已知的特征是学习时长。我们已经有了许多学生的学习时长和对应的考试成绩数据。现在,针对一个新来的学生,我们知道他的学习时长,通过 KNN 回归,我们可以找到学习时长最接近的 K 个学生,然后将这 K 个学生的考试成绩取平均值,作为这个新学生的成绩预测。
二、算法原理
(一)K值选择
K K K值的选择与样本分布有关,一般选择一个较小的 K K K值,可以通过交叉验证来选择一个比较优的 K K K值,默认值是5。如果数据是三维以下的,如果数据是三维或者三维以下的,可以通过可视化观察来调参。
当 k = 1 k=1 k=1时的 k k k近邻算法称为最近邻算法,此时将点 X X X分配给特征空间中其最近邻的点的类。即: C n 1 n n ( X ) = Y ( 1 ) C_{n}^{1nn}(X)=Y_{(1)} Cn1nn(X)=Y(1)
K K K值的选择会对 k k k近邻法的结果产生重大影响。若 K K K值较小,则相当于用较小的邻域中的训练样本进行预测,"学习"的偏差减小。
只有与输入样本较近的训练样本才会对预测起作用,预测结果会对近邻的样本点非常敏感。
若 k k k近邻的训练样本点刚好是噪声,则预测会出错。即: 值的减小意味着模型整体变复杂,易发生过拟合。
优点 :减少"学习"的偏差。
缺点 :增大"学习"的方差(即波动较大)。
若 K K K值较大,则相当于用较大的邻域中的训练样本进行预测。
这时输入样本较远的训练样本也会对预测起作用,使预测偏离预期的结果。 K K K值增大意味着模型整体变简单。
优点 :减少"学习"的方差(即波动较小)。
缺点 :增大"学习"的偏差。
应用中, K K K值一般取一个较小的数值。通常采用交叉验证法来选取最优的 K K K值, K K K值的选择取决于数据集和问题。较小的 K K K值可能导致过度拟合,而较大的 K K K值可能导致欠拟合,可以尝试不同的 K K K值,以找到特定数据集的最佳值。
(二)距离度量
距离度量是 KNN 算法中用来计算数据点之间相似性的重要组成部分,以下是几种常见的距离度量类型:
1、欧式距离
欧式距离是 KNN 中最广泛使用的距离度量,表示两个数据点在欧几里得空间中的直线距离。
计算公式如下:
d ( x , y ) = ∑ i = 1 n ( x i − y i ) 2 d(x,y)=\sqrt{\sum_{i=1}^n\left(x_i-y_i\right)^2} d(x,y)=i=1∑n(xi−yi)2
2、曼哈顿距离
曼哈顿距离(Manhattan Distance)是一种衡量两点之间距离的方式,两个点之间的距离是沿着网格(即水平和垂直方向)的路径总和,而不是像欧几里得距离那样的直线距离。
计算公式如下:
d ( x , y ) = ∑ i = 1 n ∣ x i − y i ∣ d(x,y)=\sum_{i=1}^n|x_i-y_i| d(x,y)=i=1∑n∣xi−yi∣
3、闵可夫斯基距离
闵可夫斯基距离是一个广义的距离度量,可以根据参数 𝑝的不同,生成多种常见的距离度量,如曼哈顿距离和欧几里得距离。计算方法是绝对差和的 p 次方根.例如:
如果 p = 1,简化为曼哈顿距离,即绝对差的和。
如果 p = 2,简化为欧几里得距离,即平方差的和的平方根。
距离度量必须满足一些条件:
非负性:任意两点之间的距离不能为负。
同一性:点与自身的距离为零。
对称性:两点之间的距离相同。
三角不等式:两点之间的距离应小于或等于通过第三点的路径之和。
计算公式如下所示:
d ( x , y ) = ( ∑ i = 1 n ∣ x i − y i ∣ p ) 1 p d(x,y)=\left(\sum_{i=1}^n|x_i-y_i|^p\right)^{\frac1p} d(x,y)=(i=1∑n∣xi−yi∣p)p1
(三)决策规则
1、分类决策规则
KNN算法的分类决策通常基于多数表决原则,即在新样本的 K K K个最近邻中,哪个类别的样本数最多,则预测新样本属于该类别。此外,也可以根据样本与新数据点之间的距离远近进行加权投票,即离新样本越近的邻居样本权重越大,影响力也越大。分类的决策规则可以用经验风险最小化来解释,假设我们要最小化分类中的错误,即最小化0-1 损失函数。这个损失函数可以表示为:
L = 1 K ∑ x i ∈ N K ( X ) I ( y i ≠ c m ) = 1 − 1 K ∑ x i ∈ N K ( X ) I ( y i = c m ) L=\dfrac{1}{K}\sum_{{{x}}_i\in\mathcal{N}_K({{X}})}I({y}i\neq c_m)=1-\dfrac{1}{K}\sum{{{x}}_i\in\mathcal{N}_K({{X}})}I({y}_i=c_m) L=K1xi∈NK(X)∑I(yi=cm)=1−K1xi∈NK(X)∑I(yi=cm)
其中:
∙ \bullet ∙ X {{X} } X是新样本点。
∙ \bullet ∙ N k ( x ) \mathcal{N} _k( {{x} } ) Nk(x)是新样本 ∙ \bullet ∙ X {{X}} X的 K 个最近邻的集合。
∙ \bullet ∙ y i {y} _i yi是近邻 x i {{x}}_i xi 的实际标签。
∙ \bullet ∙ c m c_m cm是预测的类别,即我们希望找到的多数类别。
∙ \bullet ∙ I ( y i ≠ c m ) I( {y} _i\neq c_m) I(yi=cm)是指示函数,表示近邻 x i {{x}}_i xi的实际类别与 c m c_m cm是否相同。
通过这个公式可以看到,损失函数 L L L表示的是分类错误的比例。为了最小化损失函数,我们需要找到一个类别 c m c_{m} cm使得近邻中属于该类别的样本数量最大。因此,损失函数最小化等价于多数表决:
c m = arg max c m ∑ x i ∈ N k ( X ) I ( y i = c m ) c_m=\arg\max_{c_m}\sum_{{{x}}_i\in\mathcal{N}_k({{X}})}I({y}_i=c_m) cm=argcmmaxxi∈Nk(X)∑I(yi=cm)
2、回归决策规则
对于 KNN 回归,决策规则与分类类似,但在回归问题中,输出是连续值,而不是类别。因此,KNN 回归通常采用均值回归,即新样本的预测值是 K 个最近邻样本的目标值的均值。同样,我们也可以基于样本与新样本点之间的距离进行加权投票,距离越近的邻居对预测的影响力越大。
在回归问题中,我们依然可以使用经验风险最小化的思想,回归中的损失函数一般是均方误差(MSE)。回归问题的损失函数表示为:
L = 1 K ∑ x i ∈ N K ( X ) ( y i − y ^ ) 2 L=\dfrac{1}{K}\sum_{{{x}}_i\in\mathcal{N}_K({{X}})}({y}_i-\hat{y})^2 L=K1xi∈NK(X)∑(yi−y^)2
其中:
∙ \bullet ∙ y ^ \hat{y} y^表示新样本的预测值。
∙ \bullet ∙ y i {y} _i yi是近邻点 x i {{x}}_i xi的实际值。
这个损失函数表示新样本X预测值与近邻点实际值之间平方误差的平均值。为了最小化均方误差,最优的预测值 y ^ \hat{y} y^应该是近邻样本实际值 y i {y}i yi的平均值,即:
y ^ = 1 K ∑ x i ∈ N K ( X ) y i \hat{y}=\frac{1}{K}\sum{{{x}}_i\in\mathcal{N}_K({{X}})}{y}_i y^=K1xi∈NK(X)∑yi
因此,KNN 回归算法的预测值是近邻点的平均值,即均值回归。
总结来说,KNN 算法的分类和回归决策规则虽然任务不同,但核心思想都是通过找到最近的K个邻居,然后根据这些邻居的属性 (类别或值) 进行多数表决或均值计算,从而做出预测。
三、算法优缺点
优点
1、KNN 可用于分类和回归任务,适应性强。
无需训练:算法不需要训练阶段,直接使用数据进行预测,节省计算资源。
2、由于依赖于邻居的多数投票,KNN 对噪声数据具有较强的抗干扰能力,不易受异常值影响。
3、KNN 在小数据集上表现良好,不需要大量数据即可进行预测。
4、不需要对数据做出特定假设,适合多种数据分布。
5、算法直观易懂,便于实现和应用。
缺点
1、正确选择 K 值很重要,影响模型的性能,但不同数据集的最佳 K 值不同。
2、在类别不平衡的数据集中,KNN 可能偏向于多数类别。
3、当特征维度很高时,KNN 的效果会下降,因为距离计算不精确,难以找到有意义的近邻。
四、KNN分类任务实现对比
(一)数据加载和样本分区
1、Python代码
python
# 导入相关包
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix
from sklearn.datasets import load_iris
##在线导入
#data = datasets.load_iris()
# 本地导入
df = pd.read_csv("D:/sentosa_ML/Sentosa_DSML/mlServer/TestData/Iris.csv")
df.head()
df["Species"].unique()
df.shape
encoder = LabelEncoder()
df["Species"] = encoder.fit_transform(df["Species"])
# 将数据集划分为特征和标签
X = df.drop("Species", axis=1) # 特征
y = df["Species"] # 标签
# 数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,random_state=0)
2、Sentosa_DSML社区版
首先,利用文本算子对数据集进行读入,
其次,连接样本分区算子,划分测试集和训练集的比例为2:8
然后接类型算子,设置Feature列和Label列
(二)训练模型
1、Python代码
python
# 初始化 KNN 分类器,K值设置为3
knn = KNeighborsClassifier(n_neighbors=3)
# 训练模型
knn.fit(X_train, y_train)
# 对新样本进行预测
X_new = pd.DataFrame([[5, 2.9, 1, 0.2]], columns=X.columns)
prediction = knn.predict(X_new)
# print(f"Predicted target name: {encoder.inverse_transform(prediction)}")
# 对测试集进行预测
y_pred = knn.predict(X_test)
2、Sentosa_DSML社区版
连接KNN分类算子,这里我们将K值设置为3,点击应用并执行,
执行结束后得到KNN模型
(三)模型评估和模型可视化
1、Python代码
python
# 评估模型
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred, average='weighted')
recall = recall_score(y_test, y_pred, average='weighted')
f1 = f1_score(y_test, y_pred, average='weighted')
# 打印评估结果
print(f"KNN 模型的准确率: {accuracy:.2f}")
print(f"加权精度 (Weighted Precision): {precision:.2f}")
print(f"加权召回率 (Weighted Recall): {recall:.2f}")
print(f"F1 值 (Weighted F1 Score): {f1:.2f}")
# 生成混淆矩阵
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=encoder.classes_, yticklabels=encoder.classes_)
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.title('Confusion Matrix')
plt.show()
# 绘制特征分布图
plt.figure(figsize=(12, 8))
for i, column in enumerate(X.columns, 1):
plt.subplot(2, 2, i)
sns.boxplot(x=df['Species'], y=X[column])
plt.title(f'{column} by Species')
plt.tight_layout()
plt.show()
可以绘制Iris数据集中各个特征在不同分类下的分布图,以帮助我们了解不同类别的鸢尾花(Species)在不同特征(如sepal_length, sepal_width等)上的分布情况,生成了4个箱线图,每个箱线图展示了一个特征在不同Species(花种)类别上的分布情况。
2、Sentosa_DSML社区版
连接评估算子对模型进行评估
得到训练集和测试集的各评估指标结果,如下所示:
右击模型可以查看模型的模型信息,可以得到模型混淆矩阵、特征重要性等结果
也可以连接二维箱线图,绘制Iris数据集中不同特征(sepal_length, sepal_width、petal_length、petal_width)在不同分类(Species)下的分布图
执行后可以得到绘制结果,如下图所示:
五、KNN回归任务实现对比
(一)数据加载和样本分区
1、Python代码
python
# 导入相关库
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsRegressor
import matplotlib.pyplot as plt
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import seaborn as sns
# 读取 winequality 数据集
df = pd.read_csv("D:/sentosa_ML/Sentosa_DSML/mlServer/TestData/winequality.csv")
# 检查数据集
print(df.head())
print(df.info())
# 将数据集划分为特征和目标变量
X = df.drop("quality", axis=1) # 特征
y = df["quality"] # 标签(目标值)
# 数据集拆分为训练集和测试集,训练集和测试集比例为8:2
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
2、Sentosa_DSML社区版
首先,利用文本算子对数据集进行读取
其次,连接样本样本分区算子划分训练集和测试集,训练集和测试集比例为8:2
然后连接类型算子设置Label列和Feature列
(二)训练模型
1、Python代码
python
# 初始化 KNN 回归模型
knn_regressor = KNeighborsRegressor(n_neighbors=3) # K值设置为3
# 训练模型
knn_regressor.fit(X_train, y_train)
# 对测试集进行预测
y_pred = knn_regressor.predict(X_test)
2、Sentosa_DSML社区版
连接KNN回归算子,设置模型超参数K值为3
右键执行后得到KNN模型
(三)模型评估和模型可视化
1、Python代码
python
# 计算评估指标
r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mape = np.mean(np.abs((y_test - y_pred) / y_test)) * 100
smape = 100 / len(y_test) * np.sum(2 * np.abs(y_test - y_pred) / (np.abs(y_test) + np.abs(y_pred)))
# 打印评估结果
print(f"R²: {r2:.4f}")
print(f"MAE: {mae:.4f}")
print(f"MSE: {mse:.4f}")
print(f"RMSE: {rmse:.4f}")
print(f"MAPE: {mape:.2f}%")
print(f"SMAPE: {smape:.2f}%")
# 绘制实际值与预测值的对比图
plt.figure(figsize=(8, 6))
plt.scatter(y_test, y_pred, color="blue", alpha=0.6)
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], 'r--')
plt.xlabel('Actual Quality')
plt.ylabel('Predicted Quality')
plt.title('Actual vs Predicted Wine Quality')
plt.show()
# 计算残差
residuals = y_test - y_pred
# 使用 Seaborn 并添加核密度估计 (KDE) 曲线
plt.figure(figsize=(8, 6))
sns.histplot(residuals, kde=True, bins=20)
plt.title('Residuals Histogram with KDE')
plt.xlabel('Residuals')
plt.ylabel('Frequency')
plt.grid(True)
plt.show()
2、Sentosa_DSML社区版
连接评估算子,对模型进行评估
得到训练集和测试集评估结果如下图所示:
右击可以查看模型信息,得到模型特征重要性图、实际值---残差值散点图和残差立方图等结果,如下所示:
六、总结
相比传统代码方式,利用Sentosa_DSML社区版完成机器学习算法的流程更加高效和自动化,传统方式需要手动编写大量代码来处理数据清洗、特征工程、模型训练与评估,而在Sentosa_DSML社区版中,这些步骤可以通过可视化界面、预构建模块和自动化流程来简化,有效的降低了技术门槛,非专业开发者也能通过拖拽和配置的方式开发应用,减少了对专业开发人员的依赖。
Sentosa_DSML社区版提供了易于配置的算子流,减少了编写和调试代码的时间,并提升了模型开发和部署的效率,由于应用的结构更清晰,维护和更新变得更加容易,且平台通常会提供版本控制和更新功能,使得应用的持续改进更为便捷。
为了非商业用途的科研学者、研究人员及开发者提供学习、交流及实践机器学习技术,推出了一款轻量化且完全免费的Sentosa_DSML社区版。以轻量化一键安装、平台免费使用、视频教学和社区论坛服务为主要特点,能够与其他数据科学家和机器学习爱好者交流心得,分享经验和解决问题。文章最后附上官网链接,感兴趣工具的可以直接下载使用