目前我在Matlab中使用pdist
函数来计算三维笛卡尔系统中各点之间的欧几里德距离。我这样做是因为我想知道哪个点与所有其他点(medoid)的平均距离最小。 pdist
的语法如下所示:
% calculate distances between all points
distances = pdist(m);
但是因为pdist返回一维距离数组,所以没有简单的方法来确定哪个点具有最小的平均距离(直接)。这就是我使用squareform
然后计算最小平均距离的原因,如下所示:
% convert found distances to matrix of distances
distanceMatrix = squareform(distances);
% find index of point with smallest average distance
[~,j] = min(mean(distanceMatrix,2));
每列的距离是平均值,变量j
是平均距离最小的列(和点)的索引。
这是有效的,但是方形需要花费很多时间(这段代码重复了数千次),所以我正在寻找一种优化它的方法。 是否有人知道以pdist
的结果与平均距离最小的方式推断点的更快方法?
答案 0 :(得分:3)
我认为使用SQUAREFORM函数的任务是从矢量化视点开始的最佳方法。如果您通过
查看此功能的内容edit squareform
你会发现它执行了很多检查,当然需要花费时间。既然你知道你对方形的输入并且可以确定它是可行的,那么你可以用squareform的核心来创建你的自定义函数。
[r, c] = size(m);
distanceMatrix = zeros(r);
distanceMatrix(tril(true(r),-1)) = distances;
distanceMatrix = distanceMatrix + distanceMatrix';
然后运行与查找medioid相同的代码。
答案 1 :(得分:1)
这是一个不需要调用方形的实现:
N1 = 10;
dim = 5;
% generate points
X = randn(N1, dim);
% find mean distance
for iter=N1:-1:1
d_mean(iter) = mean(pdist2(X(iter,:),X([1:(iter-1) (iter+1):end],:),'euclidean'));
% D(iter,:) = pdist2(X(iter,:),X([1:(iter-1) (iter+1):end],:),'euclidean');
end
[val ind] = min(d_mean);
但是在不了解您的问题的情况下,我不知道它是否会更快。
如果这是您的程序性能的关键,您可能需要考虑其他加速选项,如mex。
祝你好运。答案 2 :(得分:1)
当pdist计算观察对之间的距离(1,2,...,n)时,距离按以下顺序排列:
(2,1),(3,1),...,(m,1),(3,2),...,(m,2),...,(m,m- 1))
为了证明这一点,请尝试以下方法:
> X = [.2 .1 .7 .5]';
> D = pdist(X)
.1 .5 .3 .6 .4 .2
在此示例中,X存储n = 4个观测值。结果D是观测值(2,1),(3,1),(4,1),(3,2),(4,2),(5,4)之间距离的矢量。该布置对应于以下n×n矩阵的下三角部分的条目:
M =
0 0 0 0
.1 0 0 0
.5 .6 0 0
.3 .4 .2 0
请注意,D( 1 )= M( 2,1 ),D( 2 )=( 3,1 )等等。因此,获得M中与D(k)对应的索引对的一种方法是计算M中D(k)的linear index。这可以通过以下方式完成:
% matrix size
n = 4;
% r(j) is the no. of elements in cols 1..j, belonging to the upper triangular part
r = cumsum(1:n-1);
% p(j) is the no. elements in cols 1..j, belonging to the lower triangular part
p = cumsum(n-1:-1:1);
% The linear index of value D(k)
q = find(p >= k, 1);
% The subscript indices of value D(k)
[i j] = ind2sub([n n], k + r(q));
请注意,n,r和p只需设置一次。从那时起,您可以使用最后两行找到任何给定k的索引。我们来看看:
for k = 1:6
q = find(p >= k, 1);
[i, j] = ind2sub([n n], k + r(q));
fprintf('D(%d) is the distance between observations (%d %d)\n', k, i, j);
end
这是输出:
D(1)是观测值(2 1)之间的距离
D(2)是观测值(3 1)之间的距离
D(3)是观测值(4 1)之间的距离
D(4)是观察之间的距离(3 2)
D(5)是观察之间的距离(4 2)
D(6)是观察之间的距离(4 3)
答案 3 :(得分:0)
无需使用squareform
:
distances = pdist(m);
l=length(distances);
n=(1+sqrt(1+4*l))/2;
m=[];
for i=1:n
idx=[1+i:n:length(distances)];
m(i)=mean(distances(idx));
end
j=min(m);
我不确定,但也许这也可以矢量化,但现在已经很晚了。