Comparison between vectors in matlab - matlab

if i have A=[3 4 5 6] and B=[6 5 4] then i want to compare each value in A with all values in B,
if this value is greater then increase counter with 1 and if this value is equal then increase another counter with 1

If you want an array that corresponds to the result of each value in A, you could do
arrayfun(#(x) sum(x > B), A)
this gives [0, 0, 1, 2]. If you want the total sum you would just put sum(...) around that:
sum(arrayfun(#(x) sum(x > B), A))
this gives 3.
For the equal-counter, you can simply change > to ==:
arrayfun(#(x) sum(x == B), A)
this gives [0, 1, 1, 1].

Another approach in comparison to arrayfun would be bsxfun. Though it takes a bit more memory, I'd argue that it's faster. arrayfun is implicitly a for loop and using loops in MATLAB is usually slower than vectorized approaches.
If you want the greater than case, use the gt function with bsxfun, so:
>> A = [3 4 5 6];
>> B = [6 5 4];
>> sum(bsxfun(#gt, A, B.'), 1)
ans =
0 0 1 2
If you want to accumulate all of the values that match the criterion, you can put another sum call within this bsxfun call:
>> sum(sum(bsxfun(#gt, A, B.'), 1))
ans =
3
For the greater than or equal case, use ge:
>> sum(bsxfun(#ge, A, B.'), 1)
ans =
0 1 2 3
For the equality case, use eq:
>> sum(bsxfun(#eq, A, B.'), 1)
ans =
0 1 1 1
Again, if you want to accumulate all of the values that match the criterion, nest another sum call with the above results.

Related

matlab/octave compare vectors using dictionary order?

Is there a succinct way in Octave to compare two vectors using dictionary order (lexicographic) order?
i.e. I'd like to compare two vectors a , b by the first element, return result if they differ; otherwise compare the second element, and so on..
For example, if a = [0 1 5] , b = [0 2 1], I'd like to have
a <? b
for some operator/function <? to return true.
If I simply do a < b, this will return a vector of logical values.
ans =
0 1 0
The following will work for both MATLAB and Octave...
You can create a comparison function using find like so:
lexlt = #(a, b) find([a < b true], 1) < find([a > b true], 1);
It will return true if the first vector argument is lexographically less than the second, and false otherwise (if it's greater than or equal to it). For example:
>> a = [0 1 5];
>> b = [0 2 1];
>> lexlt(a, a)
ans =
logical
0
>> lexlt(a, b)
ans =
logical
1
>> lexlt(b, a)
ans =
logical
0
And here's the corresponding function for a "greater than" comparison (i.e. the first argument is lexographically greater than the second):
lexgt = #(a, b) find([a > b true], 1) < find([a < b true], 1);
In Octave you can use issorted:
result = ~isequal(a,b) && issorted([a;b],'rows');
In MATLAB you can use issortedrows:
result = issortedrows([a;b],'strictascend')
Find first index which they are not equal. Then, compare them in the specified index.
idx = find(a ~= b);
result = a(idx(1)) < b(idx(1)); % if length(idx) > 0

Quantiles in Matlab

Would there be a function in matlab, or an easy way, to generate the quantile groups to which each data point belongs to?
Example:
x = [4 0.5 3 5 1.2];
q = quantile(x, 3);
ans =
1.0250 3.0000 4.2500
So I would like to see the following:
result = [2 1 2 3 1]; % The quantile groups
In other words, I am looking for the equivalent of this thread in matlab
Thanks!
You can go through all n quantiles in a loop and use logical indexing to find the quantile
n = 3;
q = quantile(x,n);
y = ones(size(x));
for k=2:n
y(x>=q(k)) = k;
end
Depending on how you define "quantile group", you could use:
If "quantile group" means how many values in q are less than x:
result = sum(bsxfun(#gt, x(:).', q(:)));
If "quantile group" means how many values in q are less than or equal to x:
result = sum(bsxfun(#ge, x(:).', q(:)));
If "quantile group" means index of the value in q which is closest to each value in x:
[~, result] = min(abs(bsxfun(#minus, x(:).', q(:))));
None of these returns the result given in your example, though: the first gives [2 0 1 3 1], the second [2 0 2 3 1], the third [3 1 2 3 1].

Find row-wise combinations of a 2 dimensional matrix

I have a matrix:
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
I want to find all row-wise combinations of X. i.e.
A(1) = [2, 6, 1; 3, 8, 1; 4, 7, 1]
A(2) = [2, 6, 1; 3, 8, 1; 6, 2, 1]
:
:
:
Here's what I've tried:
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
p = 3
[m, n] = size(X);
comb = combnk(1:m, p);
[s, t] = size(comb);
c = [X(comb(:,1), :, :) X(comb(:,2), :, :) X(comb(:,3), :, :)];
This gives me a matrix like:
c = 2 6 1 3 8 1 4 7 1
2 6 1 3 8 1 6 2 1
2 6 1 3 8 1 6 4 1
I want to apply the concatenate matrix option to obtain c to make it dynamic depending on value of p but I'm not sure how to use it. I don't want to use For loops. Please help me out.
This is fully vectorized, so it should be fast:
n = 3; %// number of rows to pick each time
ind = reshape(nchoosek(1:size(X,1), n).', [], 1); %'// indices of combinations
A = permute(reshape(X(ind,:).', size(X,2), n, []), [2 1 3]);
The result is
A(:,:,1)
ans =
2 6 1
3 8 1
4 7 1
A(:,:,2)
ans =
2 6 1
3 8 1
6 2 1
etc.
Should you need the result in the form of a cell array, you can convert A from 3D-array to cell array this way:
A = mat2cell(A, size(A,1), size(A,2), ones(1,size(A,3)));
Your thinking is pretty close. This code does the job. I put comments in code, which should be easy to read.
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
p = 3;
%// List all combinations choosing 3 out of 1:8.
v = nchoosek(1:size(X,1), p);
%// Use each row of v to create the matrices, and put the results in an cell array.
%// This is the A matrix in your question.
A = arrayfun(#(k)X(v(k,:), :), 1:size(v,1), 'UniformOutput', false);
%// And you can concatenate A vertically to get c.
flatA = cellfun(#(x)reshape(x, 1, []), A, 'UniformOutput', false);
c = vertcat(flatA{:});
PS: From my understanding I thought the result you wanted was A, which is an easy to use cell array. But I added an extra step to get c exactly as in your question just in case.
Disclaimer: arrayfun and cellfun are pretty much equivalent to for loop in terms of performance.
You can do it using reshape and a bunch of transposes since Matlab is column-major ordered:
c = reshape(X(comb',:)',9,[])'
or if you want a 3D matrix:
A = permute(reshape(X(comb',:)',3,3,[])', [2,1,3])

how to omit for loop when there is constrains

I have the following two arrays:
A = [1 2;3 4] and B = [1 5 4]
I want to do the following operation:
for each element of A(call it A(i))
for each element of B~=b do
( (A(i) - 1)/(b-1) ) * ( (A(i) - 5)/(b-5) ) * ( (A(i)- 4)/(b-4) )
end
end
It means that, sometimes the numerator equals to zero, so the product should be zeros. And I want to do the operation for the elements of B which are not equal to the b in denominator to not make it Inf.
How can I do this for the whole matrix A instead of using for loop?
Code
A = [1 2;3 4];
B = [1 5 4];
m1 = bsxfun(#minus,A,permute([1 5 4],[3 1 2]));
m2 = bsxfun(#minus,B,permute([1 5 4],[3 1 2]));
for k1=1:size(A,1)
for k2=1:size(A,2)
t2 = squeeze(bsxfun(#rdivide,m1(k1,k2,:),m2));
t2(1:size(t2,1)+1:end)=1;
A1(k1,k2) = prod(t2(:)); %%// Output
end
end
Output
A1 =
0 -0.2500
-0.1111 0
You can remove the nested loops, but at least two issues there -
You would be going to 4th and 5th dimension with it, using bsxfun. So, debugging would be tough.
bsxfun with higher dimensions to my knowledge seems to get slower.
You could just do the operation, and correct later:
C = (A-1)./(B-1) .* (A-5)./(B-5) .* (A-4)./(B-4)
C(isinf(C)) = 0;
or
C(B==b) = 0;
Possibly you'd need bsxfun, I'm not clear on the size of the output you want...

Matlab swap

I am trying to create a function that will swap a specific number in a matrix with a specific number in the same matrix. For examlpe, if I start with A = [1 2 3;1 3 2], I want to be able to create B = [2 1 3; 2 3 1], simply by telling matlab to swap the 1's with the 2's. Any advice would be appreciated. Thanks!
If you have the following matrix:
A = [1 2 3; 1 3 2];
and you want all the ones to become twos and the twos to become ones, the following would be the simplest way to do it:
B = A;
B(find(A == 1)) = 2;
B(find(A == 2)) = 1;
EDIT:
As Kenny suggested, this can even be further simplified as:
B = A;
B(A == 1) = 2;
B(A == 2) = 1;
Another way to deal with the original problem is to create a permutation vector indicating to which numbers should the original entries be mapped to. For the example, entries [1 2 3] should be mapped respectively to [2 1 3], so that we can write
A = [1 2 3; 1 3 2];
perm = [2 1 3];
B = perm(A)
(advantage here is that everything is done in one step, and that it also works for operations more complicated than swaps ; drawback is that all elements of A must be positive integers with a known maximum)
Not sure why you would to perform that particular swap (row/column interchanges are more common). Matlab often denotes ':' to represent all of something. Here's how to swap rows and columns:
To swap rows:
A = A([New order of rows,,...], :)
To Swap columns:
A = A(:, [New order of columns,,...])
To change the entire i-th column:
A(:, i) = [New; values; for; i-th; column]
For example, to swap the 2nd and 3rd columns of A = [1 2 3;1 3 2]
A = A(:, [1, 3, 2])
A = [1 2 3; 1 3 2]
alpha = 1;
beta = 2;
indAlpha = (A == alpha);
indBeta = (A == beta);
A(indAlpha) = beta;
A(indBeta ) = alpha
I like this solution, it makes it clearer what is going on. Less magic numbers, could easily be made into a function. Recycles the same matrix if that is important.
I don't have a copy of MatLab installed, but I think you can do some thing like this;
for i=1:length(A)
if (A(i)=1), B(i) = 2, B(i)=A(i)
end
Note, that's only convert 1's to 2's and it looks like you also want to convert 2's to 1's, so you'll need to do a little more work.
There also probably a much more elegant way of doing it given you can do this sort of thing in Matlab
>> A = 1:1:3
A = [1,2,3]
>> B = A * 2
B = [2,4,6]
There might be a swapif primitive you can use, but I haven't used Matlab in a long time, so I'm not sure the best way to do it.
In reference to tarn's more elegant way of swapping values you could use a permutation matrix as follows:
>> a =[1 2 3];
>> T = [1 0 0;
0 0 1;
0 1 0];
>> b = a*T
ans =
1 3 2
but this will swap column 2 and column 3 of the vector (matrix) a; whereas the question asked about swapping the 1's and 2's.
Update
To swap elements of two different values look into the find function
ind = find(a==1);
returns the indices of all the elements with value, 1. Then you can use Mitch's suggestion to change the value of the elements using index arrays. Remeber that find returns the linear index into the matrix; the first element has index 1 and the last element of an nxm matrix has linear index n*m. The linear index is counted down the columns. For example
>> b = [1 3 5;2 4 6];
>> b(3) % same as b(1,2)
ans = 3
>> b(5) % same as b(1,3)
ans = 5
>> b(6) % same as b(2,3)
ans = 6