ramgorur
ramgorur

Reputation: 2164

matlab: mapping function over columns (like lisp)

I need to apply a function over columns of a matrix. Let's say I have this matrix --

>> m = rand(3,3)
m =
    0.8626    0.5661    0.8489
    0.6830    0.1498    0.1401
    0.0857    0.4775    0.3296

and two vectors of lower and upper bounds --

>> mins = [2 3 5]
mins =
     2     3     5

>> maxs = [7 11 13]
maxs =
     7     11     13

Now what I am doing is to split the matrix into columns --

>> cols = num2cell(m, 1)
cols = 
    [3x1 double]    [3x1 double]    [3x1 double]

Now what I was trying is to apply a function over each column that takes the lower and the upper bounds to normalize the column values, more specifically I want to normalize the column m(:,1) with mins(1) and maxs(1), m(:,2) with mins(2) and maxs(2) ... column m(:,n) with mins(n) and maxs(n) and so on. My take was like this --

>> norm_cols = cellfun(@(c, lb, ub) (ub - lb) .* c + lb, cols, mins, maxs);
Error using cellfun
Input #3 expected to be a cell array, was double instead.

My question is such thing doable in matlab? and lets say it's doable, then how do I merge the splitted columns into matrix again?

Moreover, please note that I am aware of loops, but I do not want to use it (as my matrix can grow like 1000x1000), so please do not provide any solution that uses loop. Although I am not sure if function mapping could give better speed up than loops (that's another issue, but not for today).

Upvotes: 2

Views: 233

Answers (1)

Chris Taylor
Chris Taylor

Reputation: 47402

Well, you could certainly do something like this

>> x = {[1; 2; 3]/10, [4; 5; 6]/10, [7; 8; 9]/10};
>> mins = {1.5 4.5 7.5};  
>> maxs = {2.5 5.5 8.5};
>> y = cellfun(@(a, lb, ub) (ub-lb) * x + lb, x, mins, maxs, 'uniform', 0)

y = 

    [3x1 double]    [3x1 double]    [3x1 double]

>> [y{:}]

ans =

   1.600000000000000   4.900000000000000   8.199999999999999
   1.700000000000000   5.000000000000000   8.300000000000001
   1.800000000000000   5.100000000000000   8.400000000000000

But it's even cooler to use bsxfun to broadcast your arguments across the rows, without turning it into a cell array first

>> x = [1 4 7; 2 5 8; 3 6 9] / 10;
>> mins = [1.5 4.5 7.5];
>> maxs = [2.5 5.5 8.5];
>> y = bsxfun(@plus, bsxfun(@times, x, maxs-mins), mins);

Upvotes: 4

Related Questions