Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

pdist2

两组观测值之间的两两距离

说明

示例

D = pdist2(X,Y,Distance) 使用 Distance 指定的度量返回 XY 中每对观测值之间的距离。

示例

D = pdist2(X,Y,Distance,DistParameter) 使用 DistanceDistParameter 指定的度量返回该距离。仅当 Distance'seuclidean''minkowski''mahalanobis' 时,您才能指定 DistParameter

示例

对于任何以前的参量,D = pdist2(___,Name,Value) 使用名称-值参数修改计算。例如,

  • D = pdist2(X,Y,Distance,'Smallest',K) 使用 Distance 指定的度量计算距离,并以升序返回 X 中观测值与 Y 中每个观测值的前 K 个最小两两距离。

  • D = pdist2(X,Y,Distance,DistParameter,'Largest',K) 使用 DistanceDistParameter 指定的度量计算距离,并以降序返回 K 个最大的两两距离。

示例

[D,I] = pdist2(___) 也返回矩阵 I。矩阵 I 包含与 D 中的距离对应的 X 中的观测值的索引。

示例

全部折叠

创建包含三个观测值和两个变量的两个矩阵。

rng('default') % For reproducibility
X = rand(3,2);
Y = rand(3,2);

计算欧几里德距离。输入参量 Distance 的默认值为 'euclidean'。在不使用名称-值对组参量的情况下计算欧几里德距离时,不需要指定 Distance

D = pdist2(X,Y)
D = 3×3

    0.5387    0.8018    0.1538
    0.7100    0.5951    0.3422
    0.8805    0.4242    1.2050

D(i,j) 对应于 X 中的观测值 iY 中的观测值 j 之间的两两距离。

创建包含三个观测值和两个变量的两个矩阵。

rng('default') % For reproducibility
X = rand(3,2);
Y = rand(3,2);

使用默认指数 2 计算闵可夫斯基距离。

D1 = pdist2(X,Y,'minkowski')
D1 = 3×3

    0.5387    0.8018    0.1538
    0.7100    0.5951    0.3422
    0.8805    0.4242    1.2050

用指数 1 计算闵可夫斯基距离,它等于城市街区距离。

D2 = pdist2(X,Y,'minkowski',1)
D2 = 3×3

    0.5877    1.0236    0.2000
    0.9598    0.8337    0.3899
    1.0189    0.4800    1.7036

D3 = pdist2(X,Y,'cityblock')
D3 = 3×3

    0.5877    1.0236    0.2000
    0.9598    0.8337    0.3899
    1.0189    0.4800    1.7036

创建包含三个观测值和两个变量的两个矩阵。

rng('default') % For reproducibility
X = rand(3,2);
Y = rand(3,2);

Y 中的每个观测值求出 X 中观测值的两个最小的两两欧几里德距离。

[D,I] = pdist2(X,Y,'euclidean','Smallest',2)
D = 2×3

    0.5387    0.4242    0.1538
    0.7100    0.5951    0.3422

I = 2×3

     1     3     1
     2     2     2

对于 Y 中的每个观测值,pdist2 通过计算距离值并将其与 X 中的所有观测值进行比较,求出两个最小的距离。然后,该函数按升序对 D 的每列中的距离进行排序。I 包含与 D 中的距离对应的 X 中的观测值的索引。

创建两个由点组成的大型矩阵,然后测量 pdist2 采用默认的 "euclidean" 距离度量时所用的时间。

rng default % For reproducibility
N = 10000;
X = randn(N,1000);
Y = randn(N,1000);
D = pdist2(X,Y); % Warm up function for more reliable timing information
tic
D = pdist2(X,Y);
standard = toc
standard = 16.2766

接下来,测量 pdist2 采用 "fasteuclidean" 距离度量时所用的时间。指定缓存大小为 100。

D = pdist2(X,Y,"fasteuclidean",CacheSize=100); % Warm up function
tic
D2 = pdist2(X,Y,"fasteuclidean",CacheSize=100);
accelerated = toc
accelerated = 1.7433

计算加速后的计算比标准计算快多少倍。

standard/accelerated
ans = 9.3366

在此示例中,加速版本的速度提高了一倍多。

定义一个忽略 NaN 值坐标的自定义距离函数,并使用该自定义距离函数计算两两距离。

创建包含三个观测值和三个变量的两个矩阵。

rng('default') % For reproducibility
X = rand(3,3)
Y = [X(:,1:2) rand(3,1)]
X =

    0.8147    0.9134    0.2785
    0.9058    0.6324    0.5469
    0.1270    0.0975    0.9575


Y =

    0.8147    0.9134    0.9649
    0.9058    0.6324    0.1576
    0.1270    0.0975    0.9706

X 和 Y 的前两列是相同的。假设缺少 X(1,1)

X(1,1) = NaN
X =

       NaN    0.9134    0.2785
    0.9058    0.6324    0.5469
    0.1270    0.0975    0.9575

计算汉明距离。

D1 = pdist2(X,Y,'hamming')
D1 =

       NaN       NaN       NaN
    1.0000    0.3333    1.0000
    1.0000    1.0000    0.3333

如果 X 中的观测值 iY 中的观测值 j 包含 NaN 值,则对于 ij 之间的两两距离,函数 pdist2 返回 NaN。因此,D1(1,1)、D1(1,2) 和 D1(1,3) 为 NaN 值。

定义一个自定义距离函数 nanhamdist,该函数忽略 NaN 值的坐标并计算汉明距离。当处理大量观测值时,您可以通过遍历数据的坐标来更快地计算距离。

function D2 = nanhamdist(XI,XJ)  
%NANHAMDIST Hamming distance ignoring coordinates with NaNs
[m,p] = size(XJ);
nesum = zeros(m,1);
pstar = zeros(m,1);
for q = 1:p
    notnan = ~(isnan(XI(q)) | isnan(XJ(:,q)));
    nesum = nesum + ((XI(q) ~= XJ(:,q)) & notnan);
    pstar = pstar + notnan;
end
D2 = nesum./pstar; 

将函数句柄作为输入参量传递给 pdist2,以使用 nanhamdist 计算该距离。

D2 = pdist2(X,Y,@nanhamdist)
D2 =

    0.5000    1.0000    1.0000
    1.0000    0.3333    1.0000
    1.0000    1.0000    0.3333

kmeans 执行 k 均值聚类以将数据划分为 k 个簇。当您有要进行聚类的新数据集时,可以使用 kmeans 创建包含现有数据和新数据的新簇。kmeans 函数支持 C/C++ 代码生成,因此您可以生成接受训练数据并返回聚类结果的代码,然后将代码部署到设备上。在此工作流中,您必须传递训练数据,训练数据有可能相当大。为了节省设备上的内存,您可以分别使用 kmeanspdist2 来分离训练和预测。

使用 kmeans 在 MATLAB® 中创建簇,并在生成的代码中使用 pdist2 将新数据分配给现有簇。对于代码生成,定义接受簇质心位置和新数据集的入口函数,并返回最近邻簇的索引。然后,为入口函数生成代码。

生成 C/C++ 代码需要 MATLAB® Coder™。

执行 k 均值聚类

使用三种分布生成训练数据集。

rng('default') % For reproducibility
X = [randn(100,2)*0.75+ones(100,2);
    randn(100,2)*0.5-ones(100,2);
    randn(100,2)*0.75];

使用 kmeans 将训练数据分成三个簇。

[idx,C] = kmeans(X,3);

绘制簇和簇质心。

figure
gscatter(X(:,1),X(:,2),idx,'bgm')
hold on
plot(C(:,1),C(:,2),'kx')
legend('Cluster 1','Cluster 2','Cluster 3','Cluster Centroid')

Figure contains an axes object. The axes object contains 4 objects of type line. One or more of the lines displays its values using only markers These objects represent Cluster 1, Cluster 2, Cluster 3, Cluster Centroid.

将新数据分配给现有簇

生成测试数据集。

Xtest = [randn(10,2)*0.75+ones(10,2);
    randn(10,2)*0.5-ones(10,2);
    randn(10,2)*0.75];

使用现有簇对测试数据集进行分类。使用 pdist2 找到距离每个测试数据点最近的质心。

[~,idx_test] = pdist2(C,Xtest,'euclidean','Smallest',1);

使用 idx_testgscatter 绘制测试数据并对测试数据加标签。

gscatter(Xtest(:,1),Xtest(:,2),idx_test,'bgm','ooo')
legend('Cluster 1','Cluster 2','Cluster 3','Cluster Centroid', ...
    'Data classified to Cluster 1','Data classified to Cluster 2', ...
    'Data classified to Cluster 3')

Figure contains an axes object. The axes object contains 7 objects of type line. One or more of the lines displays its values using only markers These objects represent Cluster 1, Cluster 2, Cluster 3, Cluster Centroid, Data classified to Cluster 1, Data classified to Cluster 2, Data classified to Cluster 3.

生成代码

生成将新数据分配给现有簇的 C 代码。请注意,生成 C/C++ 代码需要 MATLAB® Coder™。

定义名为 findNearestCentroid 的入口函数,该函数接受质心位置和新数据,然后使用 pdist2 找到最近的簇。

在入口函数的函数签名后面添加 %#codegen 编译器指令(即 pragma),以指示您要为此 MATLAB 算法生成代码。添加此指令指示 MATLAB 代码分析器帮助您诊断和修复在代码生成过程中可能导致错误的违规。

type findNearestCentroid % Display contents of findNearestCentroid.m
function idx = findNearestCentroid(C,X) %#codegen
[~,idx] = pdist2(C,X,'euclidean','Smallest',1); % Find the nearest centroid

注意:如果您点击位于此页右上角的按钮,并在 MATLAB® 中打开此示例,则 MATLAB® 将打开示例文件夹。该文件夹包括入口函数文件。

使用 codegen (MATLAB Coder) 生成代码。由于 C 和 C++ 是静态类型语言,因此必须在编译时确定入口函数中所有变量的属性。要指定 findNearestCentroid 的输入的数据类型和数组大小,请使用 -args 选项传递表示具有特定数据类型和数组大小的值集的 MATLAB 表达式。有关详细信息,请参阅 Specify Variable-Size Arguments for Code Generation

codegen findNearestCentroid -args {C,Xtest}
Code generation successful.

codegen 生成 MEX 函数 findNearestCentroid_mex,扩展名因平台而异。

验证生成的代码。

myIndx = findNearestCentroid(C,Xtest);
myIndex_mex = findNearestCentroid_mex(C,Xtest);
verifyMEX = isequal(idx_test,myIndx,myIndex_mex)
verifyMEX = logical
   1

isequal 返回逻辑值 1 (true),这意味着所有输入都相等。这一比较结果确认 pdist2 函数、findNearestCentroid 函数和 MEX 函数均返回相同的索引。

您还可以使用 GPU Coder™ 生成优化的 CUDA® 代码。

cfg = coder.gpuConfig('mex');
codegen -config cfg findNearestCentroid -args {C,Xtest}

有关代码生成的详细信息,请参阅General Code Generation Workflow。有关 GPU Coder 的详细信息,请参阅Get Started with GPU Coder (GPU Coder)Supported Functions (GPU Coder)

输入参数

全部折叠

输入数据,指定为数值矩阵。X 是一个 mx×n 矩阵,而 Y 是一个 my×n 矩阵。行对应于单个观测值,列对应单个变量。

数据类型: single | double

距离度量,指定为字符向量、字符串标量或函数句柄,如下表中所述。

描述
'euclidean'

欧几里德距离(默认值)

'squaredeuclidean'

平方欧几里德距离。(此选项仅用于提高效率。它不满足三角不等式。)

'seuclidean'

标准化的欧几里德距离。每个观测值间坐标差都通过除以标准差 S = std(X,'omitnan') 中的对应元素来缩放。使用 DistParameterS 指定不同值。

'fasteuclidean'当预测变量的数目至少为 10 时,使用替代算法计算的欧几里德距离,该算法可以节省时间。在某些情况下,这种更快的算法会降低准确度。以 'fast' 开头的算法不支持稀疏数据。有关详细信息,请参阅 算法
'fastsquaredeuclidean'当预测变量的数目至少为 10 时,使用替代算法计算的平方欧几里德距离,该算法可以节省时间。在某些情况下,这种更快的算法会降低准确度。以 'fast' 开头的算法不支持稀疏数据。有关详细信息,请参阅 算法
'fastseuclidean'当预测变量的数目至少为 10 时,使用替代算法计算的标准化的欧几里德距离,该算法可以节省时间。在某些情况下,这种更快的算法会降低准确度。以 'fast' 开头的算法不支持稀疏数据。有关详细信息,请参阅 算法
'mahalanobis'

马氏距离,使用 X 的样本协方差 C = cov(X,'omitrows') 计算。使用 DistParameterC 指定一个不同值,其中矩阵 C 是对称正定矩阵。

'cityblock'

城市街区距离

'minkowski'

闵可夫斯基距离。默认指数是 2。使用 DistParameter 指定其他指数 P,其中 P 是表示指数的正标量值。

'chebychev'

切比雪夫距离(最大坐标差)

'cosine'

1 减去点之间夹角的余弦值(视为向量)

'correlation'

1 减去点之间的样本相关性(视为值序列)

'hamming'

汉明距离,即相异坐标所占的百分比

'jaccard'

1 减去杰卡德系数,即非零相异坐标所占的百分比

'spearman'

1 减去样本观测值之间的斯皮尔曼秩相关(视为值序列)

@distfun

自定义距离函数句柄。距离函数的形式如下

function D2 = distfun(ZI,ZJ)
% calculation of distance
...
其中

  • ZI 是包含单个观测值的 1×n 向量。

  • ZJ 是包含多个观测值的 m2×n 矩阵。distfun 必须接受具有任意数目的观测值的矩阵 ZJ

  • D2 是距离的 m2×1 向量,D2(k) 是观测值 ZIZJ(k,:) 之间的距离。

对于非稀疏数据,使用内置距离度量计算距离通常比使用函数句柄更快。

有关定义,请参阅距离度量

当您使用 'seuclidean''minkowski''mahalanobis' 时,您可以指定额外的输入参量 DistParameter 来控制这些度量。您也可以像使用其他度量一样来使用这些度量,但这种情况下使用的是 DistParameter 的默认值。

示例: 'minkowski'

数据类型: char | string | function_handle

距离度量参数值,指定为正标量、数值向量或数值矩阵。仅当您将 Distance 指定为 'seuclidean''minkowski''mahalanobis' 时,此参量才有效。

  • 如果 Distance'seuclidean'DistParameter 是对应于每个维度的缩放因子的向量,指定为正向量。默认值为 std(X,'omitnan')

  • 如果 Distance'minkowski'DistParameter 是闵可夫斯基距离的指数,指定为正标量。默认值为 2。

  • 如果 Distance'mahalanobis'DistParameter 是协方差矩阵,指定为数值矩阵。默认值为 cov(X,'omitrows')DistParameter 必须是对称正定矩阵。

示例: 'minkowski',3

数据类型: single | double

名称-值参数

将可选的参量对组指定为 Name1=Value1,...,NameN=ValueN,其中 Name 是参量名称,Value 是对应的值。名称-值参量必须出现在其他参量后,但参量对组的顺序无关紧要。

在 R2021a 之前,使用逗号分隔每个名称和值,并用引号将 Name 引起来。

示例: 或者使用 'Smallest',K,或者使用 'Largest',K。但您不能同时使用 'Smallest''Largest'

格拉姆矩阵的大小,以 MB 为单位,指定为正标量或 'maximal'。仅当 Distance 参量以 fast 开头时,pdist2 函数才能使用 CacheSize

如果是 'maximal'pdist2 尝试为大小为 MX×MY 的整个中间矩阵分配足够的内存,其中 MX 是输入数据 X 的行数,MY 是输入数据 Y 的行数。高速缓存的大小不必大到足以容纳整个中间矩阵,但必须至少大到足以容纳一个 MX×1 向量。否则,pdist2 使用常规算法来计算欧几里德距离。

如果距离参量以 fast 开头,并且 CacheSize 太大或为 'maximal',则 pdist2 可能会尝试分配超出可用内存的格拉姆矩阵。在这种情况下,MATLAB® 会引发错误。

示例: CacheSize='maximal'

数据类型: double | char | string

要求出的最小距离的数目,指定为由 'Smallest' 和一个正整数组成的以逗号分隔的对组。如果指定 'Smallest',则 pdist2 以升序对 D 的每列中的距离进行排序。您只能使用参量 SmallestLargest 之一。

示例: 'Smallest',3

数据类型: single | double

要求出的最大距离的数目,指定为由 'Largest' 和一个正整数组成的以逗号分隔的对组。如果指定 'Largest',则 pdist2 以降序对 D 的每列中的距离进行排序。您只能使用参量 SmallestLargest 之一。

示例: 'Largest',3

数据类型: single | double

输出参数

全部折叠

两两距离,以数值矩阵形式返回。

如果未指定 'Smallest''Largest',则 D 是 mx×my 矩阵,其中 mx 和 my 分别是 XY 中的观测值数目。D(i,j)X 中的观测值 iY 中的观测值 j 之间的距离。如果 X 中的观测值 i 或 Y 中的观测值 j 包含 NaN,则内置距离函数返回的 D(i,j)NaN

如果将 'Smallest''Largest' 指定为 K,则 DK×my 矩阵。D 包含 Y 中每个观测值到 X 中观测值的 K 个最小或 K 个最大两两距离。对于 Y 中的每个观测值,pdist2 通过计算并比较其与 X 中所有观测值的距离值,求出 K 个最小或最大距离。如果 K 大于 mx,则 pdist2 返回一个 mx×my 矩阵。

排序索引,以正整数矩阵形式返回。ID 的大小相同。I 包含与 D 中的距离对应的 X 中的观测值的索引。

详细信息

全部折叠

距离度量

距离度量是定义两个观测值之间距离的函数。pdist2 支持各种距离度量:欧几里德距离、标准化的欧几里德距离、马氏距离、城市街区距离、闵可夫斯基距离、切比雪夫距离、余弦距离、相关性距离、汉明距离、杰卡德距离和斯皮尔曼距离。

给定一个 mx×n 数据矩阵 X(它被视为 mx 个 (1×n) 的行向量 x1、x2、...、xmx)和一个 my×n 数据矩阵 Y(它被视为 my 个 (1×n) 的行向量 y1、y2、...、ymy),则向量 xs 和 yt 之间的各种距离定义如下:

  • 欧几里德距离

    dst2=(xsyt)(xsyt).

    欧几里德距离是闵可夫斯基距离的特例,其中 p = 2

    通过将 Distance 参数设置为 'euclidean' 可指定欧几里德距离。

  • 标准化的欧几里德距离

    dst2=(xsyt)V1(xsyt),

    其中 V 是 n×n 对角矩阵,它的第 j 个对角线元素是 (S(j))2,其中 S 是对应于每个维度的缩放因子的向量。

    通过将 Distance 参数设置为 'seuclidean' 可指定标准化的欧几里德距离。

  • 快速欧几里德距离与欧几里德距离相同,只是当预测变量的数目至少为 10 时会使用替代算法进行计算,该算法可以节省时间。在某些情况下,这种更快的算法会降低准确度。不支持稀疏数据。请参阅 快速欧几里德距离算法

    通过将 Distance 参数设置为 'fasteuclidean' 可指定快速欧几里德距离。

  • 快速标准化的欧几里德距离与标准化的欧几里德距离相同,只是当预测变量的数目至少为 10 时会使用替代算法进行计算,该算法可以节省时间。在某些情况下,这种更快的算法会降低准确度。不支持稀疏数据。请参阅 快速欧几里德距离算法

    通过将 Distance 参数设置为 'fastseuclidean' 可指定快速标准化的欧几里德距离。

  • 马氏距离

    dst2=(xsyt)C1(xsyt),

    其中 C 是协方差矩阵。

    通过将 Distance 参数设置为 'mahalanobis' 可指定马氏距离。

  • 城市街区距离

    dst=j=1n|xsjytj|.

    城市街区距离是闵可夫斯基距离的特例,其中 p = 1

    通过将 Distance 参数设置为 'cityblock' 可指定城市街区距离。

  • 闵可夫斯基距离

    dst=j=1n|xsjytj|pp.

    对于特例 p = 1,闵可夫斯基距离即城市街区距离。对于特例 p = 2,闵可夫斯基距离即欧几里德距离。对于特例 p = ∞,闵可夫斯基距离即切比雪夫距离。

    通过将 Distance 参数设置为 'minkowski' 可指定闵可夫斯基距离。

  • 切比雪夫距离

    dst=maxj{|xsjytj|}.

    切比雪夫距离是闵可夫斯基距离的特例,其中 p = ∞

    通过将 Distance 参数设置为 'chebychev' 可指定切比雪夫距离。

  • 余弦距离

    dst=(1xsyt(xsxs)(ytyt)).

    通过将 Distance 参数设置为 'cosine' 可指定余弦距离。

  • 相关性距离

    dst=1(xsx¯s)(yty¯t)(xsx¯s)(xsx¯s)(yty¯t)(yty¯t),

    其中

    x¯s=1njxsj

    y¯t=1njytj.

    可通过将 Distance 参数设置为 'correlation' 可指定相关性距离。

  • 汉明距离是相异坐标所占的百分比:

    dst=(#(xsjytj)/n).

    通过将 Distance 参数设置为 'hamming' 可指定汉明距离。

  • 杰卡德距离是 1 减去杰卡德系数,即非零相异坐标所占的百分比:

    dst=#[(xsjytj)((xsj0)(ytj0))]#[(xsj0)(ytj0)].

    通过将 Distance 参数设置为 'jaccard' 可指定杰卡德距离。

  • 斯皮尔曼距离是 1 减去样本观测值之间的斯皮尔曼秩相关(视为值序列):

    dst=1(rsr¯s)(rtr¯t)(rsr¯s)(rsr¯s)(rtr¯t)(rtr¯t),

    其中

    • rsj 是对 x1j、x2j、...xmx,j 应用 tiedrank 计算所得的 xsj 的秩。

    • rtj 是对 y1j、y2j、...ymy,j 应用 tiedrank 计算所得的 ytj 的秩。

    • rs 和 rt 是 xs 和 yt 的基于坐标轴的秩向量,即 rs = (rs1, rs2, ... rsn) 且 rt = (rt1, rt2, ... rtn)。

    • r¯s=1njrsj=(n+1)2.

    • r¯t=1njrtj=(n+1)2.

    通过将 Distance 参数设置为 'spearman' 可指定斯皮尔曼距离。

算法

全部折叠

快速欧几里德距离算法

fast 开头的 Distance 参量(如 'fasteuclidean''fastseuclidean')的值在计算欧几里德距离时使用的算法会使用额外的内存来节省计算时间。此算法在 Albanie 的文献 [1] 中和其他位置称为“欧几里德距离矩阵技巧”。内部测试表明,当预测变量的数目至少为 10 时,该算法可以节省时间。以 'fast' 开头的算法不支持稀疏数据。

为了求得所有点 xi 和 xj 之间距离的矩阵 D(其中每个 xi 具有 n 个变量),该算法使用以下方程中的最后一行来计算距离:

Di,j2=xixj2=(xixj)T(xixj)=xi22xiTxj+xj2.

方程最后一行中的矩阵 xiTxj 称为格拉姆矩阵。当您计算并使用格拉姆矩阵而不是通过平方与求和来计算平方距离时,计算平方距离集的速度更快,但在数值上稳定性稍差。有关讨论,请参阅 Albanie 的文献 [1]

为了存储格拉姆矩阵,软件使用默认大小为 1e3 MB 的缓存。您可以使用 CacheSize 名称-值参量设置缓存大小。如果 CacheSize 的值太大或为 "maximal"pdist2 可能会尝试分配超出可用内存容量的格拉姆矩阵。在这种情况下,MATLAB 会引发错误。

参考

[1] Albanie, Samuel. Euclidean Distance Matrix Trick. June, 2019. Available at https://www.robots.ox.ac.uk/%7Ealbanie/notes/Euclidean_distance_trick.pdf.

扩展功能

版本历史记录

在 R2010a 中推出

全部展开