Performance 对于X中的每个元素,查找最大的索引,而不必在Y中查找
我正在寻找一种改进以下算法性能的方法。给定两个数组X和Y 对于X的每个元素,找到Y中最大值的索引,该索引不超过X中元素的值。可以安全地假设X和Y单调递增(排序),并且Y(1)小于X中的每个值。 而且X通常比Y大得多 下面给出了一个例子Performance 对于X中的每个元素,查找最大的索引,而不必在Y中查找,performance,matlab,sorting,Performance,Matlab,Sorting,我正在寻找一种改进以下算法性能的方法。给定两个数组X和Y 对于X的每个元素,找到Y中最大值的索引,该索引不超过X中元素的值。可以安全地假设X和Y单调递增(排序),并且Y(1)小于X中的每个值。 而且X通常比Y大得多 下面给出了一个例子 X = [0.2, 1.5, 2.2, 2.5, 3.5, 4.5, 5.5, 5.8, 6.5]; Y = [0.0, 1.0, 3.0, 4.0, 6.0]; 我希望输出是 idx = [1, 2, 2, 2, 3, 4, 4, 4, 5] 我想到的最快的
X = [0.2, 1.5, 2.2, 2.5, 3.5, 4.5, 5.5, 5.8, 6.5];
Y = [0.0, 1.0, 3.0, 4.0, 6.0];
我希望输出是
idx = [1, 2, 2, 2, 3, 4, 4, 4, 5]
我想到的最快的方法是下面的函数,它没有利用列表被排序的事实,并使用for循环单步遍历其中一个数组。这提供了一个有效的解决方案,但在我使用此函数进行的实验中,分析运行总共需要30分钟,其中有将近27分钟的时间
function idx = matchintervals(X,Y)
idx = zeros(size(X));
for i = 1:length(Y)-1
idx(X >= Y(i) & X < Y(i+1)) = i;
end
idx(X >= Y(end)) = length(Y);
end
函数idx=匹配间隔(X,Y)
idx=零(大小(X));
对于i=1:长度(Y)-1
idx(X>=Y(i)&X=Y(结束))=长度(Y);
结束
非常感谢您的帮助。使用
排序
和少量掩码
-
%// Concatenate X and Y and find the sorted indices
[sXY,sorted_id] = sort([X Y]);
%// Take care of sorted_id for identical values between X and Y
dup_id = find(diff(sXY)==0);
tmp = sorted_id(dup_id);
sorted_id(dup_id) = sorted_id(dup_id+1);
sorted_id(dup_id+1) = tmp;
%// Mask of Y elements in XY array
maskY = sorted_id>numel(X);
%// Find island lengths of Y elements in concatenated XY array
diff_maskY = diff([false maskY false]);
island_lens = find(diff_maskY ==-1) - find(diff_maskY ==1);
%// Create a mask of double datatype with 1s where Y intervals change
mask_Ys = [ false maskY(1:end-1)];
mask_Ysd = double(mask_Ys(~maskY));
%// Incorporate island lengths to change the 1s by offsetted island lengths
valid = mask_Ysd==1;
mask_Ysd(valid) = mask_Ysd(valid) + island_lens(1:sum(valid)) - 1;
%// Finally perform cumsum to get the output indices
idx = cumsum(mask_Ysd);
如果您正在寻找最快的解决方案,它可能会像这样以一个简单的while循环结束(这利用了数组被排序的事实):
一行,但可能比gnovice的解决方案慢:
idx = sum(bsxfun(@ge, X, Y'));
我有一个和Divakar相似的想法。这基本上是使用稳定的排序
在Y
的值之后找到X
中的值的插入点。
X
和Y
都需要排序才能正常工作
%// Calculate the entry points
[~,I] = sort([Y,X]);
whereAreXs = I>numel(Y);
idx = find(whereAreXs)-(1:numel(X));
您可以通过以下方式查看X
的值以及不超过X
值的Y
的相应值:
%%// Output:
disp([X;Y(idx)]);
出于好奇,
X
和Y
通常有多大?X大约有100000个元素,Y大约有10000个元素。问题是,大约有大量的数据块大小如此,需要多次运行实验来调整参数。@jodag那么,X
或Y
在这些迭代中是否保持不变?你能跨它们重复使用数据吗?@Divakar No X和Y在迭代之间是独立的。@jodag好的,那么你试过发布的解决方案了吗?@gnovice是的,这是个问题。现在应该通过编辑更正。感谢您提供的基准测试工具。看起来所有答案都给出了有效的解决方案,Divikar、knedlsepp和您的解决方案都非常有效。既然你的是最快的,我就接受它。@jodag:我通过改变初始化索引的方式,使它的速度更快了。这无疑是优雅的,但比gnovice的解决方案慢了一点。@jodag:从理论上讲,gnovice的答案也是如何在低级语言中实现的。现在MATLAB循环的性能相当好,所以这当然是一个好方法。(但是:您测试了哪些数据大小?在gnovice的回答中运行测试数据我的解决方案在我的R2014a机器上执行速度快25%)@knedlsepp:我更新了初始化索引的方式,并将时间缩短了一半以上repmat
似乎效率很低。:)@gnovice:很高兴看到一个实循环方法比所有的矢量化技巧都好。
%// Calculate the entry points
[~,I] = sort([Y,X]);
whereAreXs = I>numel(Y);
idx = find(whereAreXs)-(1:numel(X));
%%// Output:
disp([X;Y(idx)]);