🎩 欢迎来到技术探索的奇幻世界👨💻
📜 个人主页:@一伦明悦-CSDN博客
✍🏻 作者简介: C++软件开发、Python机器学习爱好者
🗣️ 互动与支持:💬评论 👍🏻点赞 📂收藏 👀关注+
如果文章有所帮助,欢迎留下您宝贵的评论,
点赞加收藏支持我,点击关注,一起进步!
目录
前言
sklearn.neighbors是scikit-learn库中用于实现K近邻算法的模块。它提供了用于分类、回归、密度估计等任务的K近邻算法的实现。该模块包含了多种K近邻算法的实现,如基本的KNN分类器、回归器、最近邻图等。你可以使用该模块来构建K近邻模型,并对数据进行分类、回归等任务。
K近邻(K-Nearest Neighbors,KNN)是一种常用的监督学习算法,用于分类和回归问题。在分类问题中,给定一个未标记的样本,KNN算法会通过查找其最近的K个已标记的样本(即邻居),以多数投票的方式确定该样本的类别。在回归问题中,KNN算法会通过取其K个最近邻居的平均值来预测目标变量的值。KNN算法的核心思想是假设相似的样本在特征空间中具有相似的类别或值。
正文
01-核密度估计实战
核密度估计(KDE)是一种非参数方法,用于估计随机变量的概率密度函数。其原理是在每个数据点周围放置一个核,并对所有核的贡献进行求和,以估计域中每个点的密度。常用的核函数包括高斯核、Epanechnikov核和三角形核等。KDE可以用于数据分析中的密度估计,也可通过识别低概率密度区域进行异常检测。优点包括捕捉复杂的数据分布、不对潜在数据分布做出假设,但缺点是核选择和带宽参数的选择会影响结果,并且对于高维数据而言计算密集型。
核密度估计的原理是基于概率密度函数的非参数估计方法。它的核心思想是通过在每个数据点周围放置一个核,来估计数据的概率密度分布。这个核可以是一个平滑的对称函数,通常是一个以该数据点为中心的函数。核的形状决定了对密度函数的估计的影响程度。
具体来说,对于每个数据点 ( x_i ),核密度估计会计算一个以 ( x_i ) 为中心的核函数的贡献,然后将所有数据点的贡献进行求和。这样就得到了在整个数据域中每个点的密度估计值。常用的核函数包括高斯核(也称为正态分布核)、Epanechnikov核和三角形核等。高斯核在实践中应用广泛,因为它的平滑性和对称性使得估计的密度函数更加平滑且具有良好的性质。
核密度估计的目标是找到一个平滑的函数,尽可能准确地反映出观测数据的密度分布情况。通过调整核的形状和带宽参数,可以调整估计密度函数的平滑度和精确度。核的选择和带宽参数的选择对最终的密度估计结果至关重要。较窄的带宽可能导致估计过度拟合,而较宽的带宽可能导致估计过度平滑,因此在实践中需要进行适当的参数选择。
总之,核密度估计通过在每个数据点周围放置核函数来估计数据的概率密度分布,其原理在于通过核的贡献求和来计算每个点的密度估计值,常用的核函数包括高斯核等,但对核函数和带宽参数的选择十分敏感。
下面给出代码,详细分析应用过程:
数据加载和降维:首先,使用load_digits()
加载手写数字数据集,然后使用主成分分析(PCA)将原始的64维数据投影到较低维度(这里是15维),以便后续的处理和可视化。
带宽参数优化:通过网格搜索交叉验证(GridSearchCV),在一系列候选的带宽参数值中找到最佳的带宽参数。带宽参数是核密度估计中的一个关键参数,决定了核的宽度,影响了估计的平滑度和精度。
核密度估计:使用最佳的带宽参数来初始化核密度估计器,并在数据上进行核密度估计。这里的核密度估计器是基于高斯核的。
数据采样和逆变换:从核密度估计模型中抽样生成新的数据点。然后使用PCA的逆变换将这些新的数据点变换回原始的64维空间,以便与原始数据进行对比。
可视化结果:将原始数据集中的一部分手写数字和从核密度模型中生成的新手写数字进行对比展示。这里的图像展示了真实的手写数字(上半部分)和从核密度模型中提取的“新”数字(下半部分)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.neighbors import KernelDensity
from sklearn.decomposition import PCA
from sklearn.model_selection import GridSearchCV
# 加载数据
digits = load_digits()
# 将64维数据投影到较低维
pca = PCA(n_components=15, whiten=False)
data = pca.fit_transform(digits.data)
# 使用网格搜索交叉验证来优化带宽
params = {'bandwidth': np.logspace(-1, 1, 20)}
grid = GridSearchCV(KernelDensity(), params)
grid.fit(data)
print("best bandwidth: {0}".format(grid.best_estimator_.bandwidth))
# 使用最佳估计器来计算核密度估计
kde = grid.best_estimator_
# 从数据中抽样44个点
new_data = kde.sample(44, random_state=0)
new_data = pca.inverse_transform(new_data)
# 把数据变换为4*11结构的网格
new_data = new_data.reshape((4, 11, -1))
real_data = digits.data[:44].reshape((4, 11, -1))
# 绘制真实的手写数字数据集以及抽样出的44个数字的数据集
fig, ax = plt.subplots(9, 11, subplot_kw=dict(xticks=[], yticks=[]))
for j in range(11):
ax[4, j].set_visible(False)
for i in range(4):
im = ax[i, j].imshow(real_data[i, j].reshape((8, 8)),
cmap=plt.cm.binary, interpolation='nearest')
im.set_clim(0, 16)
im = ax[i + 5, j].imshow(new_data[i, j].reshape((8, 8)),
cmap=plt.cm.binary, interpolation='nearest')
im.set_clim(0, 16)
ax[0, 5].set_title('从输入数据中进行选择')
ax[5, 5].set_title('从核密度模型中提取的“新”数字')
plt.savefig("../4.png", dpi=500)
plt.show()
示例运行结果如下图所示:
02-缓存最近邻分析
缓存最近邻(Cache KNN)是一种优化K最近邻(KNN)算法的方法,其原理是通过缓存先前计算的最近邻结果,以减少后续查询时的计算量。在KNN算法中,为了找到一个样本的最近邻,需要计算该样本与所有训练数据之间的距离,并选取距离最近的K个样本作为最近邻。而缓存最近邻通过存储先前查询过的样本的最近邻结果,当遇到相似的查询时,直接从缓存中获取最近邻结果,避免了重复计算距离的过程,从而提高了算法的运行效率。
具体来说,缓存最近邻的工作流程如下:
查询阶段:当需要寻找一个新样本的最近邻时,首先检查缓存中是否已经存储了该样本的最近邻结果。
命中缓存:如果缓存中存在该样本的最近邻结果,则直接返回缓存中的结果,无需重新计算距离。
未命中缓存:如果缓存中不存在该样本的最近邻结果,则执行标准的KNN算法,计算该样本与所有训练数据之间的距离,并选取距离最近的K个样本作为最近邻,并将结果存储到缓存中以备下次查询使用。
通过缓存最近邻,可以显著减少KNN算法的计算时间,特别是在处理大规模数据集时。然而,需要注意的是,缓存最近邻的效果取决于缓存策略的设计和缓存空间的大小。
下面给出代码示例详细分析应用过程: 这段代码实现了对K最近邻算法的优化,包括使用缓存来减少计算时间,并通过美化图像提升可读性。
首先,加载了手写数字数据集(load_digits)作为例子。
确定了需要测试的最近邻数量列表(n_neighbors_list)。
创建了KNeighborsTransformer用于计算最近邻图,以及KNeighborsClassifier用于分类。
使用Pipeline将转换器和分类器组合起来,并为缓存提供了一个临时目录。
使用GridSearchCV进行参数网格搜索,找到最佳的分类器超参数。
绘制了两个子图:一个显示了分类准确度随最近邻数量的变化,另一个显示了拟合时间随最近邻数量的变化。
from tempfile import TemporaryDirectory
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsTransformer, KNeighborsClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_digits
from sklearn.pipeline import Pipeline
print(__doc__)
X, y = load_digits(return_X_y=True)
n_neighbors_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 转换器使用网格搜索中所需的最大邻居数来计算最近邻图。分类器模型根据自己的n_neighbors参数的要求过滤最近的邻居图。
graph_model = KNeighborsTransformer(n_neighbors=max(n_neighbors_list),
mode='distance')
classifier_model = KNeighborsClassifier(metric='precomputed')
# 请注意,我们为"memory"提供了一个目录来缓存图计算,该图计算在调整分类器的超参数时将多次使用。
with TemporaryDirectory(prefix="sklearn_graph_cache_") as tmpdir:
full_model = Pipeline(
steps=[('graph', graph_model), ('classifier', classifier_model)],
memory=tmpdir)
param_grid = {'classifier__n_neighbors': n_neighbors_list}
grid_model = GridSearchCV(full_model, param_grid)
grid_model.fit(X, y)
# 绘制网格搜索的结果
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].errorbar(x=n_neighbors_list,
y=grid_model.cv_results_['mean_test_score'],
yerr=grid_model.cv_results_['std_test_score'],
fmt='-o', color='b', ecolor='lightblue', capsize=5)
axes[0].set(xlabel='n_neighbors', ylabel='Classification accuracy', title='Classification Accuracy')
axes[0].grid(True)
axes[1].errorbar(x=n_neighbors_list, y=grid_model.cv_results_['mean_fit_time'],
yerr=grid_model.cv_results_['std_fit_time'],
fmt='-o', color='r', ecolor='pink', capsize=5)
axes[1].set(xlabel='n_neighbors', ylabel='Fit time (with caching)', title='Fit Time (with caching)')
axes[1].grid(True)
fig.tight_layout()
plt.savefig("../4.png", dpi=500)
plt.show()
示例运行结果如下图所示:
左图显示了分类准确度随最近邻数量的变化,其中蓝色的实线表示平均测试准确度,轻蓝色区域表示标准差范围。误差条表示了测试准确度的不确定性。
右图显示了拟合时间随最近邻数量的变化,其中红色的实线表示平均拟合时间,粉红色区域表示标准差范围。误差条表示了拟合时间的不确定性。
03-邻域成分分析实战
邻域成分分析(Neighborhood Component Analysis,简称NCA)是一种监督学习降维技术,旨在通过优化样本的投影来最大化分类性能。其原理是通过学习一个线性变换,将高维数据映射到低维空间,并使得同类样本之间的距离尽可能小,不同类样本之间的距离尽可能大。
具体来说,NCA的工作原理如下:
对于每个样本,计算其与其他样本之间的距离,并根据样本的标签,确定哪些样本属于同一类别,哪些样本属于不同类别。
通过学习一个线性变换矩阵,将高维数据映射到低维空间,使得同类样本之间的距离在低维空间中尽可能小,不同类样本之间的距离在低维空间中尽可能大。
优化目标通常是最大化一个特定的分类性能指标,例如KNN分类器的准确率或者逻辑回归模型的对数似然。
总体而言,NCA试图学习一个投影矩阵,以最大化分类性能。通过调整投影矩阵,使得样本在低维空间中的分布更有利于后续的分类任务,从而提高了算法的效果。
下面给出具体代码示例分析应用过程:
这段代码首先生成了一个二维的分类数据集(X, y),其中X是特征,y是对应的类标签。然后,使用matplotlib绘制了原始数据点的散点图,每个数据点附带一个标签,标识数据点的索引。接着定义了两个函数:link_thickness_i
和 relate_point
。
link_thickness_i
函数计算了数据点 i 与其他数据点之间的连接粗细,粗细值与数据点之间的距离成反比。函数内部使用了np.einsum
来计算欧式距离的平方,并利用log-sum-exp技巧来处理数值稳定性问题。然后,通过指数函数将距离转换为连接粗细值。
relate_point
函数根据连接粗细值绘制了数据点 i 与其他数据点之间的连接线。连接线的颜色由数据点 j 的类别确定,颜色映射与原始数据点的类别相同。
最后,选择了一个数据点 i(这里是索引为3的数据点),并调用relate_point
函数绘制了该数据点与其他数据点之间的连接线。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.neighbors import NeighborhoodComponentsAnalysis
from matplotlib import cm
from scipy.special import logsumexp
X, y = make_classification(n_samples=9, n_features=2, n_informative=2,
n_redundant=0, n_classes=3, n_clusters_per_class=1,
class_sep=1.0, random_state=0)
plt.figure(1)
ax = plt.gca()
for i in range(X.shape[0]):
ax.text(X[i, 0], X[i, 1], str(i), va='center', ha='center')
ax.scatter(X[i, 0], X[i, 1], s=300, c=cm.Set1(y[[i]]), alpha=0.4)
ax.set_title("Original points")
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
ax.axis('equal') # so that boundaries are displayed correctly as circles
def link_thickness_i(X, i):
diff_embedded = X[i] - X
dist_embedded = np.einsum('ij,ij->i', diff_embedded,
diff_embedded)
dist_embedded[i] = np.inf
# compute exponentiated distances (use the log-sum-exp trick to
# avoid numerical instabilities
exp_dist_embedded = np.exp(-dist_embedded -
logsumexp(-dist_embedded))
return exp_dist_embedded
def relate_point(X, i, ax):
pt_i = X[i]
for j, pt_j in enumerate(X):
thickness = link_thickness_i(X, i)
if i != j:
line = ([pt_i[0], pt_j[0]], [pt_i[1], pt_j[1]])
ax.plot(*line, c=cm.Set1(y[j]),
linewidth=5*thickness[j])
i = 3
relate_point(X, i, ax)
plt.show()
示例运行结果如下图所示:
图中的散点代表了原始的数据点,每个散点附带有一个标签表示数据点的索引。
连接线的粗细表示了对应数据点之间的距离,粗细越大表示距离越近。
连接线的颜色由对应连接的另一个数据点的类别确定,不同类别的数据点使用不同的颜色。
下面这段代码是使用NeighborhoodComponentsAnalysis(NCA)对原始数据进行降维,并绘制了降维后的数据点之间的关系。首先,通过nca.fit(X, y)
对NCA模型进行训练,将原始数据X
和对应的类标签y
传入模型中进行学习。
接着,在降维后的空间中,使用nca.transform(X)
将原始数据映射到新的低维空间X_embedded
。然后,调用relate_point
函数绘制了降维后的数据点之间的连接线,连接线的粗细表示了数据点之间的关系密度。
在绘制图像时,每个数据点都用一个散点表示,散点的位置由降维后的数据点坐标决定,而散点的颜色仍然由原始数据点的类别决定。图像的标题为"NCA embedding",表示这是使用NCA进行降维后的结果。
nca = NeighborhoodComponentsAnalysis()
nca.fit(X, y)
plt.figure(2)
ax2 = plt.gca()
X_embedded = nca.transform(X)
relate_point(X_embedded, i, ax2)
for i in range(len(X)):
ax2.text(X_embedded[i, 0], X_embedded[i, 1], str(i),
va='center', ha='center')
ax2.scatter(X_embedded[i, 0], X_embedded[i, 1], s=300, c=cm.Set1(y[[i]]),
alpha=0.4)
ax2.set_title("NCA embedding")
ax2.axes.get_xaxis().set_visible(False)
ax2.axes.get_yaxis().set_visible(False)
ax2.axis('equal')
plt.savefig("../4.png", dpi=500)
plt.show()
示例运行结果如下图所示:
图中的散点代表了降维后的数据点,每个散点附带有一个标签表示数据点的索引。
连接线的粗细表示了数据点之间的关系密度,粗细越大表示关系越密切。
散点的颜色仍然由原始数据点的类别确定,保持了原始数据的类别信息。
图像标题"NCA embedding"表明这是使用NCA进行降维后的结果。
04-基于局部离群因子算法的新颖性检测
局部离群因子(Local Outlier Factor,LOF)是一种用于检测数据集中离群点(异常点)的算法。它主要基于数据点相对于其邻近数据点的密度来判断数据点的异常程度。以下是局部离群因子算法的详细分析和工作原理:
工作原理:
邻近度量: LOF算法首先通过定义数据点与其邻近数据点之间的距离来衡量点的密度。通常采用欧氏距离或其他距离度量方法。
局部密度计算: 对于每个数据点,计算其邻近数据点的距离,并根据邻近点之间的距离来计算局部密度。局部密度越大表示该点周围数据点密度越高。
局部可达密度计算: 对于每个数据点,计算其邻近数据点的局部密度与其邻近点的局部密度之比,得到该点的局部可达密度。局部可达密度反映了数据点相对于其邻近数据点的密度情况。
局部离群因子计算: LOF算法通过比较每个数据点的局部可达密度与邻近数据点的局部可达密度之比来计算局部离群因子。离群点的局部离群因子通常会远高于普通数据点。
异常点检测: 根据局部离群因子的值,可以识别出相对于其邻近数据点具有异常行为的数据点,即离群点。
算法特点:
LOF算法不仅考虑了离群点自身的特性,还考虑了其周围数据点的密度情况,因此可以更准确地确定离群点。
LOF算法对数据分布没有假设,适用于各种数据集,对数据集的拓扑结构没有要求。
LOF算法能够对离群点进行定量评估,通过局部离群因子值对异常点进行排序。
应用:
金融领域:用于检测信用卡欺诈、异常交易等。
网络安全:用于检测网络攻击、异常流量等。
工业领域:用于检测设备故障、异常生产情况等。
医疗领域:用于识别疾病患者中的异常病例等。
通过局部离群因子算法,可以帮助识别和定位数据集中的离群点,发现数据中的新颖性模式和异常行为,从而在各个领域中带来更深入的见解和价值。
下面给出具体代码示例分析应用过程:这段代码演示了使用局部离群因子(LOF)算法进行新颖性检测,并可视化检测结果。下面是代码的详细分析和生成图像的解释:
生成数据:通过np.meshgrid
生成一个网格,在该网格范围内生成正常观测结果、新的正常观测值和异常观测值。正常观测结果被生成在中心点周围,新的正常观测值被生成在原正常观测结果上下各移动一定距离,异常观测值被随机生成在整个网格中。
拟合模型:使用LocalOutlierFactor
模型进行新颖性检测,设定参数:n_neighbors=20
表示邻近点数量,novelty=True
表示进行新颖性检测,contamination=0.1
表示异常数据的比例。对于训练数据X_train
进行模型拟合。
预测和评估:使用模型对测试数据X_test
和异常数据X_outliers
进行预测,得到预测结果。统计预测结果中的错误数量,分别统计测试数据中的正常观测值和异常观测值的错误数量。
绘制图像:绘制学习的边界,点和最接近平面的向量,通过plt.contourf
和plt.contour
绘制LOF学习的边界。绘制训练观测结果、新的正常观测值和异常观测值的散点图,使用不同颜色区分。添加图例,解释图中各个元素的含义。在图像上添加了误差信息,显示了新的正常观测值和异常观测值的错误数量。
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from sklearn.neighbors import LocalOutlierFactor
print(__doc__)
np.random.seed(42)
xx, yy = np.meshgrid(np.linspace(-5, 5, 500), np.linspace(-5, 5, 500))
# 生成正常(非异常)的训练观察结果
X = 0.3 * np.random.randn(100, 2)
X_train = np.r_[X + 2, X - 2]
# 生成新的正常(非异常)观测值
X = 0.3 * np.random.randn(20, 2)
X_test = np.r_[X + 2, X - 2]
# 生成新的异常的观测值
X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2))
# 拟合模型以进行新颖性检测(novelty = True)
clf = LocalOutlierFactor(n_neighbors=20, novelty=True, contamination=0.1)
clf.fit(X_train)
# 请勿在X_train上使用predict,decision_function和score_samples,因为这样会产生错误的结果,而只会在新的、没见过的数据上使用(X_train中未使用),例如X_test,X_outliers或meshgrid
y_pred_test = clf.predict(X_test)
y_pred_outliers = clf.predict(X_outliers)
n_error_test = y_pred_test[y_pred_test == -1].size
n_error_outliers = y_pred_outliers[y_pred_outliers == 1].size
# 绘制学习的边界,点和最接近平面的向量
Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.title("Novelty Detection with LOF")
plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 0, 7), cmap=plt.cm.PuBu)
a = plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='darkred')
plt.contourf(xx, yy, Z, levels=[0, Z.max()], colors='palevioletred')
s = 40
b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c='white', s=s, edgecolors='k')
b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c='blueviolet', s=s,
edgecolors='k')
c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c='gold', s=s,
edgecolors='k')
plt.axis('tight')
plt.xlim((-5, 5))
plt.ylim((-5, 5))
plt.legend([a.collections[0], b1, b2, c],
["learned frontier", "training observations",
"new regular observations", "new abnormal observations"],
loc="upper left",
prop=matplotlib.font_manager.FontProperties(size=11))
plt.xlabel(
"errors novel regular: %d/40 ; errors novel abnormal: %d/40"
% (n_error_test, n_error_outliers))
plt.show()
示例运行结果如下图所示:
学习的边界:通过等高线表示LOF学习的边界,分为正常区域(深蓝色)和异常区域(浅红色)。
点和向量:训练观测结果(白色点)、新的正常观测值(紫蓝色点)和新的异常观测值(金色点)分别用散点表示,边缘有黑色边框。图中的向量表示最接近平面的方向。
图例:解释了图中各个元素的含义,包括学习的边界、训练观测结果、新的正常观测值和新的异常观测值。
误差信息:在x轴标签中显示了新的正常观测值和异常观测值的错误数量,以便评估模型性能。
通过这个图像,可以直观地看到LOF算法对于新颖性检测的效果,以及模型如何将正常观测值和异常观测值进行分类。
总结
对核密度估计(KDE)、缓存最近邻、邻域成分分析(NCA)以及局部离群因子(LOF)算法总结如下:
核密度估计(KDE):
概述:KDE是一种非参数的方法,用于估计随机变量的概率密度函数。它提供了对潜在概率密度函数的平滑估计。
过程:在每个数据点上放置一个核(一个平滑的对称函数)。对所有核的贡献进行求和,以估计域中每个点的密度。通常使用高斯核,但也可以使用其他核函数,如Epanechnikov或三角形核。
应用:数据分析中的密度估计。通过识别低概率密度区域进行异常检测。
优点:捕捉复杂的数据分布。不对潜在数据分布做出假设。
缺点:核选择和带宽参数的选择会显著影响结果。计算密集型,特别是对于高维数据。
近似最近邻(ANN)缓存:
概述:ANN缓存是一种通过存储预先计算的每个数据点的最近邻来加速最近邻搜索的技术。
过程:预先计算并存储每个数据点的最近邻。在查询最近邻时,检索缓存的结果,而不是从头开始计算。
应用:大型数据集中的高维最近邻搜索。加速kNN和LOF等算法。
优点:减少重复最近邻查询的计算时间。对于大规模数据集效率高。
缺点:需要额外的内存来存储缓存的结果。可能不适用于数据点频繁变化的动态数据集。
邻域成分分析(NCA):
概述:NCA是一种以监督方式直接从数据中学习距离度量的方法。它旨在最大化学习度量的判别能力。
过程:学习一个线性变换矩阵,最大化正确分类的可能性。使用梯度下降或其他优化技术迭代地学习变换。
应用:用于分类任务的降维。用于提高分类性能的特征提取。
优点:将距离度量适应于特定任务。通过学习灵活的变换处理非线性决策边界。
缺点:对数据中的噪声和异常值敏感。对于大型数据集和高维特征空间计算量大。
局部离群因子(LOF)算法:
概述:LOF是一种无监督算法,用于通过测量数据点相对于其邻居的局部密度偏差来检测异常值。
过程:基于其k个最近邻计算每个数据点的局部密度。计算每个点的局部离群因子,指示其相对于邻居的局部密度偏差。具有显着较高LOF值的点被视为异常值。
应用:在各种领域进行异常检测,包括欺诈检测和网络安全。
优点:有效识别高维数据集中的异常值。不假设特定的数据分布。
缺点:计算密集型,特别是对于大型数据集。对参数选择(如k和底层数据分布)敏感。