高效算法,用于计算matlab中大量位置的成对距离

时间:2014-09-23 17:36:25

标签: algorithm matlab

我最近在使用matlab计算大量位置的球面距离时遇到了问题。这是问题所在:

1.locations是纬度和经度,存储在尺寸为nx2的矢量位置,其中n = 10 ^ 5.

2.我想计算向量区域中任意两个位置之间的球形距离。请注意,生成的距离矩阵可能稀疏,也可能不稀疏,因为我无法在没有距离的情况下检查它。让我们假设它是稀疏的,因为我们可以用数字截断距离,比如1000.(单位是km),结果距离矩阵足以供我使用。

3.我尝试了两种方法来计算它,但每种方法都有缺点。

PS:我在Mac OS上使用MATLAB 2014学生版运行代码。函数great_circle_distance()非常类似于Matlab内置函数,用于计算具有地理空间坐标的任意两个位置之间的大圆距离。这里的问题与此功能的使用无关。

提前感谢各种建议。

- 光盘

方法一:

dist = zeros(n, 1);
dist_vec = [];
dist_id = [];
dist_id2 = [];
for i =1:n
dist = great_circle_distance(locs(i, :), locs);
dist_temp=(dist<300) &(dist>0);   % for example, consider the distance between 0 and 300
[dist_id_temp, dist_id2_temp,dist_vtemp]=find(dist_temp);
dist_vec_temp=dist(dist_id_temp);
dist_id=[dist_id; dist_id_temp];
dist_id2=[dist_id2; dist_id2_temp];
dist_vec=[dist_vec; dist_vec_temp];

if mod(i, 1000) == 0

    i

end
end
dist_mat = sparse(dist_id, dist_id2, dist_vec);

这里的缺点是需要很长时间才能完成,至少48小时,但它在2-5G左右消耗的内存不会太多。

方法2:

d = pdist(locs, @great_circle_distance);
[i, j] = find(tril(true(n), -1)); % extract index below main diagonal
d = d';
a = [i, j, d];
con = d == 0;   % specify condition. 
a(con, :) = [];   % delete rows satisfying condition con.
clear i j d;
i = a(:, 1);
j = a(:, 2);
d = a(:, 3);
dist_mat = sparse(i, j, d);

这种方法的缺点是在代码中计算d时会占用太多内存(超过15G)。

1 个答案:

答案 0 :(得分:1)

1)方法#1

构建中间变量(数组改变大小等)的方式效率非常低。考虑这种改进的实现:

% given some data (longitude/latitude)
locs = rand(N,2);    % N = 10^5 in your case

% pick an appropriate size (guesstimate the number of nonzeros in the sparse mat)
nzmx = ...;

% compute pairwise-distance matrix (only those satisfying some condition)
D = spalloc(N, N, nzmx);
for i=1:N
    d = great_circle_distance(locs(i,:), locs);
    idx = find(100<d & d<400);   % distances in the range [100,400] km
    D(idx,i) = d(idx);
end

请注意,对于N=10^5条目,double类型的完整距离矩阵将占用:N*N*8个字节,或大约((10^5)^2*8)/2^30 = 74.5 GB个内存(即{g}个千兆字节)!所以很明显我假设你有足够的RAM来保存稀疏矩阵,即使在应用你的条件之后,否则计算不能完全完成(在这种情况下你必须将它分成块,然后计算一块在一次一个)。假设只有5%的矩阵是非零的,那就像4GB的连续内存。因此,您必须在上面的代码中为nzmx选择合适的值。

您提到距离函数great_circle_distance与此处的讨论无关。请确保它已正确矢量化,否则会严重影响性能。

更新:只需填充稀疏矩阵的下半部分就可以实现一个改进:

D = spalloc(N, N, nzmx);
for i=1:N-1
    d = great_circle_distance(locs(i,:), locs(i+1:end,:));
    idx = find(100<d & d<400);
    if isempty(idx), continue; end
    D(idx+i,i) = d(idx);
end

2)方法#2

显然,因为你正在使用pdist,它将计算整个矩阵(只有它的一半)。所以你必须确保你有足够的内存来存储它(根据我的计算大约((N*(N-1)/2)*8)/2^30 = 37.25 GB。)