initialize matrix index in MATLAB - matlab

I have one program with MATLAB. I have 3 variable such as a, b and c.
c is matrix with 2 columns and 10000 rows. a is row index matrix c and b is index column matrix c. For example
c=[1 2 3 4;
5 6;
7 8;
9 10;
11 12]
a=[2,4];
b=[1,2];
i want write c(a,b)=0 return c(2,1)=0 and c(4,2)=0.
c= 1 2
0 6
7 8
9 0
11 12
but return
c= 1 2
0 0
7 8
0 0
11 12
I don't use for and while.
this example is very small in matrix program c is double (3000*3000) and b, c is double(1*1085)

To me below is working-
c(a(1,1),b(1,1)) = c(a(1,2),b(1,2))=0
Use indexing to get right elements from a and b and use this to change c for more on indexing see here.
Output-
c =
1 2
0 6
7 8
9 0
11 12
EDIT
To use looping for large matrix use this-
close all;clear;clc
c=[1 2 ;
5 6;
7 8;
9 10;
11 12];
a=[2,4,3];
b=[1,2,2];
concated = [a;b];
sz = size(concated);
for i=1:sz(1,2)
ind = concated(:,i);
c(ind(1,1),ind(2,1)) = 0;
end
disp(c);
Output-
1 2
0 6
7 0
9 0
11 12

Related

How to take union of matrix rows that are represented by another vector?

I want to take the union of some of the rows of a matrix x. The row numbers of the rows whose union has to be taken are given by vector r. Is there any built-in function in MATLAB that can do it?
x = [1 2 4 0 0;
3 6 5 0 0;
7 8 10 12 9;
2 4 6 7 0;
3 4 5 8 12];
r = [1, 3, 5];
I think this will work for you - first, take the submatrix x(r,:) with the rows you want, and then find all the unique values in it:
unique(x(r,:))
ans =
0
1
2
3
4
5
7
8
9
10
12
You could do it like this
>>> union(union(x(r(1),:),x(r(2),:)),x(r(3),:))
ans =
0 1 2 3 4 5 7 8 9 10 12
or set up a for loop that iterates over the vector r to compute all the unions

Shift rows in matrix with respect to vector values in Octave/MATLAB

Can I shift rows in matrix A with respect to values in vector v?
For instance A and v specified as follows:
A =
1 0 0
1 0 0
1 0 0
v =
0 1 2
In this case I want to get this matrix from A:
A =
1 0 0
0 1 0
0 0 1
Every i-th row in A has been shifted by i-th value in v
Can I do this operation with native functions?
Or should I write it by myself?
I've tried circshift function, but I couldn't figure out how to shift rows separately.
The function circshift does not work as you want and even if you use a vector for the amount of shift, that is interpreted as the amount of shift for each dimension. While it is possible to loop over the rows of your matrix, that will not be very efficient.
More efficient is if you compute the indexing for each row which is actually quite simple:
## First, prepare all your input
octave> A = randi (9, 4, 6)
A =
8 3 2 7 4 5
4 4 7 3 9 1
1 6 3 9 2 3
7 4 1 9 5 5
octave> v = [0 2 0 1];
octave> sz = size (A);
## Compute how much shift per row, the column index (this will not work in Matlab)
octave> c_idx = mod ((0:(sz(2) -1)) .- v(:), sz(2)) +1
c_idx =
1 2 3 4 5 6
5 6 1 2 3 4
1 2 3 4 5 6
6 1 2 3 4 5
## Convert it to linear index
octave> idx = sub2ind (sz, repmat ((1:sz(1))(:), 1, sz(2)) , c_idx);
## All you need is to index
octave> A = A(idx)
A =
8 3 2 7 4 5
9 1 4 4 7 3
1 6 3 9 2 3
5 7 4 1 9 5
% A and v as above. These could be function input arguments
A = [1 0 0; 1 0 0; 1 0 0];
v = [0 1 2];
assert (all (size (v) == [1, size(A, 1)]), ...
'v needs to be a horizontal vector with as many elements as rows of A');
% Calculate shifted indices
[r, c] = size (A);
tmp = mod (repmat (0 : c-1, r, 1) - repmat (v.', 1, c), c) + 1;
Out = A(sub2ind ([r, c], repmat ([1 : r].', 1, c), tmp))
Out =
1 0 0
0 1 0
0 0 1
If performance is an issue, you can replace repmat with an equivalent bsxfun call which is more efficient (I use repmat here for simplicity to demonstrate the approach).
With focus on performance, here's one approach using bsxfun/broadcasting -
[m,n] = size(A);
idx0 = mod(bsxfun(#plus,n-v(:),1:n)-1,n);
out = A(bsxfun(#plus,(idx0*m),(1:m)'))
Sample run -
A =
1 7 5 7 7
4 8 5 7 6
4 2 6 3 2
v =
3 1 2
out =
5 7 7 1 7
6 4 8 5 7
3 2 4 2 6
Equivalent Octave version to use automatic broadcasting would look something like this -
[m,n] = size(A);
idx0 = mod( ((n-v(:)) + (1:n)) -1 ,n);
out = A((idx0*m)+(1:m)')
Shift vector with circshift in loop, iterating row index.

How to combine matrix of different size in a cell array into a matrix in MATLAB

Similarly to How to combine vectors of different length in a cell array into matrix in MATLAB I would like to combine matrix having different dimension, stored in a cell array, into a matrix having zeros instead of the empty spaces. Specifically, I have a cell array {1,3} having 3 matrix of size (3,3) (4,3) (4,3):
A={[1 2 3; 4 5 6; 7 8 9] [1 2 3; 4 5 6; 7 8 9; 9 9 9] [1 2 3; 4 5 6; 7 8 9; 4 4 4]}
and I would like to obtain something like:
B =
1 2 3 1 2 3 1 2 3
4 5 6 4 5 6 4 5 6
7 8 9 7 8 9 7 8 9
0 0 0 9 9 9 4 4 4
I tried using cellfun and cell2mat but I do not figure out how to do this. Thanks.
Even if other answers are good, I'd like to submit mine, using cellfun.
l = max(cellfun(#(x) length(x),A))
B = cell2mat(cellfun(#(x) [x;zeros(l-length(x),3)], A, 'UniformOutput', 0));
Using bsxfun's masking capability -
%// Convert A to 1D array
A1d = cellfun(#(x) x(:).',A,'Uni',0) %//'
%// Get dimensions of A cells
nrows = cellfun('size', A, 1)
ncols = cellfun('size', A, 2)
%// Create a mask of valid positions in output numeric array, where each of
%// those numeric values from A would be put
max_nrows = max(nrows)
mask = bsxfun(#le,[1:max_nrows]',repelem(nrows,ncols)) %//'
%// Setup output array and put A values into its masked positions
B = zeros(max_nrows,sum(ncols))
B(mask) = [A1d{:}]
Sample run
Input -
A={[1 2 3 5 6; 7 8 9 3 8] [1 2 3; 4 5 6; 7 8 9; 9 9 9] [1 2 3; 4 5 6; 7 8 9; 4 4 4]}
Output -
B =
1 2 3 5 6 1 2 3 1 2 3
7 8 9 3 8 4 5 6 4 5 6
0 0 0 0 0 7 8 9 7 8 9
0 0 0 0 0 9 9 9 4 4 4
I would be surprised if this is possible in one or a few lines. You will probably have to do some looping yourself. The following achieves what you want in the specific case of incompatible first dimension lengths:
A={[1 2 3; 4 5 6; 7 8 9] [1 2 3; 4 5 6; 7 8 9; 9 9 9] [1 2 3; 4 5 6; 7 8 9; 4 4 4]}
maxsize = max(cellfun(#(x) size(x, 1), A));
B = A;
for k = 1:numel(B)
if size(B{k}, 1) < maxsize
tmp = B{k};
B{k} = zeros(maxsize, size(tmp,1));
B{k}(1:size(tmp,1),1:size(tmp,2)) = tmp;
end
end
B = cat(2, B{:});
Now B is:
B =
1 2 3 1 2 3 1 2 3
4 5 6 4 5 6 4 5 6
7 8 9 7 8 9 7 8 9
0 0 0 9 9 9 4 4 4
I would do it using a good-old for loop, which is quite intuitive I think.
Here is the commented code:
clc;clear var
A={[1 2 3; 4 5 6; 7 8 9] [1 2 3; 4 5 6; 7 8 9; 9 9 9] [1 2 3; 4 5 6; 7 8 9; 4 4 4]};
%// Find the maximum rows and column # to initialize the output array.
MaxRow = max(cell2mat(cellfun(#(x) size(x,1),A,'Uni',0)));
SumCol = sum(cell2mat(cellfun(#(x) size(x,2),A,'Uni',0)));
B = zeros(MaxRow,SumCol);
%// Create a counter to keep track of the current columns to fill
ColumnCounter = 1;
for k = 1:numel(A)
%// Get the # of rows and columns for each cell from A
NumRows = size(A{k},1);
NumCols = size(A{k},2);
%// Fill the array
B(1:NumRows,ColumnCounter:ColumnCounter+NumCols-1) = A{k};
%// Update the counter
ColumnCounter = ColumnCounter+NumCols;
end
disp(B)
Output:
B =
1 2 3 1 2 3 1 2 3
4 5 6 4 5 6 4 5 6
7 8 9 7 8 9 7 8 9
0 0 0 9 9 9 4 4 4
[max_row , max_col] = max( size(A{1}) , size(A{2}) , size(A{3}) );
A{1}(end:max_row , end:max_col)=0;
A{2}(end:max_row , end:max_col)=0;
A{3}(end:max_row , end:max_col)=0;
B=[A{1} A{2} A{3}];
for this specific problem, simply this will do:
B=cat(1,A{:});
or what I often just give a try for 2D cells, and works for your example as well:
B=cell2mat(A');
if you literally don't give a f* what dimension it will be cut in (and you're exceedingly lazy): put the same into a try-catch-block and loop over some dims as below.
function A=cat_any(A)
for dims=1:10% who needs more than 10 dims? ... otherwise replace 10 with: max(cellfun(#ndims,in),[],'all')
try, A=cat(dims,A{:}); end
if ~iscell(A), return A; end
end
disp('Couldn''t cat!') %if we can't cat, tell the user
end
Beware, this might lead to unexpected results ... but in most cases simply just worked for me.

Find how many times a pair of values occurs

Suppose there are 2 vectors (i,j), A(10,1), B(10,1) which have obtain random values from [1,10] interval. eg.
A = [1 6 1 10 1 7 1 9 3 6]
B = [7 2 3 5 6 8 7 9 10 2].
I am interested in creating a new vector which will count how many values with the same i index occur. e.g.
1 and 7 ⇒ 2 occurrences
6 and 2 ⇒ 2 occurrences
1 and 3 ⇒ 1 occurrence
10 and 5 ⇒ 1 occurrence
1 and 6 ⇒ 1 occurrence
...
etc.
So that a final array/vector C occurs, with all the possible pairs and their counted occurrence with size C(number_of_pairs,2).
Use accumarray and then find:
A = [1 6 1 10 1 7 1 9 3 6];
B = [7 2 3 5 6 8 7 9 10 2]; %// data
aa = accumarray([A(:) B(:)], 1); %// how many times each pair occurs
[ii jj vv] = find(aa);
C = [ii jj vv]; %// only pairs which occurr at least once
In your example, this gives
C =
6 2 2
1 3 1
10 5 1
1 6 1
1 7 2
7 8 1
9 9 1
3 10 1
Or perhaps aa or vv are what you need; I'm not sure about what your desired output is.
Another possible approach, inspired by #Rody's answer:
mat = [A(:) B(:)];
[bb ii jj] = unique(mat, 'rows');
C = [mat(ii,:) accumarray(jj,1)];
Something like this?
A = [1 6 1 10 1 7 1 9 3 6];
B = [7 2 3 5 6 8 7 9 10 2];
%// Find the unique pairs
AB = [A;B].';
ABu = unique(AB, 'rows');
%// Count the number of occurrences of each unique pair
%// (pretty sure there's a better way to do this...)
C = arrayfun(#(ii) ...
[ABu(ii,:) sum(all(bsxfun(#eq, AB, ABu(ii,:)),2))], 1:size(ABu,1), ...
'UniformOutput', false);
C = cat(1,C{:});
Result:
C =
1 3 1
1 6 1
1 7 2
3 10 1
6 2 2
7 8 1
9 9 1
10 5 1
Something like this?
C = zeros(10);
for k = 1:10
C(A(k), B(k)) = C(A(k), B(k)) + 1
end

How do I make sums of sumatrixes in MATLAB without cycle?

I have a large matrix (time x frequency), which I want to reduce partially. I want to sum every 1000 rows (time-samples) together keepinq the frequency information, it is kind of a segmentation.
Is there any way to do it without any cycle in MATLAB?
A smaller example:
M=[1 2 3; 2 3 4; 5 8 7; 5 6 7; 1 2 3; 1 2 4];
and I want to sum every 2 rows together so, that I get:
[3 5 7; 10 14 14; 2 4 7]
Suppose you have a matrix with N rows and M columns and you want to sum every R rows together (where N is divisible by R),
>> mat = [1 2 3; 2 3 4; 5 8 7; 5 6 7; 1 2 3; 1 2 4]
mat =
1 2 3
2 3 4
5 8 7
5 6 7
1 2 3
1 2 4
>> [N, M] = size(mat); %=> [6, 3]
>> R = 2;
The following will allow you to sum groups of R rows:
>> res = reshape(mat, R, [])
res =
1 5 1 2 8 2 3 7 3
2 5 1 3 6 2 4 7 4
>> res = sum(res)
res =
3 10 2 5 14 4 7 14 7
>> res = reshape(res, [], M)
res =
3 5 7
10 14 14
2 4 7
You can also do everything in one line:
>> reshape(sum(reshape(mat, R, [])), [], M)
ans =
3 5 7
10 14 14
2 4 7