I have this matrix in matlab.
It has 31 rows and 546 columns.
I need to change the first group of zeros (until before the 2s) in each column into 3s, but the second group of 0s (after the 1s) should stay as 0s. SO at the end I should a matrix like this
This should work:
a = 1;
while ~ismember(1,yourmatrix(a,:))
line = yourmatrix(a,:);
line(line==0)=3;
yourmatrix(a,:) = line;
a=a+1;
end
The ismember function checks if elements are members of an array. Until a line contains the number 1, it replaces every 0 with a 3 per line.
You can read more about the ismember function here and about matrix indexing here.
Related
I have this kind of data
A = [1 0.5
1 0.1
1 0.3
2 1
2 0.5
2 0.1
2 1
5 2 ]
Looking at the first column, there can be repeating numbers, and those appearing only once. From rows starting with repeating numbers, I want to select the last occurrence, along with the rest of the row. For the above example, my output will become:
Output = [1 0.3
2 1 ]
How can I do this?
I am going to assume a couple of things:
The first column doesn't have to be sorted, but only contiguous groups are considered (i.e. if the first column contains entries like [2;2;2;3;2], the last row won't be considered a part of the "2 group"). If you want detached rows/groups to be considered, make sure to sort the rows of A before applying this algorithm).
The first column contains integers only.
Here's my suggestion:
out = A( [false; diff([logical(diff(A(:,1),1)); true])>0], :);
An explanation of the way it works:
We differentiate the first column to detect value transitions.
To the end of the previous result we concatenate a true, so that if the last row is part of a group, it gets considered.
Then we differentiate this again, so that we detect consecutive transitions (like the 2->5 in your example. We keep only "positive" transitions because only this indicates a new number in the first column.
Finally, we concatenate a false to the beginning, because the first row is never selected.
Using the unique function, you can easily solve your problem:
%%% Find the first indices of the unique numbers in column 1
[~, i_first, ~] = unique(A(:,1),'first');
%%% Then, find the last indices of the unique numbers in column 1
[~, i_last, ~] = unique(A(:,1),'last');
%%% Lastly, remove the entries with the same starting and finishing index
%%% from the last indices vector
i_last(i_last == i_first) = [];
%%% Output the requested values
Output = A(i_last, :);
This solution asumes the following: (courtesy of Dev-iL)
1. first column has to contain integers (otherwise this would require uniquetol)
2. non-contiguous groups are treated as contiguous (i.e. this performs sorting implicitly)
I have a matrix of 0s, 1s, 2s and 3s.If all the elements in the same row are the same then I want it to display the text 'flush'. For example, I have the matrix
[0,1,0,2,3;
0,0,0,0,0;
3,2,1,3,1;
2,2,2,2,2];
How would I program Matlab to recognise the 2nd and 4th row all have the same number?
A = [0,1,0,2,3; 0,0,0,0,0; 3,2,1,3,1; 2,2,2,2,2]
As it was said before if you only have positive numbers you can use the variance.
n_flush = var(A, [], 2) == 0
However, this will fail for negative numbers for example a row like [-2 -1 1 2].
What I would do is to compare the first column with the rest and flag the rows where all the elements are equal.
n_flush = all(bsxfun(#eq, A(:,1), A(:,2:end)),2)
Now, if you want to display flush every time the rows are equal you can do
for ind = find(n_flush)
fprintf('flush row %i\n', ind)
end
If you need to have the whole thing in a one-liner (which is what many Matlab-geeks try to do), then maybe this here will suit your needs
cellfun(#(x) char((x==0)*sprintf('flush')), num2cell(var(A')'), 'UniformOutput', false)
Edit: nice idea GameOfThrows
Yet another solution by explicitly subtracting the first column from each column via duplicating the first column to other columns of a matching-sized matrix.
identical_rows = ~any(A - kron(ones(1,size(A,2)),A(:,1)),2)
For my experiment I have 20 categories which contain 9 pictures each. I want to show these pictures in a pseudo-random sequence where the only constraint to randomness is that one image may not be followed directly by one of the same category.
So I need something similar to
r = randi([1 20],1,180);
just with an added constraint of two numbers not directly following each other. E.g.
14 8 15 15 7 16 6 4 1 8 is not legitimate, whereas
14 8 15 7 15 16 6 4 1 8 would be.
An alternative way I was thinking of was naming the categories A,B,C,...T, have them repeat 9 times and then shuffle the bunch. But there you run into the same problem I think?
I am an absolute Matlab beginner, so any guidance will be welcome.
The following uses modulo operations to make sure each value is different from the previous one:
m = 20; %// number of categories
n = 180; %// desired number of samples
x = [randi(m)-1 randi(m-1, [1 n-1])];
x = mod(cumsum(x), m) + 1;
How the code works
In the third line, the first entry of x is a random value between 0 and m-1. Each subsequent entry represents the change that, modulo m, will give the next value (this is done in the fourth line).
The key is to choose that change between 1 and m-1 (not between 0 and m-1), to assure consecutive values will be different. In other words, given a value, there are m-1 (not m) choices for the next value.
After the modulo operation, 1 is added to to transform the range of resulting values from 0,...,m-1 to 1,...,m.
Test
Take all (n-1) pairs of consecutive entries in the generated x vector and count occurrences of all (m^2) possible combinations of values:
count = accumarray([x(1:end-1); x(2:end)].', 1, [m m]);
imagesc(count)
axis square
colorbar
The following image has been obtained for m=20; n=1e6;. It is seen that all combinations are (more or less) equally likely, except for pairs with repeated values, which never occur.
You could look for the repetitions in an iterative manner and put new set of integers from the same group [1 20] only into those places where repetitions have occurred. We continue to do so until there are no repetitions left -
interval = [1 20]; %// interval from where the random integers are to be chosen
r = randi(interval,1,180); %// create the first batch of numbers
idx = diff(r)==0; %// logical array, where 1s denote repetitions for first batch
while nnz(idx)~=0
idx = diff(r)==0; %// logical array, where 1s denote repetitions for
%// subsequent batches
rN = randi(interval,1,nnz(idx)); %// new set of random integers to be placed
%// at the positions where repetitions have occured
r(find(idx)+1) = rN; %// place ramdom integers at their respective positions
end
I know that there is the command
A(:, find(sum(abs(A)) == 1)) = []
and that will find which columns summed up equals one and then removes them. This is not what I am looking for because if a row contains a 2 and a -1 it will remove that row. But I am trying to find a column that contains all zeros and a 1 and then the command will set that 1 to a zero.
Any help will be greatly appreciated.
EX:
A column of zeros
[1 2 3
0 3 2
0 1 2]
I want the first column to then be changed to a column of zeros
Try this:
sum(a)==1 & sum(a==1) & ~sum(a>1) & ~sum(a<0)
The first statement will be true when the column sums 1
The second will be true when there is at least a 1
The third will be true when there are no numbers greater than 1
The fourth will be true when there are no numbers less than 0
So, only 1s and 0s that add up to 1
The final result will be a vector of 1s and 0s (1==true, 0=false)
To change those single 1s in columns to 0 do:
a(:,sum(a)==1 & sum(a==1) & ~sum(a>1) & ~sum(a<0))=0
You need to merge those two conditions :
idx = find ((sum(a==1)==1));
idx2 = find ((sum(abs(a)) == 1));
The first one search for columns where their only one number "1".
And the second search for columns where the absolute sums is only 1, so no problem with 2,-1,-1,1 !
You're almost there. Just needed to assign 0 instead of deleteting using []
A(:, find(sum(abs(A)) == 1)) = 0
A simpler expression would be:
A(:, sum(A==1)==1 & sum(abs(A))==1) = 0;
Explanation:
A==1 - returns a boolean array with 1's where A==1, 0's everywhere else
sum(A==1) - sums over the first dimension of the boolean array: will ==1 where there is exactly one 1
sum(abs(A)) - when there is exactly one 1, this sum will ==1 only if the rest are zero
I'm just beginning to teach myself MATLAB, and I'm making a 501x6 array. The columns will contain probabilities for flipping 101 sided die, and as such, the columns contain 101,201,301 entries, not 501. Is there a way to 'stretch the column' so that I add 0s above and below the useful data? So far I've only thought of making a column like a=[zeros(200,1);die;zeros(200,1)] so that only the data shows up in rows 201-301, and similarly, b=[zeros(150,1);die2;zeros(150,1)], if I wanted 200 or 150 zeros to precede and follow the data, respectively in order for it to fit in the array.
Thanks for any suggestions.
You can do several thing:
Start with an all-zero matrix, and only modify the elements you need to be non-zero:
A = zeros(501,6);
A(someValue:someOtherValue, 5) = value;
% OR: assign the range to a vector:
A(someValue:someOtherValue, 5) = 1:20; % if someValue:someOtherValue is the same length as 1:20