How to efficiently sample a matrix in matlab, given a list of coordinates with repeatitions - matlab

I have a list of coordinates to a matrix, and I want to sample the matrix elements from it. The list of coordinates is with repetitions and actually is larger than the number of elements in the matrix.
e.g.
A = magic(3)
coords = [1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3];
I want to get back a vector of values (pseudo code): sample_from_matrix(A, coords);

You can try it that way:
A( sub2ind( size(A), coords(:,1), coords(:,2) ) )
If you want to remove coordinate duplicates first:
coords = unique( coords, 'rows' );
A( sub2ind( size(A), coords(:,1), coords(:,2) ) )

Related

How can I go through the columns of a matrix in matlab and add them each to a specific column of a sum matrix in matlab?

Supose there is a Matrix
A =
1 3 2 4
4 2 5 8
6 1 4 9
and I have a Vector containing the "class" of each column of this matrix for example
v = [1 , 1 , 2 , 3]
How can I sum the columns of the matrix to a new matrix as column vectors each to the column of their class? In this example columns 1 and 2 of A would added to the first column of the new matrix, column 2 to the 3 to the 2nd, column 4 the the 3rd.
Like
SUM =
4 2 4
6 5 8
7 4 9
Is this possible without loops?
One of the perfect scenarios to combine the powers of accumarray and bsxfun -
%// Since we are to accumulate columns, first step would be to transpose A
At = A.' %//'
%// Create a vector of linear IDs for use with ACCUMARRAY later on
idx = bsxfun(#plus,v(:),[0:size(A,1)-1]*max(v))
%// Use ACCUMARRAY to accumulate rows from At, i.e. columns from A based on the IDs
out = reshape(accumarray(idx(:),At(:)),[],size(A,1)).'
Sample run -
A =
1 3 2 4 6 0
4 2 5 8 9 2
6 1 4 9 8 9
v =
1 1 2 3 3 2
out =
4 2 10
6 7 17
7 13 17
An alternative with accumarray in 2D. Generate a grid with the vector v and then apply accumarray:
A = A.';
v = [1 1 2 3];
[X, Y] = ndgrid(v,1:size(A,2));
Here X and Y look like this:
X =
1 1 1
1 1 1
2 2 2
3 3 3
Y =
1 2 3
1 2 3
1 2 3
1 2 3
Then apply accumarray:
B=accumarray([X(:) Y(:)],A(:)),
SUM = B.'
SUM =
4 2 4
6 5 8
7 4 9
As you see, using [X(:) Y(:)] create the following array:
ans =
1 1
1 1
2 1
3 1
1 2
1 2
2 2
3 2
1 3
1 3
2 3
3 3
in which the vector v containing the "class" is replicated 3 times since there are 3 unique classes that are to be summed up together.
EDIT:
As pointed out by knedlsepp you can get rid of the transpose to A and B like so:
[X2, Y2] = ndgrid(1:size(A,1),v);
B = accumarray([X2(:) Y2(:)],A(:))
which ends up doing the same. I find it a bit more easier to visualize with the transposes but that gives the same result.
How about a one-liner?
result = full(sparse(repmat(v,size(A,1),1), repmat((1:size(A,1)).',1,size(A,2)), A));
Don't optimize prematurely!
The for loop performs fine for your problem:
out = zeros(size(A,1), max(v));
for i = 1:numel(v)
out(:,v(i)) = out(:,v(i)) + A(:,i);
end
BTW: With fine, I mean: fast, fast, fast!

how to remove rows with same information but different representation?

given
A=1 1 0
1 2 0.563826213141399
1 3 1.18321595677734
1 4 1.95685972913029
2 1 0.563826213141399
2 2 0
2 3 0.830602192143995
2 4 1.65196852337589
2 5 1.77172232586001
3 1 1.18321595677734
3 2 0.830602192143995
3 3 0
3 4 0.821522975656861
3 5 1.12716458303105
3 6 1.78117938413852
as seen row 2 and 5 are same in real but not in the matrix. how can I remove one of the same rows?
using unique I couldn't do this.
It seems like you have a representation of a graph using a weighted adjacency matrix.
If I understand correctly, you wish to have a single entry per edge.
You can do this by taking only the upper triangle of the adjacency matrix
A = sparse( A(:,1), A(:,2), A(:,3), max(A(:,2)), max(A(:,2)) );
[ii jj wij] = find( triu( A ) ) ;
disp( [ii jj wij] )
outputs:
1 2 0.563826
1 3 1.183216
2 3 0.830602
1 4 1.956860
2 4 1.651969
3 4 0.821523
2 5 1.771722
3 5 1.127165
3 6 1.781179

Sorting Coordinate Matrix in Matlab

In Matlab I have a big matrix containing the coordinates (x,y,z) of many points (over 200000). There is an extra column used as identification. I have written this code in order to sort all coordinate points. My final goal is to find duplicated points (rows with same x,y,z). After sorting the coordinate points I use the diff function, two consecutive rows of the matrix with the same coordinates will take value [0 0 0], and then with ismember I can find which rows of that matrix resulting from applying "diff" have the [0 0 0] row. With the indices returned from ismember I can find which points are repeated.
Back to my question...This is the code I wrote to sort properly my coordintes+id matrix. I guess It could be done better. Any suggestion?
%coordinates are always positive
a=[ 1 2 8 4; %sample matrix
1 0 5 6;
2 4 7 1;
3 2 1 0;
2 3 5 0;
3 1 2 8;
1 2 4 8];
b=a; %for checking purposes
%sorting first column
a=sortrows(a,1);
%sorting second column
for i=0:max(a(:,1));
k=find(a(:,1)==i);
if not(isempty(k))
a(k,:)=sortrows(a(k,:),2);
end
end
%Sorting third column
for i=0:max(a(:,2));
k=find(a(:,2)==i);
if not(isempty(k))
%identifying rows with same value on first column
for j=1:length(k)
[rows,~] = ismember(a(:,1:2), [ a(k(j),1),i],'rows');
a(rows,3:end)=sortrows(a(rows,3:end),1);
end
end
end
%Checking that rows remain the same
m=ismember(b,a,'rows');
if length(m)~=sum(m)
disp('Error while sorting!');
end
Why don't you just use unique?
[uniqueRows, ii, jj] = unique(a(:,1:3),'rows');
Example
a = [1 2 3 5
3 2 3 6
1 2 3 9
2 2 2 8];
gives
uniqueRows =
1 2 3
2 2 2
3 2 3
and
jj =
1
3
1
2
meaning third row equals first row.
If you need the full unique rows, including the fourth column: use ii to index a:
fullUniqueRows = a(ii,:);
which gives
fullUniqueRows =
1 2 3 9
2 2 2 8
3 2 3 6
Trying to sort a based on the fourth column? Do this -
a=[ 1 2 8 4; %sample matrix
1 0 5 6;
2 4 7 1;
3 2 1 0;
2 3 5 0;
3 2 1 8;
1 2 4 8];
[x,y] = sort(a(:,4))
sorted_a=a(y,:)
Trying to get the row indices having repeated x-y-z coordinates being represented by the first three columns? Do this -
out = sum(squeeze(all(bsxfun(#eq,a(:,1:3),permute(a(:,1:3),[3 2 1])),2)),2)>1
and use it similarly for sorted_a.

assign to matrix index pairs that are mapped to values

I've seen some post for assigning index vector to matrix,
but what i am looking for is for the case like this:
i'm taking random values from 1:8,
each value correspond to pair of index e.g:
1- [1,3]
2- [1,4]
3- [1,5]
4- [2,4]
5- [2,5]
6- [3,5]
7- [1,2]
8- [2,3]
then i have [5Xm] matrix of ones and i want to assign zeros according to the random values.
e.g
random values : 1,5,2
0 1 0
1 0 1
0 1 1
1 1 0
1 0 1
thanks in advance
%// Data
pairs = [
1 3
1 4
1 5
2 4
2 5
3 5
1 2
2 3 ];
m = 3;
values = [1 5 2];
%// Generate matrix
matrix = ones(5,m);
matrix(sub2ind(size(matrix),pairs(values,:).',repmat(1:m,size(pairs,2),1))) = 0;

Matlab: How to conditionally select a subset of a matrix based on a row function?

I have a vector like this, which represents horizontal/vertical dimensions on a board
Hor Verti
1 2
2 3
4 1
2 3
2 2
1 4
..... and many more
I also have an starting vector of (1, 1) . I want to sub-select all rows of this matrix where either horizontal == 1 and vertical is +-2 units away, or vertical == 1 and horizontal = +-2.
Think of like a rook on a mini-4x4 chess board, that is constrained to moving 2 spaces at a time. I want to find all the valid spaces that it can move to out of a series of proposed spaces, it is ok that some of the proposals exists more than once, because they are proposed by different people.
I want subset of proposals where
[ (Hori== sInitial(1) && (Vert - sInitial(2) <=2) )
|| (Vert == sInitial(2) && (Hori - sInitial(1) <=2) )
]
Is it possible to do this without a for-loop?
For a 4x4 grid of possible positions:
>> [x,y] = ndgrid(1:4,1:4)
x =
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
y =
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
>> xy = [x(:) y(:)];
If the player is in position pos = [2 3] and allowed to move up to 2 spaces (either horizontal or vertical), the possible moves would be:
>> idx = (pdist2(xy, pos, 'cityblock') <= 2) & any(bsxfun(#eq, xy, pos), 2);
>> M = reshape(double(idx), [4 4]); M(pos(1),pos(2)) = nan;
M =
0 0 1 0
1 1 NaN 1
0 0 1 0
0 0 1 0
(I've marked the initial position with NaN, possible moves with 1, rest of grid with 0).
or in terms of coordinates:
>> coords = xy(idx,:)
coords =
2 1
2 2
1 3
2 3
3 3
4 3
2 4
The above pdist2 function computes the Manhattan distance.
That's easy. Given some data
data = [1 2
2 3
4 1
2 3
2 2
1 4
3 1];
simply do:
row_indices = find( (data(:,1)==1 | data(:,2)==1) & abs(data(:,1)-data(:,2))<=2 )
data(row_indices,:)