Simulation of an arbitrary bag of marbles - matlab

So, I'm trying to simulate an arbitrary model of a bag of marbles (with replacement, if that makes a difference in how this works) and am running into issues displaying the results.
How I have it set up is the code asks for how many marbles are in the bag, the how many you would like to pick, and then how many different colors there are. (Defined as N, S, and k respectively).
I then go through a loop between 1 and k in a cell array to name the colors of the marbles and then create a second array that simulates the probabilities by asking how many of each color there is in the bag.
I then generate a random matrix that simulates 10 "games" (ie: rDist=randi(N,[10,S]);
Now that I have the marbles that I've picked, I create another 10xS cell array and want to fill that cell array with the colors of the marbles based on the number picked. That is, let's say I have 10 marbles and 7 are red and 3 are green. If the PRNG picks 1:7, I want the results cell array to say "red" and if it chooses 8:10, I want "green" in the corresponding positions. I can do this for finite numbers, but I want to extend this to K marble colors with any number of distributions of marble colors. Can you offer any help?
My "finite" solution for 2 marble types is below:
for lc=1:10*S
counter=0;
if (rDist(lc)>=1 && (rDist(lc)<=Probabilities(1)))
Results{lc}=Color{1};
end
counter=Probabilities(1);
if (rDist(lc)>counter && (rDist(lc)<=counter+Probabilities(2)))
Results{lc}=Color{2};
end
end

You can calculate the intervals that correspond to each color with cumsum. Then you need to find which interval each entry of rDist belongs to.
numPicks = 5;
numGames = 10;
names = {'red', 'white', 'blue'};
counts = [2 6 9];
N = sum(counts);
cumsumCounts = cumsum(counts);
rDist=randi(N, [numGames, numPicks]);
out = cell(size(rDist));
for i = length(counts):-1:1
out(rDist <= cumsumCounts(i)) = names(i);
end
You could also do this with quantiz from the communication systems toolbox or randSample from the statistics and machine learning toolbox. Finally, you could use the more confusing one-liner out = names(arrayfun( #(x)( find(cumsumCounts >= x, 1) ), rDist));

Related

Add random number to cell of matrices

I have a cell, A of size 1 by 625. i.e.
A = { A1, A2, ..., A625},
where each of the 625 elements of the cell A are 3D matrices of the same size, 42 by 42 by 3.
Problem 1
Since the entries of my matrices represent concentration of red blood cells which are of very small values and I cannot simply work with randn.
For each of the matrix, I try with this command, e.g.:
A1 = A1 .*(1 + randn(42,42,3)/100)
I try with dividing by 100 to minimize the possibility of very negative number (e.g. 1.234e-6) but I cannot eliminate this possibility.
Also, is there any quick way to add different randn(42,42,3) to different 625 matrices. A + randn(42,42,3) won't work because it is adding the same set of random numbers.
Problem 2
I want to make 30 copies of the cell A by adding random numbers to each of entries of the 625 matrices. That is, I want to obtain a cell, Patients which is a cell of 1 by 30 and each of the cell element is another cell element of 625 matrices.
Patients = A % Initialization. I have 30 patients.
for i = 1 : 30;
Patients = { Patients, Patients + `method from problem 1`};
end
I have tried to make my problems clear. I appreciate so much for your help.
Problem 1:
% optional: initialize the random number generator to the current time. T
rng('shuffle');
A = cell(625);
A = cellfun( #(x) rand(42,42,3), A ,'UniformOutput', false)
note the differences between 'rand', 'randn', 'rng'
from the MATLAB documentation:
rng('shuffle') seeds the random number generator based on the current time. Thus, rand, randi, and randn produce a different sequence of numbers after each time you call rng.
rand = Uniformly distributed random numbers -> no negative values [0, 1]
randn = Normally distributed random numbers
If you want to generate numbers in a special interval (from the MATLAB documentation):
In general, you can generate N random numbers in the interval [a,b] with the formula r = a + (b-a).*rand(N,1).
Problem 2:
I highly recommend you to build a struct with your 30 cells. This will facilitate the indexing/looping later significantly! You can name the struct fields after your patients, so you will have less trouble keeping track of them.
You can also build an cell-array. This is the easiest way for indexing.
In both cases: do preallocation of the memmory! (MATLAB stores variables coherent in your memory. If the variable grows, MATLAB might have to relocate the variable...)
% for preallocation + initialization in one step:
A = cell(625);
Patients.Peter = cellfun( #(x) rand(42,42,3), A ,'UniformOutput', false);
Patients.Tom = cellfun( #(x) rand(42,42,3), A ,'UniformOutput', false);
% loop through the struct like this
FldNms = fieldnames( Patients );
for i = 0:length(Patients)
Patients.(FldNms{i}) = % do whatever you like
end
If you prefer an array:
% preallocation:
arry = cell(30);
for i = 1:length(array)
arry(i) = { cellfun( #(x) rand(42,42,3), A ,'UniformOutput', false) };
end
This is a lot of wild indexing and you will get a lot of trouble by using (),{} and [] for indexing.
Think again if you need a cell array in the first place. An array of 625 matrices might suit you as well. Data structure can significantly affect the performance, the readability and your coding time!
For your first question, what about
cellfun(#(x)(x + randn(42,42,3)/100), A, 'uni', 0)
your second problem should (A) be a second question and (B) be trivial to solve once your first is done. Just drop the Patients + and your code should work correctly.

generate different random variable

I want to generate 5 different random variables, & I want also to satisfy other condition which is N(rand1,rand2) =0 where N is 10-by-10 matrix that contains 0s & 1s.
This is the code that I wrote , it generate different random number , but I want to satisfy the other condition.
nb_sources=5;
nb_Des=5;
rand_nb= randperm(n,n);
source = [rand_nb(1:nb_sources)] ;
distination= [rand_nb(nb_sources+1:nb_sources+nb_Des)] ;
Since you're interested only in N(r1,r2)=0, you need to enumerate all these elements of N (lets say from from 1 to 30), generate 5 random numbers as rand(30,5,1) and pick up the indices. E.g. something like this
Nelem = 5;
[I,J] = find(N==0);
ind = randperm(size(I,1));
Res=[I(ind(1:Nelem)),J(ind(1:Nelem))];

Average part of a multidimensional array based on another array (Matlab)

B = randn(1,25,10);
Z = [1;1;1;2;2;3;4;4;4;3];
Ok, so, I want to find the locations where Z=1(or any numbers that are equal to each other), then average across each of the 25 points at these specific locations. In the example you would end with a 1*25*4 array.
Is there an easy way to do this?
I'm not the most versed in Matlab.
First things first: break down the problem.
Define the groups (i.e. the set of unique Z values)
Find elements which belong to these groups
Take the average.
Once you have done that, you can begin to see it's a pretty standard for loop and "Select columns which meet criteria".
Something along the lines of:
B = randn(1,25,10);
Z = [1;1;1;2;2;3;4;4;4;3];
groups = unique(Z); %//find the set of groups
C = nan(1,25,length(groups)); %//predefine the output space for efficiency
for gi = 1:length(groups) %//for each group
idx = Z == groups(gi); %//find it's members
C(:,:,gi) = mean(B(:,:,idx), 3); %//select and mean across the third dimension
end
If B = randn(10,25); then it's very easy because Matlab function usually works down the rows.
Using logical indexing:
ind = Z == 1;
mean(B(ind,:));
If you're dealing with multiple dimensions use permute (and reshape if you actually have 3 dimensions or more) to get yourself to a point where you're averaging down the rows as above:
B = randn(1,25,10);
BB = permute(B, [3,2,1])
continue as above

generation of random number in MATLAB

I would like to generate three sets of random variables and I dont want them to be the same
for example if I want to generate the following sets ranged from 1 to 10
Set1= [ 1 4 ]
set2= [ 3 5 ]
Set3= [ 7 9]
You can create an array of unique random numbers using the function "randperm" and then divide the array into sets.
x = randperm(10,6);
Set1 = x(1:2);
Set2 = x(3:4);
Set3 = x(5:6);
After choosing two elements for each set, it's essential to randomize the remaining elements to choose from for the next iteration . The code below is trying to achieve it -
set123 = zeros(3,2); %// Pre-allocate for the output
array1 = 1:10; %// Array of numbers to choose from for the first iteration
for k = 1:3
%// Create many possible combinations of such two numbers from the sets.
%// The sets would have 10 elements to choose from at the start and
%// then 8 and then 6.
combs = nchoosek(array1,2);
%// At each stage all the possible combinations of the pairs must be
%// juggled and one of them must be selected randomly and then indexed
%// to get the set for this iteration
choosen_rowind = randperm(size(combs,1),1);
set123(k,:) = combs(choosen_rowind,:);
%// Setup the array of numbers left to choose from the next iteration
array1 = setdiff(array1,set123);
end
%// set123 is the desired output in a single array
If I understand correctly, you want to take r-times-c random variables (in your case r=3, c=2) from the set {m,m+1,...,n} (in your case n=1 and m=10), without repetition. I assume you want a (jointly) uniform distribution.
For that you use randsample:
result = reshape(randsample(m:n, r*c), r, c);

How do I plot this? MATLAB

I have a matrix, X, in which I want to plot it using the kmeans function. What I would like: If row has a value of 1 in column 4 I would like it to be square shaped If the row has a value of 2 in column 4 I would like it + shaped BUT If the row has a value of 0 in column 5 it must be blue and if the row has a vale of 1 in column 5 it must be yellow
(You don't need to use these exact colors and shapes, I just want to distinguish these.) I tried this and it did not work:
plot(X(idx==2,1),X(idx==2,2),X(:,4)==1,'k.');
Thanks!!
Based on the example on the kmeans documentation page I propose this "nested" logic:
X = [randn(100,2)+ones(100,2);...
randn(100,2)-ones(100,2)];
opts = statset('Display','final');
% This gives a random distribution of 0s and 1s in column 5:
X(:,5) = round(rand(size(X,1),1));
[idx,ctrs] = kmeans(X,2,...
'Distance','city',...
'Replicates',5,...
'Options',opts);
hold on
plot(X(idx==1,1),X(idx==1,2),'rs','MarkerSize',12)
plot(X(idx==2,1),X(idx==2,2),'r+','MarkerSize',12)
% after plotting the results of kmeans,
% plot new symbols with a different logic on top:
plot(X(X(idx==1,5)==0,1),X(X(idx==1,5)==0,2),'bs','MarkerSize',12)
plot(X(X(idx==1,5)==1,1),X(X(idx==1,5)==1,2),'gs','MarkerSize',12)
plot(X(X(idx==2,5)==0,1),X(X(idx==2,5)==0,2),'b+','MarkerSize',12)
plot(X(X(idx==2,5)==1,1),X(X(idx==2,5)==1,2),'g+','MarkerSize',12)
The above code is a minimal working example, given that the statistics toolbox is available.
The key feature is the nested logic for the plotting. For example:
X(X(idx==1,5)==0,1)
The inner X(idx==1,5) selects those values of X(:,5) for which idx==1. From those, only values which are 0 are considered: X(X(...)==0,1). Based on the logic in the question, this should be a blue square: bs.
You have four cases, hence there are four additional plot lines.