How to check range of values from one array into another array in MATLAB? - matlab

I have Two Arrays in MATLAB, Say A and B contains random values as below. Both arrays A and B always contain a pair; 2,4,6 or 8 or more elements (even number only) and A always has less elements than B. And elements in both arrays are pre-sorted.
A=[152 271];
B=[107 266 314 517 538 732];
I want to check the range of values of all pairs (one pair, 152-271 in this example) in A against all pairs of B. And expand/modify the values of pairs of B as such, if it exceed the B values. In this example, first to compare pair 152-271 of A with first pair of B (i.e. 107-266). As 152 is greater than 107, and 271 is greater than 266. We will modify 266 values of first pair of B with 271 to wholly include the range of first pair of A within B. Both intervals (range) in A and B should somewhat overlap to modify the B values.We will stop when there are no elements to check in A. The end result will be like this:
A=[152 271];
B=[107 271 314 517 538 732];
In this image below Green,Rad and Yellow represent A,B and final B (only modified) values respectively.

You can use find with the option last to identify the indices in B
A=[152 271 280 320];
B=[107 266 314 517 538 732];
for interval = 1:numel(A)-1
%get the index of the lower interval bound in B
index=find(B<=A(interval),1,'last');
%increase the upper interval bound if nessecary
B(index+1)=max(B(index+1),A(interval+1));
end
As you did not specify any corner cases (Intervals in A exceeds B) I did not conciser them. If they can happen, you need to extend the code.

A=[152 271];
B=[107 266 314 517 538 732];
mat=[A B];
A1 = vec2mat(mat,2)
n = size(mat,1);
[t,p] = sort(mat(:));
z = cumsum(accumarray((1:2*n)',2*(p<=n)-1));
z1 = [0;z(1:end-1)];
A2 = [t(z1==0 & z>0),t(z1>0 & z==0)]
% Reference Link: (http://www.mathworks.com/matlabcentral/newsreader/view_thread/171594) by Roger Stafford

Related

How to create a matrix which contains a selected set of pixels from another matrix based on a third one?

I have a grayscale matrix A with certain values that are black(i.e., pixel values of 0). I have another grayscale matrix B which is of the same size as A.
I want to create a matrix C which contains only those values of B where A is 0 and the rest of the values in B turn to white. For example,
A = [0 35 0 0 88];
B = [22 3 34 99 4];
The matrix C should be
C= [22 255 34 99 255];
I'm trying to use logical indexing as follows but it has errors.
C(A==0)=B;
C(A~=0)=255;
How do I change the above line to get the desired results?
You are trying to assign the whole of B to the smaller matrix of just locations where A==0.
In order to use only the correct number of values for assignment, the first line needs to be
C(A==0)=B(A==0);
It should be noted however that the same result can be gained simply by setting all of C to the corresponding B values (C = B) and then just modifying those where A~=0 as in your 2nd line.

Calculate the average of elements in a matrix that correspond to a value in a separate matrix

I have a 333 x 333 adjacency matrix which consists of values that I would like to average according to the identity of each cell, which is defined in a separate 333x1 vector. There are a total of 13 different groups defined in the second vector, so ideally, I'd be able to calculate a new 13 x 13 matrix in which each cell contained the average value of the corresponding values from the larger matrix.
matrix_1: 333 x 333 --> contains values for each pairwise interaction
vector_2: 333 x 1 --> contains the identity (range: 1 - 13) for each of the elements in matrix_1 (elements are the same in both the rows and columns)
ideal output = matrix_2: 13 x 13 --> contains values in each cell which reflect the mean score for all examples of the specific identity comparison.
e.g. matrix_2(1,1) --> should contain mean score of all 1 to 1 values from matrix_1
e.g. matrix_2(1,2) --> should contain mean score of all 1 to 2 values (and 2 to 1 values) from matrix_1
Thanks in advance
Mac
I'm not 100% certain from your description, but I guess you want:
[I,J] = ndgrid(V);
out = accumarray([I(:),J(:)], M(:), [], #mean);

Calculate a "running" maximum of a vector

I have the following matrix which keeps track of the starting and ending points of data ranges (the first column represents "starts" and the second column represents the "ends"):
myMatrix = [
162 199; %// this represents the range 162:199
166 199; %// this represents the range 166:199
180 187; %// and so on...
314 326;
323 326;
397 399;
419 420;
433 436;
576 757;
579 630;
634 757;
663 757;
668 757;
676 714;
722 757;
746 757;
799 806;
951 953;
1271 1272
];
I need to eliminate all the ranges (ie. rows) which are contained within a larger range present in the matrix. For example the ranges [166:199] and [180:187] are contained within the range [162:199] and thus, rows 2 and 3 would need to be removed.
The solution I thought of was to calculate a sort of "running" max on the second column to which subsequent values of the column are compared to determine whether or not they need to be removed. I implemented this with the use of a for loop as follows:
currentMax = myMatrix(1,2); %//set first value as the maximum
[sizeOfMatrix,~] = size(myMatrix); %//determine the number of rows
rowsToRemove = false(sizeOfMatrix,1); %//pre-allocate final vector of logicals
for m=2:sizeOfMatrix
if myMatrix(m,2) > currentMax %//if new max is reached, update currentMax...
currentMax = myMatrix(m,2);
else
rowsToRemove(m) = true; %//... else mark that row for removal
end
end
myMatrix(rowsToRemove,:) = [];
This correctly removes the "redundant" ranges in myMatrix and produces the following matrix:
myMatrix =
162 199
314 326
397 399
419 420
433 436
576 757
799 806
951 953
1271 1272
Onto the questions:
1) It would seem that there has to be a better way of calculating a "running" max than a for loop. I looked into accumarray and filter, but could not figure out a way to do it with those functions. Is there a potential alternative that skips the for loop (some kind of vectorized code that is more efficient)?
2) Is there a completely different (that is, more efficient) way to accomplish the final goal of removing all the ranges that are contained within larger ranges in myMatrix? I don't know if I'm over-thinking this whole thing...
Approach #1
bsxfun based brute-force approach -
myMatrix(sum(bsxfun(#ge,myMatrix(:,1),myMatrix(:,1)') & ...
bsxfun(#le,myMatrix(:,2),myMatrix(:,2)'),2)<=1,:)
Few explanations on the proposed solution:
Compare all starts indices against each other for "contained-ness" and similarly for ends indices. Note that the "contained-ness" criteria has to be for either of these two :
Greater than or equal to for starts and lesser than or equal to for ends
Lesser than or equal to for starts and greater than or equal to for ends.
I just so happen to go with the first option.
See which rows satisfy at least one "contained-ness" and remove those to have the desired result.
Approach #2
If you are okay with an output that has sorted rows according to the first column and if there are lesser number of local max's, you can try this alternative approach -
myMatrix_sorted = sortrows(myMatrix,1);
col2 = myMatrix_sorted(:,2);
max_idx = 1:numel(col2);
while 1
col2_selected = col2(max_idx);
N = numel(col2_selected);
labels = cumsum([true ; diff(col2_selected)>0]);
idx1 = accumarray(labels, 1:N ,[], #(x) findmax(x,col2_selected));
if numel(idx1)==N
break;
end
max_idx = max_idx(idx1);
end
out = myMatrix_sorted(max_idx,:); %// desired output
Associated function code -
function ix = findmax(indx, s)
[~,ix] = max(s(indx));
ix = indx(ix);
return;
I ended up using the following for the "running maximum" problem (but have no comment on its efficiency relative to other solutions):
function x = cummax(x)
% Cumulative maximum along dimension 1
% Adapted from http://www.mathworks.com/matlabcentral/newsreader/view_thread/126657
% Is recursive, but magically so, such that the number of recursions is proportional to log(n).
n = size(x, 1);
%fprintf('%d\n', n)
if n == 2
x(2, :) = max(x);
elseif n % had to add this condition relative to the web version, otherwise it would recurse infinitely with n=0
x(2:2:n, :) = cummax(max(x(1:2:n-1, :), x(2:2:n, :)));
x(3:2:n, :) = max(x(3:2:n, :), x(2:2:n-1, :));
end

Understanding Histogram in Matlab

I got the following results after applying:[h,bins]=hist(data), such that, the data will contain the LBP (Local Binary Pattern) values.
h =
221 20 6 4 1 1 2 0 0 1
bins =
Columns 1 through 7
8.2500 24.7500 41.2500 57.7500 74.2500 90.7500 107.2500
Columns 8 through 10
123.7500 140.2500 156.7500
I want to ask the following:
Does the first bin represent the values 0-8.25 and the second bin the values 8.26-24.75, and so forth?
For the h value 221, does it mean that we have computed 221 an LBP value ranging from 0-8.25?
1) No. The bin location is in the center value of the bin, that is, for the first bin the values are 0-16.5, the second bin is 16.5-33, etc. Use histc if it is more natural to specify bin edges instead of centers.
2) h(1)=221 means that from your entire data set (that has 256 elements according to your question), 221 elements had values ranging between 0-16.5 .

I need to order a list that is dependant on another list. how to change both lists?

I have a Matlab program that generates a list x = 6.1692 8.1863 5.8092 8.2754 6.0891 the program also outputs another list aspl = 680 637 669 599 693.
The two lists are on equal length and the first element in list x is related to the first element in list aspl. I need to graph the two lists but want list aspl to be in order from smallest to largest. How would I go about doing this? If I need to move the first element in aspl to position 4 in the list, then the first element of list x also needs to be moved to position 4 in list x. The numbers above are not important they are just examples, the actual program generates hundereds of numbers.
for example x = 6.1692 8.1863 5.8092 8.2754 initially
aspl = 680 637 669 599 693
after changing aspl to ascending order this is how x should look.
x = 5.8092 8.1863 5.8092 6.1692 8.2754
aspl = 599 637 669 680 693
Use the second output of sort:
%# sort aspl, get new order of aspl
[sortedAspl, sortOrder] = sort(aspl);
%# reorder x the same way as aspl
sortedX = x(sortOrder);