Search code examples
matlabblockcell-arraymse

to find mean square error of two cell arrays of different sizes


I have two cell arrays. One is 'trans_blk' of size <232324x1> consists of cells of size <8x8> and another 'ca' is of size <1024x1> consists of cells of size <8x8>. I want to compute mean square error (MSE) for each cell of 'ca' with respect to every cell of 'trans_blk'.

I used the following code to compute:

m=0;
for ii=0:7
    for jj=0:7

        m=m+((trans_blk{:,1}(ii,jj)-ca{:,1}(ii,jj))^2);

    end
end

m=m/(size of cell);    //size of cell=8*8
disp('MSE=',m);

Its giving an error. Bad cell reference operation in MATLAB.


Solution

  • A couple of ways that I figured you could go:

    % First define the MSE function
    mse = @(x,y) sum(sum((x-y).^2))./numel(x);
    

    I'm a big fan of using bsxfun for things like this, but unfortunately it doesn't operate on cell arrays. So, I borrowed the singleton expansion form of the answer from here.

    % Singleton expansion way:
    mask = bsxfun(@or, true(size(A)), true(size(B))');
    idx_A = bsxfun(@times, mask, reshape(1:numel(A), size(A)));
    idx_B = bsxfun(@times, mask, reshape(1:numel(B), size(B))');
    
    func = @(x,y) cellfun(@(a,b) mse(a,b),x,y);
    
    C = func(A(idx_A), B(idx_B));
    

    Now, if that is a bit too crazy (or if explicitly making the arrays by A(idx_A) is too big), then you could always try a loop approach such as the one below.

    % Or a quick loop:
    results = zeros(length(A),length(B));
    y = B{1};
    for iter = 1:length(B)
      y = B{iter};
      results(:,iter) = cellfun(@(x) mse(x,y) ,A);  
    end
    

    If you run out of memory: Think of what you are allocating: a matrix of doubles that is (232324 x 1024) elements. (That's a decent chunk of memory. Depending on your system, that could be close to 2GB of memory...)

    If you can't hold it all in memory, then you might have to decide what you are going to do with all the MSE's and either do it in batches, or find a machine that you can run the full simulation/code on.

    EDIT If you only want to keep the sum of all the MSEs (as OP states in comments below), then you can save on memory by

    % Sum it as you go along:
    results = zeros(length(A),1);
    y = B{1};
    for iter = 1:length(B)
      y = B{iter};
      results = results + cellfun(@(x) mse(x,y) ,A);  
    end
    results =sum (results);