Find the same values in another column in matlab - matlab

i want to find same values of number in different column,
for example i have a matrix array:
A = [1 11 0.17
2 1 78
3 4 90
45 5 14
10 10 1]
so as you can see no. 1 in column 1 have the same values in column 2 and column 3, so i want to pick that number and put into another cell or matrix cell
B= [1]
and perform another operation C/B, letting C is equal to:
C= [1
3
5
7
9]
and you will have:
D= [1 11 0.17 1
2 1 78 3
3 4 90 5
45 5 14 7
10 10 1 9]
then after that, values in column 4 have equivalent numbers that we can define, but we will choose only those number that have number 1, or B in theirs row
define:
1-->23
3 -->56
9 --> 78
then we have, see image below:
so how can i do that? is it possible? thanks

Let's tackle your problem into steps.
Step #1 - Determine if there is a value shared by all columns
We can do this intelligently by bsxfun, unique, permute and any and all.
We first need to use unique so that we can generate all possible unique values in the matrix A. Once we do this, we can look at each value of the unique values and see if all columns in A contain this value. If this is the case, then this is the number we need to focus on.
As such, do something like this first:
Aun = unique(A);
eqs_mat = bsxfun(#eq, A, permute(Aun, [3 2 1]));
eqs_mat would generate a 3D matrix where each slice figures out where a particular value in the unique array appeared. As such, for each slice, each column will have a bunch of false values but at least one true value where this true value tells you the position in the column that matched a unique value. The next thing you'll want to do is go through each slice of this result and determine whether there is at least one non-zero value for each column.
For a value to be shared along all columns, a slice should have a non-zero value per column.
We can eloquently determine which value we need to extract by:
ind = squeeze(all(any(eqs_mat,1),2));
Given your example data, we have this for our unique values:
>> B
B =
0.1700
1.0000
2.0000
3.0000
4.0000
5.0000
10.0000
11.0000
14.0000
45.0000
78.0000
90.0000
Also, the last statement I executed above gives us:
>> ind
ind =
0
1
0
0
0
0
0
0
0
0
0
0
The above means that the second location of the unique array is the value we want, and this corresponds to 1. Therefore, we can extract the particular value we want by:
val = Aun(ind);
val contains the value that is shared along all columns.
Step #2 - Given the value B, take a vector C and divide by B.
That's pretty straight forward. Make sure that C is the same size as the total number of rows as A, so:
C = [1 3 5 7 9].';
B = val;
col = C / B;
Step #3 - For each location in A that shares the common value, we want to generate a new fifth column that gives a new value for each corresponding row.
You can do that by declaring a vector of... say... zeroes, then find the right rows that share the common value and replace the values in this fifth column with the values you want:
zer = zeros(size(A,1), 1);
D = [23; 56; 78];
ind2 = any(A == val, 2);
zer(ind2) = D;
%// Create final matrix
fin = [A col zer];
We finally get:
>> fin
fin =
1.0000 11.0000 0.1700 1.0000 23.0000
2.0000 1.0000 78.0000 3.0000 56.0000
3.0000 4.0000 90.0000 5.0000 0
45.0000 5.0000 14.0000 7.0000 0
10.0000 10.0000 1.0000 9.0000 78.0000
Take note that you need to make sure that what you're assigning to the fifth column is the same size as the total number of columns in A.

Related

How to make the size(B,1) = size(A,1)?

I'm trying to Write a function that takes a matrix A as an input and returns the matrix B as the output. B has the same number of rows as A.
Each element of the first column of B contains the mean of the corresponding row of A.
The second column contains the median values.
While the third column has the minimums.
Each element of the fourth column of B is equal to the maximum value of given row of A.
function B = simple_stats (A)
n = size(A,1);
x = A(1,:);
y = median(A);
z = min(A);
r = max(A);
B = [x.',y.',z.',r.'];
B(1:n,:); % Here I have a problem and B has not the same number of rows as A.
end
You need to specify that you want to compute the median, mean, min and max across the second dimension of your matrix A. By default, all of these functions operate along the first dimension (down the columns). All of these functions take a dim parameter which is used to specify the dimension along which to apply the operation.
A = randi(10, 5, 3);
%// 8 3 3
%// 8 2 1
%// 6 3 5
%// 2 9 1
%// 6 1 9
B = [mean(A, 2), median(A, 2), min(A, [], 2), max(A, [], 2)];
%// 4.6667 3.0000 3.0000 8.0000
%// 3.6667 2.0000 1.0000 8.0000
%// 4.6667 5.0000 3.0000 6.0000
%// 4.0000 2.0000 1.0000 9.0000
%// 5.3333 6.0000 1.0000 9.0000

Rearranging elements in a row matlab

I have two matrices in Matlab.
A =
and
B =
I want to assign the elements having the same cell-value according to it's corresponding column number in A matrix and move the elements there. I want to map the elements of B with A so that B elements also moves in that position.
I want this
A =
And therefore,
B =
Is there a way to do this?!
Thanks.
Easiest way I can think of is to create row/column pairs where the rows correspond row locations of the matrix and column locations are the actual elements of the matrix themselves. The values seen at these row/column pairs are again just the matrix values themselves.
You can very easily do this with sparse. Recreating the matrix above and storing this in A:
A = [1 2 5 8; 1 2 4 7];
... I would do it this way:
r = repmat((1:size(A,1)).', 1, size(A,2)); %'
S = full(sparse(r(:),A(:),A(:)));
The first line of code generates row locations for each value in the matrix A, then using sparse to specify row/column pairs and the associated values and we use full to convert to a proper numeric matrix.
We get:
S =
1 2 0 0 5 0 0 8
1 2 0 4 0 0 7 0
You can also do the same for the matrix B. You'd use sparse and specify the third parameter to be B instead:
B = [0.5 0.2 0.6 0.8; 0.4 0.6 0.8 0.9];
S2 = full(sparse(r(:),A(:),B(:)));
We get:
>> S2
S2 =
0.5000 0.2000 0 0 0.6000 0 0 0.8000
0.4000 0.6000 0 0.8000 0 0 0.9000 0

Average for all elements in a row except the element itself - MATLAB

For a given matrix A, how can i create a matrix B of the same size where every column is the mean (or any other function) of all the other columns?
example:
a function on
A = [
1 1 1
2 3 4
4 5 6]
should result in
B = [
1 1 1
3.5 3 2.5
5.5 5 4.5]
Perfect setup for bsxfun -
B = bsxfun(#minus,sum(A,2),A)./(size(A,2)-1)
Explanation: Breaking it down to two steps
Given
>> A
A =
1 1 1
2 3 4
4 5 6
Step #1: For each element in A, calculate the sum of all elements except the element itself -
>> bsxfun(#minus,sum(A,2),A)
ans =
2 2 2
7 6 5
11 10 9
Step #2: Divide each element result by the number of elements responsible for the summations, which would be the number of columns minus 1, i.e. (size(A,2)-1) -
>> bsxfun(#minus,sum(A,2),A)./(size(A,2)-1)
ans =
1.0000 1.0000 1.0000
3.5000 3.0000 2.5000
5.5000 5.0000 4.5000
Using your example:
[m,n]=size(A);
B=zeros(m,n);
for k=1:n
B(:,k) = mean(A(:,[1:k-1 k+1:end]),2);
end
It may not be as quick or efficient as #Divakar's answer, but I tend to prefer for loop due to better readability. It might also make it easier to call a different function from mean.
For an arbitrary function, you can use a vectorized approach if you don't mind using up more memory. Specifically, this requires generating a 3D array of size rxcxc, where r and c are the number of rows and columns of A.
f = #(x) prod(x,2); %// any function which operates on columns
c = size(A,2); %// number of columns
B = repmat(A, [1 1 c]);
B(:,1:c+1:end) = []; %// remove a different column in each 3D-layer
B = reshape(B, [], c-1, c); %// each 3D-layer of B contains a set of c-1 columns
result = f(B); %// apply function
result = squeeze(result); %// remove singleton dimension
As noted by Divakar in comments, anonymous functions tend to slow things down. It may be better to define the function f in a file.

Conflicts with a simple loop to keep record of row switches in matlab

I made a loop to keep track of loop switches.
C = zeros(i,2);
for q=1:i
if any(A(q,:)~= K(q,:))
%Save the row at which B is different(aka Ending Position)
C(q,2) = q;
for a=1:i
if A(a,:) == K(q,:)
C(q,1) = a;
end;
end
end
end
A and B are the two matrices. C is the one storing the switches. But for some reason the last row of C has a 3, which is not supposed to happen since [2 3 1] = [2 3 1]
A =
1 3 1
3 2 1
2 3 1
K =
3.0000 2.0000 1.0000
1.0000 3.0000 1.0000
2.0000 3.0000 1.0000
C =
2 1
1 2
0 3
Take a look at this statement:
if A(a,:) == K(q,:)
C(q,1) = a;
end
I suspect you only want this statement to happen if all of the elements between A(a,:) and K(q,:) are true. As such, you must use the all command to ensure that this is true. By omitting the all, this statement will be true if at least one element between these two vectors is true, which explains the unexpected behaviour. As such:
if all(A(a,:) == K(q,:))
C(q,1) = a;
end
With your example inputs, this is what I get for C:
C =
2 1
1 2
0 0
The last row being [0 0] symbolizes that the third rows between A and K were the same and not swapped, as nothing was assigned to the last row of C during that loop.

MATLAB Remove rows with second/third occurence of duplicate index

I have a large matrix with two columns. First is an index, second is data. Some indices are repeated. How can I retain only the first instance of rows with repeated indices?
For Example:
x =
1 5.5
1 4.5
2 4
3 2.5
3 3
4 1.5
to end up with:
ans =
1 5.5
2 4
3 2.5
4 1.5
I've tried various variations and iterations of
[Uy, iy, yu] = unique(x(:,1));
[q, t] = meshgrid(1:size(x, 2), yu);
totals = accumarray([t(:), q(:)], x(:));
but nothing so far has given me the output I need.
Use the 'first' tag in the unique function and then the second output supplies you with the row indices you want which you can use to 'filter' your matrix.
[~, ind] = unique(x(:,1), 'first');
ans = x(ind, :)
ans =
1.0000 5.5000
2.0000 4.0000
3.0000 2.5000
4.0000 1.5000
EDIT
or as Jonas points out (esp for old Matlab releases)
[~, ind] = unique(flipud(x(:,1)));
ans = x(flipud(ind), :)