Pseudo Random Integer with frequency constraints
2 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
Hello,
I am relatively new to MATLAB and I need to design a 200x1 matrix, which is filled with random integers that can be either 1/2/3/4, so 4 possible numbers. However, in the matrix I want '1' to occur 70% (thus a total frequency of 140 for number 1), '2', '3' and '4', to occur 10% (thus a frequency of 20 for 2,3 and 4).
Moreover, I want the matrix to be filled so that the values of 2,3, and 4 never display a consecutive repeat, but that 1 may feature consecutive repeats (as it takes 70%)
I had a solution (without the consecutive repeat constraint), using the repelem function. However, on the target PC, an older version of matlab is installed (2013) and does not include this function. Could someone provide me with a solution?
Thanks
1 commentaire
Réponse acceptée
alice
le 22 Juin 2017
One way to do it (it is not really concise and beautiful but works pretty fast): I put all the '1' in the matrix at random positions and then I fill the rest, beginning with the remaining spaces of length 1, then 2 and so on. If I reach a point where I can't respect the condition of no consecutive repeat, I try again from the beginning until I find a suitable solution, but it happens scarcely.
n = 200; % total number of elements
n1 = 0.7*n; % number of 1 that should appear
n2 = 0.1*n; % number of 2, 3 and 4 that should appear
foundSolution = 0; % boolean
cptAttempt = 0; % count the attempts to make a suitable matrix
while ~foundSolution && cptAttempt<100
M=zeros(n,1); % initialize the matrix, filled with zeros
M(randperm(n,n1))=1; % put the wanted number of '1' in random positions
cpt = n2*[1,1,1]; % count the number of '2', '3' and '4' we still have to put in the matrix
% Looking for the areas where there are '0' to fill them. The idea is
% to first fill the areas that have a length of 1, then 2, 3 and so on.
diffM = diff([1;M;1]);
iBeginSeq = find(diffM==-1);% index of the beginning of the areas to fill
iEndSeq = find(diffM==1)-1; % index of the end of the areas to fill
impossible = 0; % boolean
for nbToFill=unique(iEndSeq-iBeginSeq)' % nbToFill is the length of the areas
ind = iBeginSeq(iEndSeq-iBeginSeq==nbToFill);
nbSeq = length(ind); % number of areas that have a length of 'nbToFill'
prevValues = ones(nbSeq,1); % values in the case before, that should be different
for rnk = 0:nbToFill % fill all the first cases, then all the 2nd cases, ...
possibleValues = [2*ones(min(nbSeq,cpt(1)),1) ; ...
3*ones(min(nbSeq,cpt(2)),1) ; 4*ones(min(nbSeq,cpt(3)),1)]; % there can be at most cpt(1) '2', and if we choose always '2', there will be nbSeq '2'
newValues = possibleValues(randperm(length(possibleValues),nbSeq)); % select random possible value
pb = find(newValues==prevValues); % problem when the value of the case before is the same value
setValues = newValues(setdiff(1:nbSeq, pb)); % values with no problem
cpt(1) = cpt(1)-sum(setValues==2); % update the number of '2' we still have to put in the matrix
cpt(2) = cpt(2)-sum(setValues==3); % update the number of '3' we still have to put in the matrix
cpt(3) = cpt(3)-sum(setValues==4); % update the number of '4' we still have to put in the matrix
possibleValues = [2*ones(min(length(pb),cpt(1)),1) ; ...
3*ones(min(length(pb),cpt(2)),1) ; 4*ones(min(length(pb),cpt(3)),1)];
for iPb = pb'
if sum(cpt(setdiff(1:3,prevValues(iPb)-1)))==0
impossible = 1;
break;
else
possibleValuesHere = possibleValues;
possibleValuesHere(possibleValues==prevValues(iPb))=[]; % the value before is not possible
newValues(iPb) = possibleValuesHere(randi(length(possibleValuesHere))); % select random possible value
possibleValues(find(possibleValues==newValues(iPb),1))=[];
cpt(newValues(iPb)-1) = cpt(newValues(iPb)-1)-1; % update the number of '2', '3', '4' we still have to put in the matrix
end
end
if impossible
break
end
M(ind+rnk) = newValues; % we put the chosen values in the matrix
prevValues = newValues; % update the values of the case before
end
if impossible
break
end
end
foundSolution = ~impossible;
cptAttempt = cptAttempt+1; % count the number of attempts
end
disp(['Number of attempts: ',num2str(cptAttempt)])
0 commentaires
Plus de réponses (0)
Voir également
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!