knnsearch
使用输入数据查找 k 最近邻点
说明
示例
根据年龄和体重,在 hospital 数据集中找到与 Y 中的患者最相似的患者。
加载 hospital 数据集。
load hospital; X = [hospital.Age hospital.Weight]; Y = [20 162; 30 169; 40 168; 50 170; 60 171]; % New patients
在 X 和 Y 之间执行 knnsearch 以找到最近邻点的索引。
Idx = knnsearch(X,Y);
在 X 中找到与 Y 中患者的年龄和体重最接近的患者。
X(Idx,:)
ans = 5×2
25 171
25 171
39 164
49 170
50 172
在 X 中找到与 Y 中每个点最接近的 10 个最近邻点,首先使用闵可夫斯基距离度量,然后使用切比雪夫距离度量。
加载费舍尔鸢尾花数据集。
load fisheriris X = meas(:,3:4); % Measurements of original flowers Y = [5 1.45;6 2;2.75 .75]; % New flower data
使用闵可夫斯基距离度量和切比雪夫距离度量,在 X 和查询点 Y 之间执行 knnsearch。
[mIdx,mD] = knnsearch(X,Y,'K',10,'Distance','minkowski','P',5); [cIdx,cD] = knnsearch(X,Y,'K',10,'Distance','chebychev');
可视化两个最近邻搜索的结果。绘制训练数据。用标记 X 绘制查询点。使用圆圈表示闵可夫斯基最近邻点。使用五角星表示切比雪夫最近邻点。
gscatter(X(:,1),X(:,2),species) line(Y(:,1),Y(:,2),'Marker','x','Color','k',... 'Markersize',10,'Linewidth',2,'Linestyle','none') line(X(mIdx,1),X(mIdx,2),'Color',[.5 .5 .5],'Marker','o',... 'Linestyle','none','Markersize',10) line(X(cIdx,1),X(cIdx,2),'Color',[.5 .5 .5],'Marker','p',... 'Linestyle','none','Markersize',10) legend('setosa','versicolor','virginica','query point',... 'minkowski','chebychev','Location','best')

创建两个由点组成的大型矩阵,然后测量 knnsearch 采用默认的 "euclidean" 距离度量时所用的时间。
rng default % For reproducibility N = 10000; X = randn(N,1000); Y = randn(N,1000); Idx = knnsearch(X,Y); % Warm up function for more reliable timing information tic Idx = knnsearch(X,Y); standard = toc
standard = 25.3805
接下来,测量 knnsearch 采用 "fasteuclidean" 距离度量时所用的时间。指定缓存大小为 100。
Idx2 = knnsearch(X,Y,Distance="fasteuclidean",CacheSize=100); % Warm up function tic Idx2 = knnsearch(X,Y,Distance="fasteuclidean",CacheSize=100); accelerated = toc
accelerated = 2.4388
计算加速后的计算比标准计算快多少倍。
standard/accelerated
ans = 10.4071
对于此示例,加速版本快三倍以上。
输入参数
名称-值参数
将可选参量对组指定为 Name1=Value1,...,NameN=ValueN,其中 Name 是参量名称,Value 是对应的值。名称-值参量必须出现在其他参量之后,但对各个参量对组的顺序没有要求。
如果使用的是 R2021a 之前的版本,请使用逗号分隔每个名称和值,并用引号将 Name 引起来。
示例: knnsearch(X,Y,'K',10,'IncludeTies',true,'Distance','cityblock') 搜索 10 个最近邻点,包括结值,并使用城市街区距离。
包括所有与查询点距离相同的最近邻点的标志,指定为由 'IncludeTies' 和 false (0) 或 true (1) 组成的以逗号分隔的对组。
如果 'IncludeTies' 为 false,则 knnsearch 在距查询点相同距离的观测值中选择索引最小的观测值。
如果 'IncludeTies' 为 true,则:
示例: 'IncludeTies',true
最近邻搜索方法,指定为由 'NSMethod' 和以下值之一组成的以逗号分隔的对组。
示例: 'NSMethod','exhaustive'
knnsearch 使用的距离度量,指定为下表中的值之一,或指定为函数句柄。
| 值 | 描述 |
|---|---|
'euclidean' | 欧几里德距离 |
'seuclidean' | 标准化的欧几里德距离。X 中的行与查询矩阵 Y 之间的每个坐标差会除以根据 X 计算的标准差的对应元素进行缩放。要指定不同的缩放,请使用 'Scale' 名称-值参量。 |
'fasteuclidean' | 当预测变量的数目至少为 10 时,使用替代算法计算的欧几里德距离,该算法可以节省时间。在某些情况下,这种更快的算法会降低准确度。此距离度量仅当 NSMethod 为 'exhaustive' 时可用。以 'fast' 开头的算法不支持稀疏数据。有关详细信息,请参阅算法。 |
'fastseuclidean' | 当预测变量的数目至少为 10 时,使用替代算法计算的标准化的欧几里德距离,该算法可以节省时间。在某些情况下,这种更快的算法会降低准确度。此距离度量仅当 NSMethod 为 'exhaustive' 时可用。以 'fast' 开头的算法不支持稀疏数据。有关详细信息,请参阅算法。 |
'cityblock' | 城市街区距离 |
'chebychev' | 切比雪夫距离(最大坐标差) |
'minkowski' | 闵可夫斯基距离。默认指数是 2。要指定不同的指数,请使用 'P' 名称-值参量。 |
'mahalanobis' | 马氏距离,使用正定协方差矩阵计算。要更改协方差矩阵的值,请使用 'Cov' 名称-值参量。 |
'cosine' | 1 减去观测值(视为向量)之间夹角的余弦值 |
'correlation' | 1 减去观测值(视为值序列)之间的样本线性相关系数 |
'spearman' | 1 减去样本观测值(视为值序列)之间的斯皮尔曼秩相关 |
'hamming' | 汉明距离,即相异坐标所占的百分比 |
'jaccard' | 1 减去杰卡德系数,即非零相异坐标所占的百分比 |
您也可以通过使用 @(例如 @distfun)为自定义距离度量指定函数句柄。自定义距离函数必须:
具有
function D2 = distfun(ZI,ZJ)形式。接受以下参量:
1×n 向量
ZI,该向量包含来自X或查询点Y的单个行。m2×n 矩阵
ZJ,该矩阵包含X或Y的多行。
返回 m2×1 距离向量
D2,该距离向量的第j个元素是观测值ZI和ZJ(j,:)之间的距离。
有关详细信息,请参阅Distance Metrics。
示例: 'Distance','chebychev'
数据类型: char | string | function_handle
格拉姆矩阵的大小,以 MB 为单位,指定为正标量或 "maximal"。仅当 Distance 名称-值参量以 fast 开头且 NSMethod 名称-值参量设置为 'exhaustive' 时,knnsearch 函数才能使用 CacheSize。
如果您将 CacheSize 设置为 "maximal",knnsearch 会尝试为大小为 MX×MY 的整个中间矩阵分配足够的内存,其中 MX 是输入数据 X 的行数,MY 是输入数据 Y 的行数。高速缓存的大小不必大到足以容纳整个中间矩阵,但必须至少大到足以容纳一个 MX×1 向量。否则,knnsearch 使用标准算法来计算欧几里德距离。
如果 Distance 参量的值以 fast 开头,NSMethod 的值为 'exhaustive',而 CacheSize 的值太大或为 "maximal",则 knnsearch 可能会尝试分配超出可用内存的格拉姆矩阵。在这种情况下,MATLAB® 会引发错误。
示例: CacheSize="maximal"
数据类型: double | char | string
闵可夫斯基距离度量的指数,指定为由 'P' 和一个正标量组成的以逗号分隔的对组。
仅当 'Distance' 为 'minkowski' 时,此参量才有效。
示例: 'P',3
数据类型: single | double
数据类型: single | double
标准化欧几里德距离度量的尺度参数值,指定为由 'Scale' 和一个非负数值向量组成的以逗号分隔的对组。'Scale' 的长度等于 X 中的列数。当 knnsearch 计算标准化欧几里德距离时,X 的每个坐标由 'Scale' 的对应元素缩放,每个查询点也是如此。仅当 'Distance' 为 'seuclidean' 时,此参量才有效。
示例: 'Scale',quantile(X,0.75) - quantile(X,0.25)
数据类型: single | double
Kd 树的叶节点中的最大数据点数,指定为由 'BucketSize' 和一个正整数组成的以逗号分隔的对组。仅当 NSMethod 为 'kdtree' 时,此参量才有效。
示例: 'BucketSize',20
数据类型: single | double
根据距离对返回的索引进行排序的标志,指定为由 'SortIndices' 和 true (1) 或 false (0) 组成的以逗号分隔的对组。
为了提高性能,当以下条件成立时,您可以将 SortIndices 设置为 false:
NSMethod为'kdtree'。IncludeTies为false。
在这种情况下,knnsearch 返回的最近邻点索引没有特定顺序。当 SortIndices 为 true 时,函数按距离以升序排列最近邻点索引。
SortIndices 默认为 true。当 NSMethod 为 'exhaustive' 或 IncludeTies 为 true 时,函数始终会对索引进行排序。
示例: 'SortIndices',false
数据类型: logical
输出参量
最近邻点的输入数据索引,以数值矩阵或数值向量的元胞数组形式返回。
如果您不指定
IncludeTies(默认为false),则Idx是一个 m×k 数值矩阵,其中 m 是Y的行数,k 是搜索到的最近邻点数量。Idx(j,i)表示X(Idx(j,i),:)是X中最接近查询点Y(j,:)的 k 个观测值之一。如果您指定
'IncludeTies',true,则Idx是一个 m×1元胞数组,其中元胞j(Idx{j}) 包含一个向量,该向量中有至少 k 个索引,对应X中与查询点Y(j,:)最接近的观测值。
如果 SortIndices 为 true,则 knnsearch 按距离以升序排列索引。
最近邻点到查询点的距离,以数值矩阵或数值向量的元胞数组形式返回。
如果您不指定
IncludeTies(默认为false),则D是一个 m×k 数值矩阵,其中 m 是Y的行数,k 是搜索到的最近邻点的数量。D(j,i)是X(Idx(j,i),:)和Y(j,:)之间的距离(基于指定的距离度量)。如果您指定
'IncludeTies',true,则D是一个 m×1元胞数组,其中元胞j(D{j}) 包含一个向量,该向量中有至少 k 个距离,对应X中与查询点Y(j,:)最接近的观测值。
如果 SortIndices 为 true,则 knnsearch 按升序排列距离。
提示
对于固定正整数 k,
knnsearch在X中找到 k 个最接近Y中每个点的点。要找到X中在固定距离内接近Y中每个点的所有点,请使用rangesearch。knnsearch不保存搜索对象。要创建一个搜索对象,请使用createns。
算法
有关特定搜索算法的信息,请参阅 k-Nearest Neighbor Search and Radius Search。
以 fast 开头的 Distance 参量(如 "fasteuclidean" 和 "fastseuclidean")的值在计算欧几里德距离时使用的算法会使用额外的内存来节省计算时间。此算法在阿尔巴尼的文献 [1] 中和其他位置称为“欧几里德距离矩阵技巧”。内部测试表明,当预测变量的数目至少为 10 时,该算法可以节省时间。以 fast 开头的算法不支持稀疏数据。
为了求得所有点 xi 和 xj 之间距离的矩阵 D(其中每个 xi 具有 n 个变量),该算法使用以下方程中的最后一行来计算距离:
方程最后一行中的矩阵 称为格拉姆矩阵。当您计算并使用格拉姆矩阵而不是通过平方与求和来计算平方距离时,计算平方距离集的速度更快,但在数值上稳定性稍差。有关详细信息,请参阅阿尔巴尼 [1]。
为了存储格拉姆矩阵,软件使用默认大小为 1e3 MB 的缓存。您可以使用 CacheSize 名称-值参量设置缓存大小。如果 CacheSize 的值太大或为 "maximal",则软件可能会尝试分配超出可用内存容量的格拉姆矩阵。在这种情况下,软件会报错。
参考
[1] Albanie, Samuel. Euclidean Distance Matrix Trick. June, 2019. Available at https://samuelalbanie.com/files/Euclidean_distance_trick.pdf.
替代功能
如果您将 knnsearch 函数的 'NSMethod' 名称-值对组参量设置为合适的值('exhaustive' 用于穷举搜索算法,或 'kdtree' 用于 Kd 树算法),则搜索结果等效于使用 knnsearch 对象函数进行距离搜索得到的结果。与 knnsearch 函数不同,knnsearch 对象函数需要 ExhaustiveSearcher 或 KDTreeSearcher 模型对象。
Simulink 模块
要将 k 最近邻搜索集成到 Simulink® 中,您可以使用 Statistics and Machine Learning Toolbox™ 库中的 KNN Search 模块或具有 knnsearch 函数的 MATLAB Function 模块。有关示例,请参阅Predict Class Labels Using MATLAB Function Block。
在决定要使用的方法时,请考虑以下因素:
如果使用 Statistics and Machine Learning Toolbox 库模块,可以使用定点工具 (Fixed-Point Designer)将浮点模型转换为定点。
必须为具有
knnsearch函数的 MATLAB Function 模块启用对可变大小数组的支持。
参考
[1] Friedman, J. H., J. Bentley, and R. A. Finkel. “An Algorithm for Finding Best Matches in Logarithmic Expected Time.” ACM Transactions on Mathematical Software 3, no. 3 (1977): 209–226.
扩展功能
knnsearch 函数支持 tall 数组,但有以下用法说明和限制:
如果
X是 tall 数组,则Y不能为 tall 数组。同样,如果Y是 tall 数组,则X不能为 tall 数组。
有关详细信息,请参阅tall 数组。
用法说明和限制:
对于代码生成,当
X中的列数大于 7 时,'NSMethod'名称-值对组参量的默认值为'exhaustive'。'Distance'名称-值对组参量的值必须为编译时常量,并且不能为自定义距离函数。'IncludeTies'名称-值对组参量的值必须为编译时常量。不支持
'SortIndices'名称-值对组参量。输出参量始终是经过排序的。knnsearch不支持快速欧几里德距离计算的代码生成,即名称以fast开头的那些距离度量(例如'fasteuclidean')。名称-值参量中的名称必须为编译时常量。例如,为了在生成代码中允许对闵可夫斯基距离使用用户定义指数,请在
codegen(MATLAB Coder) 的-args值中包含{coder.Constant('Distance'),coder.Constant('Minkowski'),coder.Constant('P'),0}。当您将
'IncludeTies'指定为true时,由于数值精度的原因,生成代码中结值距离的排序顺序可能不同于 MATLAB 中的顺序。当
knnsearch使用 kd 树搜索算法,并且代码生成编译类型为 MEX 函数时,codegen(MATLAB Coder) 使用 Intel® Threading Building Blocks (TBB) 生成用于并行计算的 MEX 函数。否则,codegen使用parfor(MATLAB Coder) 生成代码。用于 kd 树搜索算法的 MEX 函数 -
codegen使用 Intel TBB 生成优化的 MEX 函数,用于多核平台上的并行计算。您可以使用 MEX 函数来加速 MATLAB 算法。有关 Intel TBB 的详细信息,请参阅 https://www.intel.com/content/www/us/en/developer/tools/oneapi/onetbb.html。如果您生成 MEX 函数来测试
parfor版本的生成代码,则可以禁用 Intel TBB。将 MEX 配置对象的ExtrinsicCalls属性设置为false。有关详细信息,请参阅coder.MexCodeConfig(MATLAB Coder)。用于穷举搜索算法的 MEX 函数和同时适用于两种算法的独立 C/C++ 代码 -
knnsearch的生成代码使用parfor(MATLAB Coder) 在生成代码中创建在受支持的共享内存多核平台上并行运行的循环。如果您的编译器不支持 Open Multiprocessing (OpenMP) 应用程序接口,或您禁用 OpenMP 库,则 MATLAB Coder™ 会将parfor循环视为for循环。要查找支持的编译器,请参阅支持的编译器。要禁用 OpenMP 库,请将配置对象的EnableOpenMP属性设置为false。有关详细信息,请参阅coder.CodeConfig(MATLAB Coder)。
knnsearch在生成的独立 C/C++ 代码中返回整数类型 (int32) 索引。因此,当您使用单精度输入时,该函数允许严格的单精度支持。对于 MEX 代码生成,该函数仍返回双精度索引以匹配 MATLAB 行为。
有关代码生成的详细信息,请参阅 Introduction to Code Generation 和 General Code Generation Workflow。
用法说明和限制:
NSMethod名称-值参量必须指定为"exhaustive"。IncludeTies和SortIndices名称-值参量必须指定为其默认值。您无法将
Distance名称-值参量指定为"fasteuclidean"或"fastseuclidean"。
有关详细信息,请参阅在 GPU 上运行 MATLAB 函数 (Parallel Computing Toolbox)。
版本历史记录
在 R2010a 中推出MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
选择网站
选择网站以获取翻译的可用内容,以及查看当地活动和优惠。根据您的位置,我们建议您选择:。
您也可以从以下列表中选择网站:
如何获得最佳网站性能
选择中国网站(中文或英文)以获得最佳网站性能。其他 MathWorks 国家/地区网站并未针对您所在位置的访问进行优化。
美洲
- América Latina (Español)
- Canada (English)
- United States (English)
欧洲
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)