matlab replace number - matlab

in a column, value 2 replace with 1 and value 1 & 3 replace with 2. The code i wrote below got problem:
S=[1 1 1 2 2 3 3 3 3];
S(S==2)=1; S(S==1)=2; S(S==3)=2;
result:
S=[2 2 2 2 2 2 2 2 2]
However, the result i wan to get is S=[2 2 2 1 1 2 2 2 2]. does anyone can help?

That is happening because when in the S(S==1)=2; step, you are affected by the modifications from the S(S==2)=1; step. Try this
S = [1 1 1 2 2 3 3 3 3];
S_copy = S;
S(S_copy == 2) = 1; S(S_copy == 1) = 2; S(S_copy == 3) = 2;
or you could also save the results of the tests into separate variables:
S = [1 1 1 2 2 3 3 3 3];
f1 = (S == 2);
f2 = (S == 1);
f3 = (S == 3);
S(f1) = 1; S(f2) = 2; S(f3) = 2;

Instead of manually replacing each value, you can use an extra matrix to define a "map" from input values in S to output values.
>> S = [1 1 1 2 2 3 3 3 3]; % input
>> M = [2 1 2]; % M[i] = j -> map value i to j
>> S = M(S) % compute output
S =
2 2 2 1 1 2 2 2 2
This operation should be really fast in Matlab.
Note that this methods works as long as the values in S can be interpreted as index values (that is, they are integers and not too large).

your are getting closer but the problem arises once you change all the 2's to one.
after this statement
S(S==2)=1;
the array looks like this
S=[1 1 1 1 1 3 3 3 3];
and after the other two statements S(S==1)=2; S(S==3)=2;
your array will obviously have all 2's.
Instead of
S(S==2)=1; S(S==1)=2; S(S==3)=2;
you can do like this:
S(S==2)=-1; S(S==1)=2; S(S==3)=2;S(S==-1)=1;
i.e. in the first step change all the 2's to some other value(e.g. -1 here) and then do the required conversion i.e. S(S==-1)=1;

Related

Create a multidimensional array following a pattern

I am making a 3 dimensional array, using matlab, that progresses according to a pattern. Athough I could write out the Array manually I am sure there is a quicker way to do it.
multiArray = cat(3,...
[1+randn(4,3); 1*randn(4,3)],...
[2+randn(4,3); 2*randn(4,3)],...
[3+randn(4,3); 3*randn(4,3)]);
If I want to make the above array to be 8x3x25 then the last line would be
[25+randn(4,3); 25*randn(4,3)]
But how can I make such an array without going through all the tedious intervening steps?
While mikkola basically got the solution, there is no need to shift dimensions at the end.
s=[4,3,25];
it=reshape(1:s(3),1,1,[]);
out = [bsxfun(#plus , it, randn(s));...
bsxfun(#times, it, randn(s))];
Here's a possible way using bsxfun.
%// 25 x 4 x 3 with elements for i + randn(4,3)
P = bsxfun(#plus, (1:25)', randn(25,4,3));
%// 25 x 4 x 3 with elements for i * randn(4,3)
T = bsxfun(#times, (1:25)', randn(25,4,3));
%// Concatenate and shift dimensions to get desired size output
multiArray = shiftdim([P T], 1);
If you don't mind taking things to 4D for efficiency purposes -
N = 25; %// Number of 3D slices
out = randn(4,2,3,N);
out(:,1,:,:) = bsxfun(#plus,permute(1:N,[1 4 3 2]),out(:,1,:,:));
out(:,2,:,:) = bsxfun(#times,permute(1:N,[1 4 3 2]),out(:,2,:,:));
out = reshape(out,8,3,N);
To legitimize the solution, let's start off with an input of A = randn(8,3,N) and initialize the output out with it. Also, let's take number of 3D slices as a small number, so say N = 3.
Thus,
>> N = 3;
A = randn(8,3,N);
out = reshape(A,[4 2 3 N]); %// This replaces "out = randn(4,2,3,N)"
Next up, we run the code that will change out -
>> out(:,1,:,:) = bsxfun(#plus,permute(1:N,[1 4 3 2]),out(:,1,:,:));
out(:,2,:,:) = bsxfun(#times,permute(1:N,[1 4 3 2]),out(:,2,:,:));
out = reshape(out,8,3,N);
Now, start validating per 3D slice -
>> out(1:4,:,1) - A(1:4,:,1)
ans =
1 1 1
1 1 1
1 1 1
1 1 1
>> out(1:4,:,2) - A(1:4,:,2)
ans =
2 2 2
2 2 2
2 2 2
2 2 2
>> out(1:4,:,3) - A(1:4,:,3)
ans =
3 3 3
3 3 3
3 3 3
3 3 3
>> out(5:end,:,1)./A(5:end,:,1)
ans =
1 1 1
1 1 1
1 1 1
1 1 1
>> out(5:end,:,2)./A(5:end,:,2)
ans =
2 2 2
2 2 2
2 2 2
2 2 2
>> out(5:end,:,3)./A(5:end,:,3)
ans =
3 3 3
3 3 3
3 3 3
3 3 3

Find the count of elements in one matrix equal to another

I need to compare the elements of two matrices and return a count of how many rows are exactly same. The ismember function returns one column for each column present in the matrix. But I want just one column indicating whether the row was same or not. Any ideas will be greatly appreciated.
If you want to compare corresponding rows of the two matrices, just use
result = all(A==B, 2);
Example:
>> A = [1 2; 3 4; 5 6]
A =
1 2
3 4
5 6
>> B = [1 2; 3 0; 5 6]
B =
1 2
3 0
5 6
>> result = all(A==B, 2)
result =
1
0
1
If you want to compare all pairs of rows:
result = pdist2(A,B)==0;
Example:
>> A = [1 2; 3 4; 1 2]
A =
1 2
3 4
1 2
>> B = [1 2; 3 0]
B =
1 2
3 0
>> result = pdist2(A,B)==0
result =
1 0
0 0
1 0

Find set intersection of multiple arrays in MATLAB

I tried to solve this problem, but I could not implement.
Could you help me anything for this?
Problem
Mat1 | Mat2 | Mat3
1 2 | 1 3 | 2 6
1 3 | 2 6 | 2 5
2 4 | 3 1 | 3 1
3 1 | 3 5 | 5 2
4 5 |
When there are 3 matrices(for example above), I want to get this result for the intersection rows in [column1 column2 matrixnumber] form.
The result for above example would be
1 3 1
1 3 2
2 6 2
2 6 3
3 1 1
3 1 2
3 1 3
It would be OK if the result is in the form [column1 column2 firstmatrix secondmatrix, ...]
1 3 1 2
2 6 2 3
3 1 1 2 3
For this problem, I want to use at most one for-loop.
Do you have any idea for this?
Here an alternative solution (which seems to run faster than Gunther's) using MATLAB's intersect:
Mat = {[1 2; 1 3; 2 4; 3 1; 4 5],
[1 3; 2 6; 3 1; 3 5],
[2 6; 2 5; 3 1; 5 2]};
result = zeros(sum(cellfun(#(x)size(x, 1), Mat)), 3); % # Preallocate memory
k = 1;
for cc = transpose(nchoosek(1:numel(Mat), 2))
x = intersect(Mat{cc}, 'rows'); % # Find intersection
y = ones(size(x, 1), 2) * diag(cc); % # Generate matrix indices
result(k:k + numel(y) - 1, :) = [[x; x], y(:)];
k = k + numel(y);
end
result(all(~result, 2), :) = []; % # Discard zero rows
result = unique(result, 'rows'); % # Discard repeated rows
The matrix result should now contain the unique intersection rows and their corresponding matrix indices, just like you want:
result =
1 3 1
1 3 2
2 6 2
2 6 3
3 1 1
3 1 2
3 1 3
If I understand correctly, you have a number of sets of pairs: Mat1,Mat2, Mat3, ... MatN. Now you want to find the unique pairs and then find out in which set every unique pair appears.
If you have a large number of sets, I suggest you start using a cell array to hold them all, makes things a lot easier:
N = 3; % total number of data sets
Mat = cell(N,1);
Mat{1} = [1 2;
1 3;
2 4;
3 1;
4 5];
Mat{2} = [1 3;
2 6;
3 1;
3 5];
Mat{3} = [2 6;
2 5;
3 1;
5 2];
% etc.
First let's find the unique pairs:
uniq_pairs = unique(cat(1,Mat{:}),'rows');
M = size(uniq_pairs ,1);
Then use ismember to check which sets contain which pairs:
matcontpair = false(M,N); %preallocate
for ii=1:N % unavoidable loop
matcontpair(:,ii) = ismember(uniq_pairs,Mat{ii},'rows');
end
To translate this intersection matrix to a set of matrix numbers for each pair, loop through it again and store the final result in a cell array (you can't use an array, because they might not be of same size (some pairs only found once, other twice, other three times ...)
pair_occurence= cell(M,1);
d=1:N;
for jj=1:M
pair_occurence{jj} = d(matcontpair(jj,:));
end
Now you have a matrix uniq_pairs of size Mx2 containing the unique pairs, and a occurence cell array pair_occurence of size Mx1: each cell corresponds to a pair and contains a list of matrices where the pair is present.
If you want to remove pairs from the list which are only present in one matrix, use the following:
% find them
lonely_pairs = cellfun(#numel,pair_occurence)<2;
% and destroy them
uniq_pairs(lonely_pairs,:) = [];
pair_occurence(lonely_pairs) = [];

Expand matrix based on first row value (MATLAB)

My input is the following:
X = [1 1; 1 2; 1 3; 1 4; 2 5; 1 6; 2 7; 1 8];
X =
1 1
1 2
1 3
1 4
2 5
1 6
2 7
1 8
I am looking to output a new matrix based on the value of the first column. If the value is equal to 1 -- the output will remain the same, when the value is equal to 2 then I would like to output two of the values contained in the second row. Like this:
Y =
1
2
3
4
5
5
6
7
7
8
Where 5 is output two times because the value in the first column is 2 and the same for 7
Here it is (vectorized):
C = cumsum(X(:,1))
A(C) = X(:,2)
D = hankel(A)
D(D==0) = inf
Y = min(D)
Edit:
Had a small bug, now it works.
% untested code:
Y = []; % would be better to pre-allocate
for ii = 1:size(X,1)
Y = [Y; X(ii,2)*ones(X(ii,1),1)];
end

Split matrix based on number in first column

I have a matrix which has the following form:
M =
[1 4 56 1;
1 3 5 1;
1 3 6 4;
2 3 5 0;
2 0 0 0;
3 1 2 3;
3 3 3 3]
I want to split this matrix based on the number given in the first column. So I want to split the matrix into this:
A =
[1 4 56 1;
1 3 5 1;
1 3 6 4]
B =
[2 3 5 0;
2 0 0 0]
C =
[3 1 2 3;
3 3 3 3]
I tried this by making the following loop, but this gave me the desired matrices with rows of zeros:
for i = 1:length(M)
if (M(i,1) == 1)
A(i,:) = M(i,:);
elseif (M(i,1) == 2)
B(i,:) = M(i,:);
elseif (M(i,1) == 3)
C(i,:) = M(i,:);
end
end
The result for matrix C is then for example:
C =
[0 0 0 0;
0 0 0 0;
0 0 0 0;
2 3 5 0;
2 0 0 0]
How should I solve this issue?
Additional information:
The actual data has a date in the first column in the form yyyymmdd. The data set spans several years and I want to split this dataset in matrices for each year and after that for each month.
You can use arrayfun to solve this task:
M = [
1 4 56 1;
1 3 5 1;
1 3 6 4;
2 3 5 0;
2 0 0 0;
3 1 2 3;
3 3 3 3]
A = arrayfun(#(x) M(M(:,1) == x, :), unique(M(:,1)), 'uniformoutput', false)
The result A is a cell array and its contents can be accessed as follows:
>> a{1}
ans =
1 4 56 1
1 3 5 1
1 3 6 4
>> a{2}
ans =
2 3 5 0
2 0 0 0
>> a{3}
ans =
3 1 2 3
3 3 3 3
To split the data based on an yyyymmdd format in the first column, you can use the following:
yearly = arrayfun(#(x) M(floor(M(:,1)/10000) == x, :), unique(floor(M(:,1)/10000)), 'uniformoutput', false)
monthly = arrayfun(#(x) M(floor(M(:,1)/100) == x, :), unique(floor(M(:,1)/100)), 'uniformoutput', false)
If you don't know how many outputs you'll have, it is most convenient to put the data into a cell array rather than into separate arrays. The command to do this is MAT2CELL. Note that this assumes your data is sorted. If it isn't use sortrows before running the code.
%# count the repetitions
counts = hist(M(:,1),unique(M(:,1));
%# split the array
yearly = mat2cell(M,counts,size(M,2))
%# if you'd like to split each cell further, but still keep
%# the data also grouped by year, you can do the following
%# assuming the month information is in column 2
yearByMonth = cellfun(#(x)...
mat2cell(x,hist(x(:,2),unique(x(:,2)),size(x,2)),...
yearly,'uniformOutput',false);
You'd then access the data for year 3, month 4 as yearByMonth{3}{4}
EDIT
If the first column of your data is yyyymmdd, I suggest splitting it into three columns yyyy,mm,dd, like below, to facilitate grouping afterward:
ymd = 20120918;
yymmdd = floor(ymd./[10000 100 1])
yymmdd(2:3) = yymmdd(2:3)-100*yymmdd(1:2)