BetaCV in matlab - arrays

I have a matrix indices with 2 columns and 20 rows.
indices =
[1 2;
2 3;
2 1;
... ]
there is a second matrix distMat with 4 rows and 4 columns and i want to find the sum of elements in distMat located in position given in each row of indices[]
distMat =
[1 3 1 5
2 2 4 2
3 8 3 7
3 8 3 7]
since indices rows are 1 2, 2 3, 3 1 so elements of that positions should be retrieved and added
so i wrote
result = sum(distMat[indices])
I am getting syntax error. so how to solve this problem

Another approach: use sparse to build a logical index that selects the values to be summed:
indices = [1 2; 2 3; 2 1];
distMat = [1 3 1 5; 2 2 4 2; 3 8 3 7; 3 8 3 7];
result = sum(distMat((sparse(indices(:,1), indices(:,2), true, size(distMat,1), size(distMat,2)))));
This works in Octave as well.

One way would be to get the linear indices and then simply index and sum, just like you had at the end -
idx = sub2ind(size(distMat), indices(:,1), indices(:,2));
out = sum(distMat(idx))
Sample run -
>> indices
indices =
1 2
2 3
2 1
>> distMat
distMat =
1 3 1 5
2 2 4 2
3 8 3 7
3 8 3 7
>> idx = sub2ind(size(distMat), indices(:,1), indices(:,2));
>> distMat(idx)
ans =
3
4
2
>> sum(distMat(idx))
ans =
9

Related

Reshape the array along the reverse dimensions

>> A = [ 1 2 3 3 4 5 5 6 7 7 8 9 ];
>>
>> B = reshape(A, 2, 2, 3)
B(:,:,1) =
1 3
2 3
B(:,:,2) =
4 5
5 6
B(:,:,3) =
7 8
7 9
Since reshape can only change the size of the given array in the way of preserving the linear indices, however I would like to reshape the array along the reverse dimensions.
For example, convert A into
>> C = reverse-reshape(A, 2, 2, 3) % not required to be only one function
C(:,:,1) =
1 3
5 7
C(:,:,2) =
2 4
6 8
C(:,:,3) =
3 5
7 9
Is there any better method than writing loops and fill numbers one by one in version R2017b?
You would first reshape with the dimensions in reverse order, then swap the first and third dimensions with permute to reorder the elements so that they are populated in reverse order:
>> B = permute(reshape(A, 3, 2, 2), [3 2 1])
B(:,:,1) =
1 3
5 7
B(:,:,2) =
2 4
6 8
B(:,:,3) =
3 5
7 9
To do this in general independent of the matrix dimensions and assuming it is a 3D matrix, declare an array called dims that contains the output desired matrix size, reverse the elements and supply this into reshape:
dims = [2 2 3];
B = permute(reshape(A, fliplr(dims)), [3 2 1]);
fliplr reverses the elements in a matrix horizontally.

Ordered random numbers in Matlab

I am trying to generate random numbers between 1 and 5 using Matlab's randperm and calling randperm = 5.
Each time this gives me a different array let's say for example:
x = randperm(5)
x = [3 2 4 1 5]
I need the vector to be arranged such that 4 and 5 are always next to each other and 2 is always between 1 and 3... so for e.g. [3 2 1 4 5] or [4 5 1 2 3].
So essentially I have two "blocks" of unequal length - 1 2 3 and 4 5. The order of the blocks is not so important, just that 4 & 5 end up together and 2 in between 1 and 3.
I can basically only have 4 possible combinations:
[1 2 3 4 5]
[3 2 1 4 5]
[4 5 1 2 3]
[4 5 3 2 1]
Does anyone know how I can do this?
Thanks
I'm not sure if you want a solution that would somehow generalize to a larger problem, but based on how you've described your problem above it looks like you are only going to have 8 possible combinations that satisfy your constraints:
possible = [1 2 3 4 5; ...
1 2 3 5 4; ...
3 2 1 4 5; ...
3 2 1 5 4; ...
4 5 1 2 3; ...
5 4 1 2 3; ...
4 5 3 2 1; ...
5 4 3 2 1];
You can now randomly select one or more of these rows using randi, and can even create an anonymous function to do it for you:
randPattern = #(n) possible(randi(size(possible, 1), [1 n]), :)
This allows you to select, for example, 5 patterns at random (one per row):
>> patternMat = randPattern(5)
patternMat =
4 5 3 2 1
3 2 1 4 5
4 5 3 2 1
1 2 3 5 4
5 4 3 2 1
You can generate each block and shuffle each one then and set them as members of a cell array and shuffle the cell array and finally convert the cell array to a vector.
b45=[4 5]; % block 1
b13=[1 3]; % block 2
r45 = randperm(2); % indices for shuffling block 1
r13 = randperm(2); % indices for shuffling block 2
r15 = randperm(2); % indices for shuffling the cell
blocks = {b45(r45) [b13(r13(1)) 2 b13(r13(2))]}; % shuffle each block and set them a members of a cell array
result = [blocks{r15}] % shuffle the cell and convert to a vector

MATLAB: detect and remove mirror imaged pairs in 2 column matrix

I have a matrix
[1 2
3 6
7 1
2 1]
and would like to remove mirror imaged pairs..i.e. output would be either:
[1 2
3 6
7 1]
or
[3 6
7 1
2 1]
Is there a simple way to do this? I can imagine a complicated for loop, something like (or a version which wouldn't delete the original pair..only the duplicates):
for i=1:y
var1=(i,1);
var2=(i,2);
for i=1:y
if array(i,1)==var1 && array(i,2)==var2 | array(i,1)==var2 && array(i,2)==var1
array(i,1:2)=[];
end
end
end
thanks
How's this for simplicity -
A(~any(tril(squeeze(all(bsxfun(#eq,A,permute(fliplr(A),[3 2 1])),2))),2),:)
Playing code-golf? Well, here we go -
A(~any(tril(pdist2(A,fliplr(A))==0),2),:)
If dealing with two column matrices only, here's a simpler version of bsxfun -
M = bsxfun(#eq,A(:,1).',A(:,2)); %//'
out = A(~any(tril(M & M.'),2),:)
Sample run -
A =
1 2
3 6
7 1
6 5
6 3
2 1
3 4
>> A(~any(tril(squeeze(all(bsxfun(#eq,A,permute(fliplr(A),[3 2 1])),2))),2),:)
ans =
1 2
3 6
7 1
6 5
3 4
>> A(~any(tril(pdist2(A,fliplr(A))==0),2),:)
ans =
1 2
3 6
7 1
6 5
3 4
Here a not so fancy, but hopefully understandable and easy way.
% Example matrix
m = [1 2; 3 6 ; 7 1; 2 1; 0 3 ; 3 0];
Comparing m with its flipped version, the function ismember returns mirror_idx, a 1D-vector with each row containing the index of the mirror-row, or 0 if there's none.
[~, mirror_idx] = ismember(m,fliplr(m),'rows');
Go through the indices of the mirror-rows. If you find one "mirrored" row (mirror_idx > 0), set its counter-part to "not mirrored".
for ii = 1:length(mirror_idx)
if (mirror_idx(ii) > 0)
mirror_idx(mirror_idx(ii)) = 0;
end
end
Take only the rows that are marked as not having a mirror.
m_new = m(~mirror_idx,:);
Greetings

Remove one element from each row of a matrix, each in a different column

How can I remove elements in a matrix, that aren't all in a straight line, without going through a row at a time in a for loop?
Example:
[1 7 3 4;
1 4 4 6;
2 7 8 9]
Given a vector (e.g. [2,4,3]) How could I remove the elements in each row (where each number in the vector corresponds to the column number) without going through each row at a time and removing each element?
The example output would be:
[1 3 4;
1 4 4;
2 7 9]
It can be done using linear indexing at follows. Note that it's better to work down columns (because of Matlab's column-major order), which implies transposing at the beginning and at the end:
A = [ 1 7 3 4
1 4 4 6
2 7 8 9 ];
v = [2 4 3]; %// the number of elements of v must equal the number of rows of A
B = A.'; %'// transpose to work down columns
[m, n] = size(B);
ind = v + (0:n-1)*m; %// linear index of elements to be removed
B(ind) = []; %// remove those elements. Returns a vector
B = reshape(B, m-1, []).'; %'// reshape that vector into a matrix, and transpose back
Here's one approach using bsxfun and permute to solve for a 3D array case, assuming you want to remove indexed elements per row across all 3D slices -
%// Inputs
A = randi(9,3,4,3)
idx = [2 4 3]
%// Get size of input array, A
[M,N,P] = size(A)
%// Permute A to bring the columns as the first dimension
Ap = permute(A,[2 1 3])
%// Per 3D slice offset linear indices
offset = bsxfun(#plus,[0:M-1]'*N,[0:P-1]*M*N) %//'
%// Get 3D array linear indices and remove those from permuted array
Ap(bsxfun(#plus,idx(:),offset)) = []
%// Permute back to get the desired output
out = permute(reshape(Ap,3,3,3),[2 1 3])
Sample run -
>> A
A(:,:,1) =
4 4 1 4
2 9 7 5
5 9 3 9
A(:,:,2) =
4 7 7 2
9 6 6 9
3 5 2 2
A(:,:,3) =
1 7 5 8
6 2 9 6
8 4 2 4
>> out
out(:,:,1) =
4 1 4
2 9 7
5 9 9
out(:,:,2) =
4 7 2
9 6 6
3 5 2
out(:,:,3) =
1 5 8
6 2 9
8 4 4

How to sort rows of a matrix based on frequency of the elements of one column?

I tried using sortrows function in Matlab. Is there any way using this function or any idea to sort rows of a matrix based on frequency of elements of a column of that matrix.
As an example: I have this matrix
matrix = [1 3 1;
1 4 2;
2 5 4;
3 2 3;
5 5 4;
5 3 3;
4 3 2;
4 2 3;
3 6 4;
2 4 3];
I would like to get something similar to this:
sorted_based_on_3rd_col = [2 4 3;
3 2 3;
4 2 3;
5 3 3;
2 5 4;
3 6 4;
5 5 4;
1 4 2;
4 3 2;
1 3 1]
which is sorted based most frequent element on third column.
Thanks for any help!
This is one way:
x = matrix(:,3);
[c,b] = histc(x,unique(x))
[~,idx] = sort(c(b),'descend')
out = matrix(idx,:)
If you don't care about the order of elements with equal frequency, this can be done like so:
>> freq = accumarray(matrix(:,3), 1);
>> [~, ind] = sort(freq(matrix(:, 3)), 1, 'descend'); % index that sorts matrix
>> matrix(ind, :) % reshuffle matrix to sort
ans =
3 2 3
5 3 3
4 2 3
2 4 3
2 5 4
5 5 4
3 6 4
1 4 2
4 3 2
1 3 1
If you do care, you need to pre-sort the matrix before anything else. Since matlab's sort is stable, this will preserve the order of items that are equal in the second sort.
>> matrix = sortrows(matrix, 1)
matrix =
1 3 1
1 4 2
2 5 4
2 4 3
3 2 3
3 6 4
4 3 2
4 2 3
5 5 4
5 3 3
>> freq = accumarray(matrix(:,3),1);
>> [~, ind] = sort(freq(matrix(:,3)), 1, 'descend');
>> matrix(ind, :)
ans =
2 4 3
3 2 3
4 2 3
5 3 3
2 5 4
3 6 4
5 5 4
1 4 2
4 3 2
1 3 1

Resources