【问题标题】:MATLAB: search for elements in an array matching multidimensional conditionMATLAB:在匹配多维条件的数组中搜索元素
【发布时间】:2014-05-25 16:08:55
【问题描述】:

我有一个实数列向量 (V1),例如:

123.2100
125.1290
...
954.2190

如果我在这个向量中的每一行添加一个数字 1,我将得到 (V2):

124.2100
126.1290
...
955.2190

我需要找出有多少来自 V2 的元素在从 V1 创建的某个错误窗口中。例如 error-window = 0.1 (但在我的情况下,V1 中的每个元素都有自己的错误窗口):

123.1100 123.3100
125.0290 125.2290
...
954.1190 954.3190

我可以创建一些这样的代码:

% x - my vector
% ppm - a variable responsible for error-window
window = [(1-(ppm/1000000))*x, (1+(ppm/1000000))*x]; % - error-window
mdiff = 1:0.001:20; % the numbers I will iteratively add to x 
                    % (like the number 1 in the example)
cdiff = zeros(length(mdiff),1); % a vector that will contain counts of elements
                                % corresponding to different mdiff temp = 0;

for i = 1:length(mdiff)
    for j = 1:size(window,1)
        xx = x + mdiff(i);
        indxx = find( xx => window(j,1) & xx <= window(j,2) );
        if any(indxx)
            temp = temp + length(indxx); %edited
        end
    end
    cdiff(i) = temp;
    temp = 0;
end

因此,最后 cdiff 将包含与 mdiff 对应的所有计数。唯一的事情,我想让代码更快。或者有没有办法避免使用第二个循环(带j)?我的意思是直接使用多维条件。

编辑

我决定像这样简化代码(感谢我在这里得到的反馈):

% x - my vector
% ppm - a variable responsible for error-window
window = [(1-(ppm/1000000))*x, (1+(ppm/1000000))*x]; % - error-window
mdiff = 1:0.001:20; % the numbers I will iteratively add to x 
                    % (like the number 1 in the example)
cdiff = zeros(length(mdiff),1); % a vector that will contain counts of elements
                                % corresponding to different mdiff temp = 0;

for i = 1:length(mdiff)
    xx = x + mdiff(i);
    cdiff(i) = sum(sum(bsxfun(@and,bsxfun(@ge,xx,window(:,1)'),bsxfun(@le,xx,window(:,2)'))));
end

在这种情况下,代码运行得更快并且看起来正确

【问题讨论】:

  • 我相信您可以使用二进制搜索之类的方法来避免进行所有 n² 次迭代。先对V1进行排序,然后对每一个V2,与V1的中项进行比较,看是高于还是低于它。如果它较低,则无需检查 V1 的上半部分。继续下去,直到找到匹配项,或者直到你用完候选人
  • 一些小cmets:不用find,直接用if any(xx &lt;= ... &amp; xx &gt;= ...)即可。接下来,将xx = ... 移动到第二个for 循环之前,因为它不会随着j 而改变。您更大的问题是您的算法需要O(n * m^2) 时间,其中n = length(mdiff)m = length(x)
  • @BasSwinckels 感谢您的评论
  • @Kirill 确保 EDIT 代码与原始代码相比产生匹配值。
  • @Divakar,是的,它产生了。在我的原始版本中,我唯一需要改变的是不要使用temp = temp + 1,而是使用temp = temp + length(indxx)。感谢您的帮助!

标签: arrays matlab conditional-statements


【解决方案1】:
add = 1; %// how much to add
error = .1; %// maximum allowed error

V2 = V1 + add; %// build V2   
ind = sum(abs(bsxfun(@minus, V1(:).', V2(:)))<error)>1; %'// index of elements
%// of V1 satisfying the maximum error condition. ">1" is used to because each 
%// element is at least equal to itself
count = nnz(ind);

【讨论】:

  • 为了检查是否在那个窗口中,你不应该检查V1 - add的大小写吗?
  • 我要做的是检查 abs(V1-V2)bsxfun-wise)。我认为这就够了,不是吗?
  • @LuisMendo V1 中的每个元素都有自己的错误术语。在这种情况下,t 将具有与 V1 相同的维度。就是这种情况,我想检查 V2 中的某些元素是否落在从 V1 创建的任何窗口内。
【解决方案2】:

认为这可能对你有用 -

%%// Input data
V1 = 52+rand(4,1)

V2 = V1+1;
t= 0.1;

low_bd = any(abs(bsxfun(@minus,V2,[V1-t]'))<t,2); %%//'
up_bd = any(abs(bsxfun(@minus,V2,[V1+t]'))<t,2); %%//'
count = nnz( low_bd | up_bd )

也可以写成-

diff_map = abs(bsxfun(@minus,[V1-t V1+t],permute(V2,[3 2 1])));
count = nnz(any(any(diff_map<t,2),1))

编辑 1:

low_bd = any(abs(bsxfun(@minus,V2,window(:,1)'))<t,2); %%//'
up_bd = any(abs(bsxfun(@minus,V2,window(:,2)'))<t,2); %%//'
count = nnz( low_bd | up_bd )

编辑 2:已编辑代码的矢量化形式

t1 = bsxfun(@plus,x,mdiff);
d1 = bsxfun(@ge,t1,permute(window(:,1),[3 2 1]));
d2 = bsxfun(@le,t1,permute(window(:,2),[3 2 1]));
t2 = d1.*d2;
cdiff_vect = max(sum(t2,3),[],1)';

【讨论】:

  • 在我的情况下,错误项 't' 作为 V1 中值的函数而变化: window = [(1-(ppm/1000000))*x, (1+(ppm/ 1000000))*x]
  • @Kirill 那么我可以假设t 的长度与V1 相同吗?
  • V1 中的每个元素都有自己的错误范围:window = [(1-(ppm/1000000))*x, (1+(ppm/1000000))*x]乙>。在这种情况下,我会显示错误窗口。如果这些窗户里面有东西,我必须数一数。
  • Divakar,是的,没错。抱歉,我的问题没有具体说明
  • @Kirill 查看编辑 1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
  • 2015-05-13
  • 1970-01-01
  • 1970-01-01
  • 2021-01-18
相关资源
最近更新 更多