Performance 对于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和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]
我想到的最快的方法是下面的函数,它没有利用列表被排序的事实,并使用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)]);