I have an array of matrix m such that
m1 = [1 2;3 4];
m2 = [2 7; 8 9];
m3 = [9 7; 8 91];
m = [m1 m2 m3]
m =
1 2 2 7 9 7
3 4 8 9 8 91
I also have a vector
v = [1 2 3];
such that i want the operations between v and m result in h such that
h = [1*m1 2*m2 3*m3] = [h1 h2 h3];
I imagine I have to do this in 3-dimensional array for h, which is a 3d array. Or maybe there are better ways.
Let A be a simple 2 by 2 matrix, rand(2,2).
From h i want to extract h1 h2 and h3 out(or better not doing any extraction) and perform operations to A such that
1.
h1*A*h1'
h2*A*h2'
h3*A*h3'
and
2.
h1*h1', h2*h2', h3*h3'.
Why i want to do this in array is because i have a lot of matrix mi so I want to avoid for loop by vectorization.
From what i could understand from the question, i suppose element-wise multiplication would be better choice. You would just have to use proper concatenation and repeatation of matrices.
m1 = [1 2; 3 4];
m2 = [2 7; 8 9];
m3 = [9 7; 8 91];
% Concatenate to create 3D matrix
m = cat(3,m1,m2,m3);
v = [1 2 3];
% Create similar 3D matrix
v1 = cat(3,ones(size(m1))*v(1),ones(size(m2))*v(2),ones(size(m3))*v(3));
% Simple element wise multiplication
h = m.*v1;
% Creating a repeated 3D matrix A, repetation is along third dimension
A = repmat(rand(2,2),[1 1 3]);
% Outputs
op_1 = h.*A.*permute(h,[2 1 3]);
op_2 = h.*permute(h,[2 1 3]);
I have a 3x3 Matrix and want to save the indices and values into a new 9x3 matrix. For example A = [1 2 3 ; 4 5 6 ; 7 8 9] so that I will get a matrix x = [1 1 1; 1 2 2; 1 3 3; 2 1 4; 2 2 5; ...] With my code I only be able to store the last values x = [3 3 9].
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x=[];
for i = 1:size(A)
for j = 1:size(A)
x =[i j A(i,j)]
end
end
Thanks for your help
Vectorized approach
Here's one way to do it that avoids loops:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
[ii, jj] = ndgrid(1:size(A,1), 1:size(A,2)); % row and column indices
vv = A.'; % values. Transpose because column changes first in the result, then row
x = [jj(:) ii(:) vv(:)]; % result
Using your code
You're only missing concatenation with previous x:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x = [];
for i = 1:size(A)
for j = 1:size(A)
x = [x; i j A(i,j)]; % concatenate new row to previous x
end
end
Two additional suggestions:
Don't use i and j as variable names, because that shadows the imaginary unit.
Preallocate x instead of having it grow in each iteration, to increase speed.
The modified code is:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x = NaN(numel(A),3); % preallocate
n = 0;
for ii = 1:size(A)
for jj = 1:size(A)
n = n + 1; % update row counter
x(n,:) = [ii jj A(ii,jj)]; % fill row n
end
end
I developed a solution that works much faster. Here is the code:
% Generate subscripts from linear index
[i, j] = ind2sub(size(A),1:numel(A));
% Just concatenate subscripts and values
x = [i' j' A(:)];
Try it out and let me know ;)
I have a cell array A of size 10x10 (say). Each cell in turn contains a 5x20 matrix. I want to select (i,j) element from each cell, where (i,j) are indices within a loop. I can run 4 for loops and easily get the answer. It may even be faster as it has been discussed many times that loops could be faster than cellfun, structfun etc.
Still, is there any solution using cellfun which I can use in a loop over (i,j) and extract (i,j) element in each cell? I tried writing a function which will act as handle to cellfun but I couldn't access two-leves down i.e. A{eachCellRow,eachCellCol}(i,j).
Example:
If A={[1 2;5 6], [3 4; 6 7]; [3 4; 6 7], [9 8; 5 6]};
Then for i=1, j=1 and i=2, j=1 output should be:
B=[1 3; 3 9] and B=[5 6; 6 5]
CELL2MAT gets all the data from a cell array that consists of numeric data only, into a numeric array. So, that helped us here. For your original problem, try this -
celldim_i = 10;
celldim_j = 10;
block_size_i = 5;
block_size_j = 20;
search_i = i; %// Edit to your i
search_j = j; %// Edit to your j
A_mat = cell2mat(A);
out = A_mat(search_i+block_size_i*(0:celldim_i-1),search_j+block_size_j*(0:celldim_j-1))
The easy to use cellfun one-liner would be:
ii = 2;
jj = 1;
A = {[1 2;5 6], [3 4; 6 7]; [3 4; 6 7], [9 8; 5 6]};
B = cell2mat( cellfun( #(x) x(ii,jj), A, 'uni', 0) )
gives:
B =
5 6
6 5
Advantage over Divakar's Solution: it works also for inconsistent matrix sizes in A.
And if you want to avoid also the outer loop, another fancy two-liner:
dim = [2 2];
[II, JJ] = meshgrid( 1:dim(1), 1:dim(2) );
C = cellfun( #(y) ...
{ cell2mat( cellfun( #(x) x( real(y), imag(y) ), A, 'uni', 0) ) },...
num2cell( II(:)+1i*JJ(:) ))
gives:
>> celldisp(C)
C{1} = % ii = 1 , jj = 1
1 3
3 9
C{2} = % ii = 1 , jj = 2
2 4
4 8
C{3} = % ii = 2 , jj = 1
5 6
6 5
C{4} = % ii = 2 , jj = 2
6 7
7 6
If memory is not an issue, you can concat all matrices along a third dim; and then indexing is very easy:
%// Example data
A = {[1 2;5 6], [3 4; 6 7]; [3 4; 6 7], [9 8; 5 6]};
ii = 2;
jj = 1;
%// Compute the result B
A2 = cat(3,A{:}); %// concat along third dim
B = reshape(A2(ii,jj,:),size(A{1})); %// index A2 and reshape
I have the following data:
A = [1 2 ; 3 2; 4 7; 10 2; 6 7; 10 9]
B = [1 2 3; 4 4 9; 1 8 0; 3 7 9; 3 6 8]
C = [4; 10; 6; 3; 1]
A =
1 2
3 2
4 7
10 2
6 7
10 9
B =
1 2 3
4 4 9
1 8 0
3 7 9
3 6 8
C.' =
4 10 6 3 1
For each unique value in A(:,2) I need to take the corresponding values in A(:,1),
look for their value in C, then take the relevant rows in B and compute their mean.
The result should be length(unique(A(:,2)) x size(B,2);
The expected result for this example:
Value "2": mean of rows 2, 4 and 5 from B
Explanation: Indices 1, 3 and 10 that correspond to value "2" in A are
at indices 2, 4, 5 in C.
Correspondingly:
Value "7": mean of rows 1 and 3 from B.
Value "9": mean of row 2 from B.
I compute it now by applying unique on A and iterating each value, searching the right indices. My data set is quite large, so it takes quite a time. How can I avoid the loops?
Let's do what you say in the question step by step:
For each unique value in A(:, 2):
[U, ia, iu] = unique(A(:, 2));
Take the corresponding values in A(:, 1) and look for their value in C:
[tf, loc] = ismember(A(:, 1), C);
It's also recommended to make sure, just in case, that all values are actually found in C:
assert(all(tf))
Then take the relevant rows in B and compute their mean:
[X, Y] = meshgrid(1:size(B, 2), iu);
result = accumarray([Y(:), X(:)], reshape(B(loc, :), 1, []), [], #mean);
Hope this helps! :)
Example
%// Sample input
A = [1 2 ; 3 2; 4 7; 10 2; 6 7; 10 9];
B = [1 2 3; 4 4 9; 1 8 0; 3 7 9; 3 6 8];
C = [4; 10; 6; 3; 1];
%// Compute means
[U, ia, iu] = unique(A(:, 2));
[tf, loc] = ismember(A(:, 1), C);
[X, Y] = meshgrid(1:size(B, 2), iu);
result = accumarray([Y(:), X(:)], reshape(B(loc, :), [], 1), [], #mean);
The result is:
result =
3.3333 5.6667 8.6667
1.0000 5.0000 1.5000
4.0000 4.0000 9.0000
Here is another solution without arrayfun and accumarray using good old-fashion matrix multiplication:
r = bsxfun(#eq, A(:,1), C')*(1:numel(C))';
[~,m,n] = unique(A(:,2));
f=histc(n, 1:numel(m));
result = diag(1./f)*bsxfun(#eq, 1:numel(m), n).'*B(r,:);
I ran a benchmark against other two solutions and it appears to be faster than both. For 1000 repetitions:
This method takes 0.205650 seconds.
Eitan T's solution takes 0.546976 seconds.
matlabit's solution takes 1.619039 seconds.
Here is the benchmark code:
N = 1e3;
tic
for k=1:N,
r = bsxfun(#eq, A(:,1), C')*(1:numel(C))'; % faster than [~,r] = ismember(A(:,1), C)
[~,m,n] = unique(A(:,2));
f=histc(n, 1:numel(m));
result2 = diag(1./f)*bsxfun(#eq, 1:numel(m), n).'*B(r,:);
end
toc
tic
for k=1:N,
[U, ia, iu] = unique(A(:, 2));
[tf, loc] = ismember(A(:, 1), C);
[X, Y] = meshgrid(1:size(B, 2), iu);
result1 = accumarray([Y(:), X(:)], reshape(B(loc, :), [], 1), [], #mean);
end
toc
tic
for k=1:N,
D = [arrayfun(#(x) find(C == x,1,'first'), A(:,1) ), A(:,2)];
data = [B(D(:,1),:), D(:,2)];
st = grpstats(data(:,1:3),data(:,4:4),{'mean'});
end
toc
Thanks,
I also thought of:
D = [arrayfun(#(x) find(C == x,1,'first'), A(:,1) ), A(:,2)];
data = [B(D(:,1),:), D(:,2)];
st = grpstats(data(:,1:3),data(:,4:4),{'mean'});
A = [1 3 5 8]
B = [1 2 3 4 5 6 7 8]
I would like to create a vector C which returns the rownumber of the element in vector A with the smallest non-negative difference to each element in vector B.
So, given the example above, it should return:
C = [1 2 2 3 3 4 4 4]
I'm sure there are many ways to do this. Here's one:
A = [1 3 5 8]
B = [1 2 3 4 5 6 7 8]
%create matrices of the values to subtract
[a,b] = meshgrid(A,B);
%subtract
aLessB = a-b;
%make sure we don't use the negative values
aLessB(aLessB < 0) = Inf;
%sort the subtracted matrix
[dum, idx] = sort(aLessB, 2, 'ascend');
idx(:,1) is the solution you are looking for.
An alternative solution:
D = bsxfun(#minus, A', B);
D(D < 0) = Inf;
[~, C] = min(D, [], 1);