find elements occurring more than once and delete matlab - matlab

I have troubles in solving this problem and I ask for your help..
suppose that I have a vector
vector1 = [ 1 1 2];
with an associated error vector (the first element of vector1 is linked with the first element of error1)
error1= [0.08 0.9 0.3];
if vector1 contains 2 equal elements (first and second element in this case) I should replace the element with the highest error with NaN
Any help is appreciated.

I assume the following things:
vector1 can have more than 2 equal elements.
error1 can contain negative values.
This may not be the fastest solution, but it works, according to me.
% Generating random inputs
vector1=[1 2 2 1 1 1 3 3 4 4 5 5 6];
error=3*randn(1,13);
% Sorting the vector
[vector2,I]=sort(vector1);
error2=error(I);
% finding unique elements and the range of repeated elements is stored in b2
[~,b,~]=unique(vector2)
b2=[b [b(2:end)-1;length(vector2)]]
b2((b2(:,1)-b2(:,2))==0,:)=[]
% Calculating maximum error for those repeated indices.
for i=1:size(b2,1)
[~,ind]=max(error2(b2(i,1):b2(i,2)));
maxErrorInd(i,1)=ind+b2(i,1)-1;
end
% Replacing with NaN
vector2(maxErrorInd)=NaN
% Mapping back since we had sorted
vector3(I)=vector2
error3(I)=error2

See if this works for you -
presence_vec_ele = double(bsxfun(#eq,vector1,unique(vector1)'))
presence_vec_ele(presence_vec_ele==0)=nan
[~,min_ind] = nanmin(bsxfun(#times,presence_vec_ele,error1),[],2)
error1(setdiff(1:numel(error1),min_ind))=NaN

Related

Matlab: Remove rows when first and last 2 elements are shuffled

I have a matrix where each element is a single unit of a 2d coordinate. As such, each element in any given row are paired, where elements in the first column are paired with those in the second, and elements in the third column paired with the fourth. All possible combinations of the 4 numbers are present in the matrix.
What I need to do is depup the matrix by removing rows where the first set of coordinates (e.g columns 1 and 2 in a row) are swapped with the second set of coordinates. For example if one row contains the value "3, 4, 2, 1" then I would need to remove "2, 1, 3, 4" from else where in the matrix.
An example of this could be seen below, where I would want to remove the last row, as it is the reverse of the first row;
3 3 1 1
1 2 2 3
3 4 1 2
4 4 3 1
4 1 4 4
1 1 3 3
I'm quite stumped as to how to do this, and my previous attempts have all failed. Whilst it may not be useful to the answer, I have included my code showing how I am constructing the initial matrix below;
%create list of all piece coordinates
p1_row_index=(1:n);
p1_column_index=(1:n);
p2_row_index=(1:n);
p2_column_index=(1:n);
% get all possible combinations of these variables
[p1_row_index,p1_column_index,p2_row_index,p2_column_index]=BalanceFactors(1,1,1:n,1:n,1:n,1:n);
pc_list(:,1)=p1_row_index; % piece1 coordiantes for rows
pc_list(:,2)=p1_column_index; % piece1 coordiantes for columns
pc_list(:,3)=p2_row_index; % piece2 coordiantes for rows
pc_list(:,4)=p2_column_index; % piece2 coordiantes for columns
Thank you for your time.
Many thanks,
Matt
Complex numbers come in handy for this:
[~, ind] = unique(sort(M(:,[1 3])+1j*M(:,[2 4]), 2), 'rows', 'stable');
result = M(ind, :);
The code works as follows:
M(:,[1 3])+1j*M(:,[2 4]) creates a complex matrix with half the columns, where each pair of coordinates of the original matrix becomes a complex number.
sort(..., 2) sorts each row. Rows that originally were shuffled versions of each other now become identical.
[~, ind] = unique(..., 'rows', 'stable') gives the index of the first occurrence of each unique (complex, sorted) row.
M(ind, :) selects the desired rows from M.

Find indices in each column and intelligently average the values in the same column based on the indices

I have a matrix that every column is independent of the each other. That said, each column has a minimum of 0 and maximum of 1, it's a probability. However, it's not necessary that each column only contain one 1. This will create a problem for me as I try to find the indices of each column that consists 1. The indexes will be used to extract the value of another matrix, let's say position matrix. If it contain two 1, the values should be averaged. Example code:
prob=[rand(4,1) rand(4,1) rand(4,1)];
max_prob_idx=find(prob==1);
%extract from position matrix
pos=rand(4,3);
extracted_pos=pos(max_prob_idx); %this is wrong, look example below
From the above code, I will obtain a column vector of extracted_pos. This messed up my data extraction. Numerically:
prob=[1 0 1
0.1 1 0.8
0.2 0.5 1
0.3 1 1]
max_prob_idx=[1; 6; 8; 9; 11; 12];
pos=[1 5 9
2 6 10
3 7 11
4 8 12]
extracted_pos=[1; 6; 8; 9; 11; 12]; %6x1 matrix
I'm missing something in between so that my final expected extracted_pos would be
extracted_pos=[1; (6+8)/2; (9+11+12)/3]; %3x1 matrix
I know this looks quite messy but I can't think any other way to explain my problem here. Can this be done? Or there is other way to do this? Thanks in advance!
% generate position matrix
pos = reshape(1:numel(prob),size(prob)); % technically the reshape is not necessary, a vector 1:numel(prob) would do it too, but I find it nicer.
% empty NaN matrix
P = nan(size(prob));
% extract 1 values
P(prob==1) = pos(prob==1); % with real data you might have to make a check with tolerance
% mean of each column
extracted_pos = mean(P,1,'omitnan');
extracted_pos may of course contain floating point numbers - it's up to you how to handle them

sum matrix using logical matrix - index exceeds matrix dimensions

I have two matrices.
mcaps which is a double 1698 x 2
index_g which is a logical 1698 x 2
When using the line of code below I get the error message that Index exceeds matrix dimensions. I don't see how this is the case though?
tsp = nansum(mcaps(index_g==1, :));
Update
Sorry I should have mentioned that I need the sum of each column in the mcaps vector
** Example of data **
mcaps index_g
5 6 0 0
4 3 0 0
6 5 1 1
4 6 0 1
8 7 0 0
There are two problems here. I missed one. Original answer is below.
What I missed is that when you use the logical index in this way, you are picking out elements of the matrix that may have different numbers of elements in each column, so MATLAB can't return a well formed matrix back to nansum, and so returns a vector. To get around this, use the fact that 0 + anything = 0
% create a mask of values you don't want to sum. Note that since
% index_g is already logical, you don't have to test equal to 1.
mask = ~index_g & isnan(mcaps)
% create a temporary variable
mcaps_to_sum = mcaps;
% change all of the values that you don't want to sum to zero
mcaps_to_sum(mask) = 0;
% do the sum
sum(mcaps_to_sum,1);
This is basically all that the nansum function does internally, is to set all of the NaN values to zero and then call the sum function.
index_g == 1 returns a 1698 x 2 logical matrix, but then you add in an extra dimension with the colon. To sum the columns, use the optional dim input. You want:
tsp = nansum(mcaps(index_g == 1),1);

Eliminating zeros in a matrix - Matlab

Hi I have the following matrix:
A= 1 2 3;
0 4 0;
1 0 9
I want matrix A to be:
A= 1 2 3;
1 4 9
PS - semicolon represents the end of each column and new column starts.
How can I do that in Matlab 2014a? Any help?
Thanks
The problem you run into with your problem statement is the fact that you don't know the shape of the "squeezed" matrix ahead of time - and in particular, you cannot know whether the number of nonzero elements is a multiple of either the rows or columns of the original matrix.
As was pointed out, there is a simple function, nonzeros, that returns the nonzero elements of the input, ordered by columns. In your case,
A = [1 2 3;
0 4 0;
1 0 9];
B = nonzeros(A)
produces
1
1
2
4
3
9
What you wanted was
1 2 3
1 4 9
which happens to be what you get when you "squeeze out" the zeros by column. This would be obtained (when the number of zeros in each column is the same) with
reshape(B, 2, 3);
I think it would be better to assume that the number of elements may not be the same in each column - then you need to create a sparse array. That is actually very easy:
S = sparse(A);
The resulting object S is a sparse array - that is, it contains only the non-zero elements. It is very efficient (both for storage and computation) when lots of elements are zero: once more than 1/3 of the elements are nonzero it quickly becomes slower / bigger. But it has the advantage of maintaining the shape of your matrix regardless of the distribution of zeros.
A more robust solution would have to check the number of nonzero elements in each column and decide what the shape of the final matrix will be:
cc = sum(A~=0);
will count the number of nonzero elements in each column of the matrix.
nmin = min(cc);
nmax = max(cc);
finds the smallest and largest number of nonzero elements in any column
[i j s] = find(A); % the i, j coordinates and value of nonzero elements of A
nc = size(A, 2); % number of columns
B = zeros(nmax, nc);
for k = 1:nc
B(1:cc(k), k) = s(j == k);
end
Now B has all the nonzero elements: for columns with fewer nonzero elements, there will be zero padding at the end. Finally you can decide if / how much you want to trim your matrix B - if you want to have no zeros at all, you will need to trim some values from the longer columns. For example:
B = B(1:nmin, :);
Simple solution:
A = [1 2 3;0 4 0;1 0 9]
A =
1 2 3
0 4 0
1 0 9
A(A==0) = [];
A =
1 1 2 4 3 9
reshape(A,2,3)
ans =
1 2 3
1 4 9
It's very simple though and might be slow. Do you need to perform this operation on very large/many matrices?
From your question it's not clear what you want (how to arrange the non-zero values, specially if the number of zeros in each column is not the same). Maybe this:
A = reshape(nonzeros(A),[],size(A,2));
Matlab's logical indexing is extremely powerful. The best way to do this is create a logical array:
>> lZeros = A==0
then use this logical array to index into A and delete these zeros
>> A(lZeros) = []
Finally, reshape the array to your desired size using the built in reshape command
>> A = reshape(A, 2, 3)

Matlab find Series of First Negative Number

With a matrix of numbers in Matlab, how would you find the first negative number after a series of positive numbers?
So far, the only answer I could come up with was to write a loop to check for the first negative number, then record it, then look for the first positive number, and truncate the array there, then start over. Is there a vectorized way to do this?
e.g., I have x = [ -1 -5 -2 3 4 8 -2 -3 1 9], and I want this function or script to give me an array of y = [1 7].
or
find(diff(sign([1 x]))<0)
that is to say: find the locations in x where the difference in sign between successive elements is negative, oh and pushing a 1 onto the front of x to take care of the case where the 1st element is already negative
This is a quite home made solution, check it out
x = [ -1 -5 -2 3 4 8 -2 -3 1 9]
neg_idx = find(x < 0) % // negative values
z = [0 diff(neg_idx)] % // increments among indices of successive values;
% // consecutive indices return a difference of 1 whereas
% // non consecutive return a value greater than 1.
% // because the first element must be distinguished
% // we put the zero in front
id = find(z ~= 1) % // Every time there is a jump, a non consecutive neg.
% // value appears
% // thus the solution is in
y = neg_idx(id)
ans =
1 7
If neg_idx is empty (i.e. no negative value is involved) you will get an Index exceeds matrix dimensions, although the condition is immediate to check.