我有一个名为l的矩阵,大小为20X3。 我想做的是这样的: 假设我有这个限制:
l1_max=20; l1_min=0.5;
l2_max=20; l2_min=0.5;
mu_max=20; mu_min=0.5;
我想强制矩阵l的所有元素都在限制范围内。 l1_max&中第1列的值l1_min。 l2_max&中第2列的值l2_min。 mu_max&中第3列的值。 mu_min。
我做的是这样的:
for k=1:20
if l(k,1)>l1_max
l(k,1) = l1_max;
elseif l(k,1)<l1_min
l(k,1) = l1_min;
end
if l(k,2)>l2_max
l(k,2) = l2_max;
elseif l(k,2)<l2_min
l(k,2) = l2_min;
end
if l(k,3)>mu_max
l(k,3) = mu_max;
elseif l(k,3)<mu_min
l(k,3) = mu_min;
end
end
能以更好的方式完成吗?
答案 0 :(得分:4)
您不必遍历行,在整个列上使用矢量化操作:
l(l(:, 1) > l1_max, 1) = l1_max;
l(l(:, 1) < l1_min, 1) = l1_min;
相若方式:
l(l(:, 2) > l2_max, 2) = l2_max;
l(l(:, 2) < l2_min, 2) = l2_min;
l(l(:, 3) > l2_max, 3) = mu_max;
l(l(:, 3) < l2_min, 3) = mu_min;
一种类似于Bas的想法的替代方法是应用min
和max
,如下所示:
l(:, 1) = max(min(l(:, 1), l1_max), l1_min);
l(:, 2) = max(min(l(:, 2), l2_max), l2_min);
l(:, 3) = max(min(l(:, 3), mu_max), mu_min);
两种方法似乎都具有可比性。
答案 1 :(得分:2)
您甚至不必遍历所有列,整个矩阵上的操作可以在bsxfun
的2次调用中完成,与列数无关:
column_max = [l1_max, l2_max, mu_max];
column_min = [l1_min, l2_min, mu_min];
M = bsxfun(@min, M, column_max); %clip to maximum
M = bsxfun(@max, M, column_min); %clip to minimum
这使用两个技巧:剪切 min_val和max_val之间的值,你可以clipped_x = min(max(x, min_val), max_val)
。另一个技巧是使用稍微模糊的bsxfun
,它在执行单例扩展之后应用一个函数。当你在两个矩阵上使用它时,它会在应用函数之前将最小的一个“挤出”到与最大的矩阵相同的大小,因此上面的示例等同于M = min(M, repmat(column_max, size(M, 1), 1))
,但希望以更有效的方式计算。
答案 2 :(得分:1)
以下是测试目前讨论的各种方法的基准。我正在使用文件交换中的TIMEIT函数。
function [t,v] = testClampColumns()
% data and limits ranges for each column
r = 10000; c = 500;
M = randn(r,c);
mn = -1.1 * ones(1,c);
mx = +1.1 * ones(1,c);
% functions
f = { ...
@() clamp1(M,mn,mx) ;
@() clamp2(M,mn,mx) ;
@() clamp3(M,mn,mx) ;
@() clamp4(M,mn,mx) ;
@() clamp5(M,mn,mx) ;
};
% timeit and check results
t = cellfun(@timeit, f, 'UniformOutput',true);
v = cellfun(@feval, f, 'UniformOutput',false);
assert(isequal(v{:}))
end
鉴于以下实施:
function M = clamp1(M, mn, mx)
for j=1:size(M,2)
for i=1:size(M,1)
if M(i,j) > mx(j)
M(i,j) = mx(j);
elseif M(i,j) < mn(j)
M(i,j) = mn(j);
end
end
end
end
function M = clamp2(M, mn, mx)
for j=1:size(M,2)
M(M(:,j) < mn(j), j) = mn(j);
M(M(:,j) > mx(j), j) = mx(j);
end
end
function M = clamp3(M, mn, mx)
for j=1:size(M,2)
M(:,j) = min(max(M(:,j), mn(j)), mx(j));
end
end
function M = clamp4(M, mn, mx)
M = bsxfun(@min, bsxfun(@max, M, mn), mx);
end
(注意:这不适用于您的情况,因为它需要一个对称的限制范围。我只是为了完整性而包括它。此外它被证明是最慢的方法。)
function M = clamp5(M, mn, mx)
assert(isequal(-mn,mx), 'Only works when -mn==mx')
idx = bsxfun(@gt, abs(M), mx);
v = bsxfun(@times, sign(M), mx);
M(idx) = v(idx);
end
我的机器上有一个大小为10000x500的输入矩阵的时间:
>> t = testClampColumns
t =
0.2424
0.1267
0.0569
0.0409
0.2868
我会说所有上述方法都足够快,bsxfun
解决方案最快:)