我在matlab中有一个已排序的向量,称之为F
,对于这个例子,它说的是:
F = [1,2,3,4,5,6,7,8,9,10];
我还有一个任意矩阵A
,其中0-10区间的元素说:
A = [1.5,9.1,5.2;2.3,0.4,7.9];
然后我对矩阵I
感兴趣,A
中的每个条目告诉我它所属的F
中的哪个区间,在这种情况下作为下限给出:< / p>
I = [1,9,5;2,0,7];
我知道,在这种情况下,它可以通过四舍五入获得,但我正在寻找一般情况。我也有一段代码为我解决了这个问题,即:
I = zeros(size(A));
X(A<F(1)) = 0;
for i = 2:length(F)
X(A<F(i) & A>F(i-1)) = i-1;
end
end
但是,此时,我会检查A
中每个i
的所有条目,即使条目只满足条件一次。
所以我的问题是找到一种更有效的方法来做到这一点。首先要避免多次检查相同的条目,但也可能利用向量F
进行排序。
我也尝试过使用arrayfun(@(a) find(a>=F,1)-1,A);
,但这比上面的逻辑版慢了大约100倍。
有什么建议吗?
答案 0 :(得分:4)
这可以完成这项任务,而且可能非常快:
result = reshape(sum(bsxfun(@lt, F(:), A(:).'), 1), size(A));
我假设间隔被定义为( a , b ]。对于[ a , b )将@lt
替换为@le
。
利用向量排序的事实,做某种binary search可能会更快。 histcounts
可能在内部执行此操作。第三个输出给出了你想要的东西:
[~, ~, result] = histcounts(A, F);
答案 1 :(得分:1)
这是一个适用于float和int输入的解决方案。
超出插值区间范围的值NaN
,因此应该确定在应用插值之前可以使用thode值做什么。
将interp
与选项nearest
一起使用,将最近邻插值应用于数据。
function out = histcount3(v , interval)
%compute center of bins
centers = interval(1:end-1) + diff(interval)/2;
%apply nearest neighbor interpolation
out = interp1(centers,interval(1:end-1),v(:),'nearest');
end
如果间隔是整数类型且间隔范围合理,则可能的快速解决方案是:
function out = histcount2(v , interval)
v= max(interval(1),v);
v=min(interval(end),v);
count= diff(interval);
count(end) = count(end)+1;
r = repelem(interval(1:end-1), count);
out = r(floor(v)-interval(1)+1);
end
和以前一样,应该决定使用超出范围的值可以做些什么。我用最小和最大间隔替换那些valuse。
我在Octave中进行了测试,但Octave没有histcount
为hist
函数的时间,前提是我认为它具有与histcount
相同的算法,但结果不同。您可以使用histcount
运行基准测试以获得正确的结果:
F = unique(randi([1000 100000],1,1000));
A = rand(100000,3)*101000;
disp('------histcount2:--------')
tic
reshape(histcount2(A(:),F),size(A));
toc
disp('------histcount3:--------')
tic
reshape(histcount3(A(:),F),size(A));
toc
disp('------hist:--------')
tic
hist(A(:),F);
toc
disp('------bsxfun:--------')
tic
reshape(sum(bsxfun(@le, F(:), A(:).'), 1), size(A));
toc
<强>结果强>:
------histcount2:repelem--------
Elapsed time is 0.00749207 seconds.
------histcount3:interpolation--------
Elapsed time is 0.042104 seconds.
------hist:--------
Elapsed time is 0.135928 seconds.
------bsxfun:--------
Elapsed time is 0.516705 seconds.
答案 2 :(得分:1)
根据matlab的建议,对@Luis Mendo建议的一点改进应该是使用discretize
。
从文档中https://se.mathworks.com/help/matlab/ref/discretize.html
离散化的行为类似于histcounts函数的行为。使用histcounts查找每个bin中的元素数。另一方面,使用离散化来查找每个元素属于哪个bin(不计算)。
因此将代码行转换为:
I = discretize(A,F)-1;
虽然必须在变量F
中指定最小值。从原始帖子继续我的示例,它会将F
转换为:
F = [0,1,2,3,4,5,6,7,8,9,10];
但是,我的测试结果显示histcounts
一直快一点。