How to compare the pairs of coordinates most efficiently without using nested loops in Matlab? - matlab

If I have 20 pairs of coordinates, whose x and y values are say :
x y
27 182
180 81
154 52
183 24
124 168
146 11
16 90
184 153
138 133
122 79
192 183
39 25
194 63
129 107
115 161
33 14
47 65
65 2
1 124
93 79
Now if I randomly generate 15 pairs of coordinates (x,y) and want to compare with these 20 pairs of coordinates given above, how can I do that most efficiently without nested loops?

If you're trying to see if any of your 15 randomly generated coordinate pairs are equal to any of your 20 original coordinate pairs, an easy solution is to use the function ISMEMBER like so:
oldPts = [...]; %# A 20-by-2 matrix with x values in column 1
%# and y values in column 2
newPts = randi(200,[15 2]); %# Create a 15-by-2 matrix of random
%# values from 1 to 200
isRepeated = ismember(newPts,oldPts,'rows');
And isRepeated will be a 15-by-1 logical array with ones where a row of newPts exists in oldPts and zeroes otherwise.

If your coordinates are 1) actually integers and 2) their span is reasonable (otherwise use sparse matrix), I'll utilize a simple truth table. Like
x_0= [27 180 ...
y_0= [182 81 ...
s= [200 200]; %# span of coordinates
T= false(s);
T(sub2ind(s, x_0, y_0))= true;
%# now obtain some other coordinates
x_1= [...
y_1= [...
%# and common coordinates of (x_0, y_0) and (x_1, y_1) are just
T(sub2ind(s, x_1, y_1))

If your original twenty points aren't going to change, you'd get better efficiency if you sorted them O(n log n); then you could see if each random point was in the list with a O(log n) search.
If your "original" points list changes (insertions / deletions), you could get equivalent performance with a binary tree.
BUT: If the number of points you're working with is really as low as in your question, your double loop might just be the fastest method! Algorithms with low Big-O curves will be faster as the amount of data gets really big, but it's often at the cost of a one-time slowdown (in your case, the sort) - and with only 15x20 data points... There won't be a human-perceptible difference; you might see one if you're timing it on your system clock. Or you might not.
Hope this helps!

Related

Extract elements given 2D matrix of column indices per row from a 2D matrix in MATLAB

I tried to resample my data from a block of matrix that defined its indices. Hopefully this example can make it clear:
A=rand(18400,100);
A_IDX=randi([1 100],[18400 100]);
A_IDX consist 18400 rows and 100 columns. I wanted to extract the matrix A at the A_IDX indices. Result would be something like:
A=[1 2 3; 4 5 6];
A_IDX=[1 3; 2 3];
A_Result=[1 3; 5 6];
I tried A(:,A_IDX) but that gave me 1840x184000 matrix size, which is not what I wanted to do in the first place. Anyone can help? Thanks in advance!
We could get the linear index equivalent for those indices and then simply indexing into the input array would give us the desired output. Now, to get those linear indices, we would make use of bsxfun for the math computations related to the index computations, which would basically involve scaling and offsetting.
Indexing with 2D array of column indices
For a 2D array of column indices, we would have -
function out = take_cols(a, col_idx)
n = size(a,1);
lidx = bsxfun(#plus,(col_idx-1)*n,(1:n).');
out = a(lidx);
Sample run -
>> a
a =
39 83 39 48 36
58 74 20 19 50
69 97 65 34 57
47 58 80 24 51
>> col_idx
col_idx =
2 4
3 5
1 4
2 5
>> take_cols(a, col_idx)
ans =
83 48
20 50
69 34
58 51
Indexing with 2D array of row indices
For a 2D array of row indices, it would be -
function out = take_rows(a, row_idx)
[m,n] = size(a);
lidx = bsxfun(#plus,row_idx, (0:n-1)*m);
out = a(lidx);
Sample run -
>> a
a =
39 83 39 48 36
58 74 20 19 50
69 97 65 34 57
47 58 80 24 51
>> row_idx
row_idx =
3 2 3 1 2
4 3 4 2 4
>> take_rows(a, row_idx)
ans =
69 74 65 48 50
47 97 80 19 51
This weird monster of code will give you what you want. It generates proper subscripts for each index and converts them to linear, then just indexes A linearly.
A_IDX_aux=A_IDX';
reshape(A(sub2ind(size(A),repelem(1:size(A,1),1,size(A_IDX,1)).',A_IDX_aux(:))),[size(A,1), size(A_IDX,2)]).';
I find my solution for this task too, but not so fast, as Divakar and Ander :)
Behold:
res = cell2mat(arrayfun( #(x) A(x,A_IDX(x,:)), (1:size(A,1))', 'UniformOutput',false));
It use cell2mat and I suppose it is not so fast as bsxfun, but hope is still alive and I was curios to test all the 3 solutions. And I got unobvious results!
Elapsed time is 0.000058 seconds. % Divakar
Elapsed time is 0.000077 seconds. % Andres
Elapsed time is 0.000339 seconds. % Me
This mean bsxf is fastest! But using right indexing give fast result too! And my solution was really slow. I suppose it's because of 'UniformOutput', false - I forced to convert to cells and then back, so it slow my method a lot.
Conclusion:
If you can use bsxf - use it!
Despite the fact that my method looks more visually pleasing than that of Andres, it is still slower.
So there is no any sense to post this answer :D I spend some time for current work, maybe it will help someone in future

How to define matrix values as a index in matlab?

I have 1788x3 double matrix.
My goal is split first and seconds columns values as a coordinates and create 256*256 matrix. Missing values will be zero.
That is the part of my matrix:
For example in 256*256 matrix (161,37) coordinates value will be 0.347365914411139
161 37 0.347365914411139
162 38 0.414350944291199
160 38 -0.904597803215328
165 35 -0.853613950415835
163 38 -0.926329070526244
166 35 -1.37361928823183
168 37 0.661707825299905
Looking forward your answers.
Regards;
The easiest, but not necessarily most efficient way to do this would be using a loop, i.e.
% if m = you 1788x3 data
x = sparse(256,256) %// x = zeros(256); % //use either of these
for nn = 1:size(m,1)
x(m(nn,1),m(nn,2)) = m(nn,3);
end

How to insert a value

I want to insert a number in the following matrix: n x 1 matrix
6
103
104
660
579
750
300
299
300
750
579
661
580
760
302
301
302
760
580
662
581
How to I insert it in the middle and shift the remaining numbers? I tried the following code:
Idx=[723];
c=false(1,length(Element_set2)+length(Idx));
c(Idx)=true;
result=nan(size(c));
result(~c)=Element_set2;
result(c)=8
You are complicating things. Simply find the middle index by finding the length of the array, dividing by 2 and truncating any decimal points, then using simply indexing to update the new matrix. Supposing that result is the column vector that was created by you and number is the value you want to insert in the middle, do the following:
number = 8; %// Change to suit whatever number you desire
middle = floor(numel(result) / 2);
result = [result(1:middle); number; result(middle+1:end)];
In the future, please read this great MATLAB tutorial on indexing directly from MathWorks: http://www.mathworks.com/company/newsletters/articles/matrix-indexing-in-matlab.html. It's a good resource on the kinds of indexing operations one expects from starting out in MATLAB.

Element-by-element max values in multidimensional matrix

I have a few multidimensional matrices of dimensions mxnxt, where each element in mxn is an individual sensor input, and t is time. What I want to do is analyse only the peak values for each element in mxn over t, so I would end up with a single 2D matrix of mxn containing only max values.
I know there are are ways to get a single overall max value, but is there a way to combine this with element-by-element operations like bsxfun so that it examines each individual element over t?
I'd be grateful for any help you can give because I'm really stuck at the moment. Thanks in advance!
Is this what you want?
out = max(A,[],3); %// checking maximum values in 3rd dimension
Example:
A = randi(50,3,3,3); %// Random 3x3x3 dim matrix
out = max(A,[],3);
Results:
A(:,:,1) =
35 5 8
38 12 42
23 46 27
A(:,:,2) =
50 6 39
4 49 41
23 1 44
A(:,:,3) =
5 41 10
20 22 14
13 46 8
>> out
out =
50 41 39
38 49 42
23 46 44
You can call max() with the matrix and select the dimension (look the documentation) on which the operation will be calculated, e.g
M = max(A,[],3)

Random sampling from gridded data: How to implement this in Matlab?

I have a 200x200 gridded data points. I want to randomly pick 15 grid points from that grid and replace the values in those grids with values selected from a known distribution shown below. All 15 grid points are assigned random values from the given distribution.
The given distribution is:
Given Distribution
314.52
1232.8
559.93
1541.4
264.2
1170.5
500.97
551.83
842.16
357.3
751.34
583.64
782.54
537.28
210.58
805.27
402.29
872.77
507.83
1595.1
The given distribution is made up from 20 values, which are part of those gridded data points. These 20 grid points are fixed i.e. they must not be part of randomly picking 15 points. The coordinates of these 20 points, which are fixed and should not be part of random picking, are:
x 27 180 154 183 124 146 16 184 138 122 192 39 194 129 115 33 47 65 1 93
y 182 81 52 24 168 11 90 153 133 79 183 25 63 107 161 14 65 2 124 79
Can someone help with how to implement this problem in Matlab?
Building off of my answer to your simpler question, here is a solution for how you can choose 15 random integer points (i.e. subscripted indices into your 200-by-200 matrix) and assign random values drawn from your set of values given above:
mat = [...]; %# Your 200-by-200 matrix
x = [...]; %# Your 20 x coordinates given above
y = [...]; %# Your 20 y coordinates given above
data = [...]; %# Your 20 data values given above
fixedPoints = [x(:) y(:)]; %# Your 20 points in one 20-by-2 matrix
randomPoints = randi(200,[15 2]); %# A 15-by-2 matrix of random integers
isRepeated = ismember(randomPoints,fixedPoints,'rows'); %# Find repeated sets of
%# coordinates
while any(isRepeated)
randomPoints(isRepeated,:) = randi(200,[sum(isRepeated) 2]); %# Create new
%# coordinates
isRepeated(isRepeated) = ismember(randomPoints(isRepeated,:),...
fixedPoints,'rows'); %# Check the new
%# coordinates
end
newValueIndex = randi(20,[1 15]); %# Select 15 random indices into data
linearIndex = sub2ind([200 200],randomPoints(:,1),...
randomPoints(:,2)); %# Get a linear index into mat
mat(linearIndex) = data(newValueIndex); %# Update the 15 points
In the above code I'm assuming that the x coordinates correspond to row indices and the y coordinates correspond to column indices into mat. If it's actually the other way around, swap the second and third inputs to the function SUB2IND.
I think yoda already gave the basic idea. Call randi twice to get the grid coordinate to replace, and then replace it with the appropriate value. Do that 15 times.