I'm running an experiment with lots of conditions, and particular numbers of groups in each condition.
A. 3 groups
B. 3 groups
C. 2 groups
D. 3 groups
E. 3 groups
I've worked out that there are 3×3×2×3×3 = 162 possible combinations of groups.
I want to create a MATLAB matrix with 162 rows and 5 columns. That is, one row for each combination and one column to indicate the value for each group.
So, for instance, the first row would be [1 1 1 1 1], indicating that this combination is group 1 for all conditions. The second row would be [1 1 1 1 2], indicating that it's group 1 for all conditions except for the last which is group 2. The 162nd and final row would be [3 3 2 3 3].
M = 1 1 1 1 1
1 1 1 1 2
.........
3 3 2 3 3
What's the most efficient way to achieve this? I realise I could use a loop, but feel sure there's a better way. I thought maybe the perms function would work but I can't see how.
You can use combvec (see last line, the rest is only generating test data):
% A. 3 groups
% B. 3 groups
% C. 2 groups
% D. 3 groups
% E. 3 groups
ngroups = zeros(5, 1);
ngroups(1) = 3;
ngroups(2) = 3;
ngroups(3) = 2;
ngroups(4) = 3;
ngroups(5) = 3;
v = {};
for i = 1:length(ngroups)
v{i} = 1:ngroups(i) % generate a vector of valid group indices
end
% get all possible combinations
x = combvec( v{:} )
As this will return a 5 x 162 double you need to transpose the resulting matrix x:
x.'
Related
idx=randperm(5)
idx=[1,3,4,2,5]
I know this works like that but I'm curious about is there anyway to get something like this.
idx=[1,3,4,2,5,5,3,2,4,1]
adding one set of array after one array
Is there any way to make that?
One vectorized way would be to create a random array of size (m,n), sort it along each row and get the argsort indices. Each row of those indices would represent a group of randperm values. Here, m would be the number of groups needed and n being the number of elements in each group.
Thus, the implementation would look something like this -
[~,idx] = sort(rand(2,5),2);
out = reshape(idx.',1,[])
Sample run -
>> [~,idx] = sort(rand(2,5),2);
>> idx
idx =
5 1 3 2 4
4 3 2 5 1
>> out = reshape(idx.',1,[])
out =
5 1 3 2 4 4 3 2 5 1
You can use the modulo operation:
n = 5 %maximum value
r = 2 %each element are repeated r times.
res = mod(randperm(r*n),n)+1
I have a 250000x2-matrix in matlab, where in the first row I have a degree (int, 0-360°), and in the second a float-value corresponding to this value. My target is to count each occurence of a degree-value-pair (e.g. a row), and write the result in a nx3-matrix. n corresponds here with the number unique rows.
Thus my first step was to get all unique values (using unique(M, 'rows')) which works. But now I want to count all unique values. This was done by the following approach:
uniqu_val = unique(values, 'rows');
instance = histcounts(values(:), uniqu_val);
Here I have to enter a vector as second element, and not a matrix (uniqu_val is a nx2-dim-matrix). But I want to get the number of occurence for each unique row, therefore I can not use only one column of the matrix uniqu_val. In short: I want to use histcounts not only for a 1D-matrix as edge-value, but for a 2D-matrix. How can I solve this problem?
You can use the third output from unique and then use histcounts like so -
%// Find the unique rows and keep the order with 'stable' option
[uniq_val,~,row_labels] = unique(values, 'rows','stable')
%// Find the counts/instances
instances = histcounts(row_labels, max(row_labels))
%// OR with HISTC: instances = histc(row_labels, 1:max(row_labels))
%// Output the unique rows alongwith the counts
out = [uniq_val instances(:)]
Sample run -
>> values
values =
2 1
3 1
2 3
3 3
1 2
3 3
1 3
3 1
3 2
1 2
>> out
out =
2 1 1
3 1 2
2 3 1
3 3 2
1 2 2
1 3 1
3 2 1
I want to raise a matrix to a next matrix and subtrat one before taking the product.
e.g.
A = [2 3 5
2 3 0]
B = [2 2 1
1 2 0]
so prod(A.^B-1) would be:
first row (2^2-1)*(3^2-1)*(5^1-1)=96
second row (2^1-1)*(3^2-1)=8
and we would have prod(A.^B-1) = 96, 81. the trick also to skip past the zero, i keep getting zero or NaN, i think the zero is being calculated as well.
Is there a way to code this,
this is the code I have in mind
if A~=0 && B~=0
prod(A.^B-1)
end
You could do it like this using logical indexing to replace instances where A.^B-1 is 0:
A = [2 3 5;2 3 0];
B = [2 2 1;1 2 0];
C = A.^B-1;
C(C==0) = 1; % Replace zeros with ones
D = prod(C,2) % Product across the columns
which returns
D =
96
8
provided that you remove the zeros, I don't think that you should get NaN unless your original matrices contain it. However, You can replace it in the same manner as well (C(isnan(C)) = 1;).
I have a vector like this:
A = [1 2 1 1 1 4 5 0 0 1 2 0 2 3 2 2 2 0 0 0 0 33]
I would like to count how many GROUPS of non zero elements it contains and save them.
so I want to isolate:
[1 2 1 1 1 4 5]
[1 2]
[2 3 2 2 2]
[33]
and then count the groups (they should be 4) :)
Can you help me please?
Thanks
To count your groups, a fast vectorized method using logical indexing is:
count = sum(diff([A 0]==0)==1)
This assumes that A is a row vector as in your example. This works with no zeros, all zeros, the empty vector, and several other test cases I tried.
To obtain your groups of values themselves, you can use a variation to my answer to a similar question:
a0 = (A~=0);
d = diff(a0);
start = find([a0(1) d]==1) % Start index of each group
len = find([d -a0(end)]==-1)-start+1 % Length, number of indexes in each group
In your case it might make sense to replace len with
finish = find([d -a0(end)]==-1) % Last index of each group
The length of start, len, and finish should be the same as the value of count so you could just use this if you need to do the breaking up. You can then use start and len (or finish) to store your groups in a cell array or struct or some other ragged array. For example:
count = length(start);
B = cell(count,1);
for i = 1:count
B{i} = A(start(i):finish(i));
end
Is it possible to do something like regular expressions with MATLAB to filter things out? Basically I'm looking for something that will let me take a vector like:
[1 2 1 1 1 2 1 3 3 3 3 1 1 4 4 4 1 1]
and will return:
[3 3 3 3 4 4 4]
These are the uninterrupted sequences (where there's no interspersion).
Is this possible?
Using regular expressions
Use MATLAB's built-in regexp function for regular expression matching. However, you have to convert the input array to a string first, and only then feed it to regexp:
C = regexp(sprintf('%d ', x), '(.+ )(\1)+', 'match')
Note that I separated the values with spaces so that regexp can match multiple digit numbers as well. Then convert the result back to a numerical array:
res = str2num([C{:}])
The dot (.) in the pattern string represents any character. To find sequences of certain digits only, specify them in brackets ([]). For instance, the pattern to find only sequences of 3 and 4 would be:
([34]+ )(\1)+
A simpler approach
You can filter out successively repeating values by checking the similarity between adjacent elements using diff:
res = x((diff([NaN; x(:)])' == 0) | (diff([x(:); NaN])' == 0))
Optionally, you can keep only certain values from the result, for example:
res(res == 3 | res == 4)
You can do it like this:
v=[1 2 1 1 1 2 1 3 3 3 3 1 1 4 4 4 1 1];
vals=unique(v); % find all unique values in the vector
mask=[]; % mask of values to retain
for i=1:length(vals)
indices=find(v==vals(i)); % find indices of each unique value
% if the maximum difference between indices containing
% a given value is 1, it is contiguous
% --> add this value to the mask
if max(indices(2:end)-indices(1:end-1))==1
mask=[mask vals(i)];
end
end
% filter out what's necessary
vproc=v(ismember(v,mask))
Result:
vproc =
3 3 3 3 4 4 4
This can be another approach, although a little bit too elaborated.
If you see the plot of your array, you want to retain its level sets (i.e. a == const) which are topologically connected (i.e. made by one piece).
Coherently, such level sets are exactly the ones corresponding to a==3 and a==4.
Here is a possible implementation
a = [1 2 1 1 1 2 1 3 3 3 3 1 1 4 4 4 1 1]
r = []; % result
b = a; % b will contain the union of the level sets not parsed yet
while ~isempty(b)
m = a == b(1); % m is the current level set
connected = sum(diff([0 m 0]).^2) == 2; % a condition for being a connected set:
% the derivative must have 1 positive and 1
% negative jump
if connected == true % if the level set is connected we add it to the result
r = [r a(m)];
end
b = b(b~=b(1));
end
If you try something like
a = [1 2 1 1 1 2 1 3 3 3 3 1 1 4 4 4 1 1] %initial vector
b = a>=3 %apply filter condition
a = a(b) %keep values that satisfy filter
a will output
a = [3 3 3 3 4 4 4]