检查坐标是否在另一个矩阵中任何点的给定距离内

时间:2017-09-27 09:27:40

标签: matlab performance matrix distance

在Matlab中,我有两个包含坐标的大矩阵(A和B)。两条线代表x和y,每列代表一个笛卡尔坐标(x; y)。

现在我想将矩阵B中距离小于1(米)的所有点存储到矩阵A中任意点的新矩阵中。

我可以遍历所有数据,但这非常耗时(矩阵是2x800000)。

有没有办法提升表现?

这是我当前代码的结构:

new_vec = [0;0];
for i=1:length(A)
    cur_x = A(1, i);
    cur_y = A(2, i);

    for j=1:length(B)
        if B(2, j) <= cur_y + 1 && B(2, j) >= cur_y - 1 && ...
               B(1, j) <= cur_x + 1 && B(1, j) >= cur_x - 1
            new_vec = [new_vec, [B(1, j); B(2, j)]];
        end
    end
end

3 个答案:

答案 0 :(得分:3)

另一种选择是使用pdist2,如下所示:

new_vec = B(:, any(pdist2(A', B', 'Chebychev') < 1, 1));

请注意,pdist2总是比您的方法更快,但可能比Wolfie的建议慢,因为pdist2始终计算A的所有点之间的所有距离B

<强>比较

我会比较:

  • 原始:您在答案中提供的代码
  • 优化:Wolfie提供的代码
  • pdist2 :我的解决方案使用pdist2
  • bsxfun :rahnema1的回答
  • bsxfun(&gt; = 2016b):rahnema1使用新2016b功能的答案

使用以下示例数据

A = rand(2, N)*N*relativeAmplitude;
B = rand(2, N)*N*relativeAmplitude;

NrelativeAmplitude=1的执行时间: enter image description here

relativeAmplitudeN=10000的执行时间: enter image description here

<强>结论

所有解决方案(Wolfie&#39; s,rahnema1&mine和我的)都比原始算法快。

优化(Wolfie)vs pdist2(我的):如果B中可能找到A的索引,那么Wolfie&# 39;答案可能快50倍,但如果不太可能,pdist可能会快50%。请注意,我的解决方案的执行时间与relativeAmplitude无关,而沃尔夫不是,但在某些情况下,沃尔夫的回答可能会快得多。

bsxfun(rahnema1)vs pdist2(我的):如果没有新的R2016b功能,bsxfun总是比{{1}慢约50% ,否则两种方法总是(几乎)同样快。

答案 1 :(得分:2)

基于当前实施的性能改进

% Appending is bad practise for memory management, you should initialise the 
% entire output array at first.
new_vec = NaN(size(B));
% You should not use i as a loop variable, since you are overwriting the default i=sqrt(-1)
% Also length(A)=max(size(A)), clearer to use size(A,2)

% Loops have been swapped as we want to exit the *A* looping when satisfied
for jj=1:size(B,2)
    % No need to re-assign current variables each loop, waste of time/memory

    % Same as before, j also is sqrt(-1) by default!
    % We could remove this loop entirely using vectorization, but it's likely quicker to
    % loop *until the condition is satisfied* then exit the loop early, avoiding many ops.
    for ii=1:size(A,2)
        % We can *half* the number of logical operations by using the abs distance!
        if abs(B(2,jj)-A(2,ii)) <= 1 && abs(B(1,jj) - A(1,ii)) <= 1
            % We pre-allocated, so no need to append - use direct indexing
            new_vec(:,jj) = B(:,jj);
            % Now the condition is satisfied for B(:,jj), exit the jj loop!
            break;
        end
    end
end
% We initialised an array of NaNs, remove the columns which are still NaN
new_vec(:, isnan(new_vec(1,:))) = [];

亮点:

  • 最佳做法:不要使用ij作为循环变量,它们的默认值为sqrt(-1)
  • Pre-allocate memory, don't append results during looping
  • 使用abs进行绝对距离检查,减少逻辑检查次数。
  • 当您不必要时,不要在每个循环中分配临时变量。
  • 因为当给定的B坐标位于任何 A坐标的距离内时,您很高兴,提前退出循环以避免更进一步检查。

初始化NaN的2D数组的一种(可能更加内存友好的)替代方法是初始化布尔false数组,然后在每个满意的jj索引处使其成立。最后,我们会new_vec = B(:,booleanVector);

答案 2 :(得分:1)

这是一个矢量化解决方案:

export class MyHeaderComponent {

construct(){ }
 private arr:string[]=['az'];
calendarOptions = {
    events :[],
         //click on day make event
    dayClick(date, jsEvent, view) {}  ,  
    renderEvents(event, element, view  ){}
}          


ngOnInit() {
    let newEvents = [
  {
    title: 'name b',
    start: '2017-09-20'
  },
  {
    title: 'name c',
    start: '2017-09-20'
  },
  {
    title: 'name d',
    start: '2017-09-20'
  }
];
    this.calendarOptions.events = newEvents;

    //callback function
    this.calendarOptions.dayClick = (date,jsEv,vie) => {
        let abc:string ='a';
        //abc = prompt('Enter Title'); 
        let dat = date.format()
        let hamz ={
            title:abc,
            start:dat
        };
        console.log(hamz);
        newEvents.push(hamz);
        this.calendarOptions.events = newEvents;
        console.log(this.calendarOptions.events);
        this.calendarOptions.events = newEvents;
        $("#myCalendar").fullCalendar('renderEvents', 
                                        newEvents, 
                                        true //we want to stick it
                                   );
        alert('ok')
      }
   }
}

从MATLAB r2016b开始,您可以将cur_x = A(1,:); cur_y = A(2,:); B1= reshape(B(1,:),[],1); B2= reshape(B(2,:),[],1); condition = abs(bsxfun(@minus,B2,cur_y))<=1 & ... abs(bsxfun(@minus,B1,cur_x))<=1; [x ,~]=find(condition); new_vec = [[0;0] B(:,x)]; 写为:

condition

condition = abs(B2-cur_y)<=1 & ...
            abs(B1-cur_x)<=1;
从@Wolfie回答condition = B2 <= cur_y + 1 & B2 >= cur_y - 1 & ... B1 <= cur_x + 1 & B1 >= cur_x - 1; 被盗的想法。