Generating a random number based off normal distribution in matlab - matlab

I am trying to generate a random number based off of normal distribution traits that I have (mean and standard deviation). I do NOT have the Statistics and Machine Learning toolbox.
I know one way to do it would be to randomly generate a random number r from 0 to 1 and find the value that gives a probability of that random number. I can do this by entering the standard normal function
f= #(y) (1/(1*2.50663))*exp(-((y).^2)/(2*1^2))
and solving for
r=integral(f,-Inf,z)
and then extrapolating from that z-value to the final answer X with the equation
z=(X-mew)/sigma
But as far as I know, there is no matlab command that allows you to solve for x where x is the limit of an integral. Is there a way to do this, or is there a better way to randomly generate this number?

You can use the built-in randn function which yields random numbers pulled from a standard normal distribution with a zero mean and a standard deviation of 1. To alter this distribution, you can multiply the output of randn by your desired standard deviation and then add your desired mean.
% Define the distribution that you'd like to get
mu = 2.5;
sigma = 2.0;
% You can any size matrix of values
sz = [10000 1];
value = (randn(sz) * sigma) + mu;
% mean(value)
% 2.4696
%
% std(value)
% 1.9939
If you just want a single number from the distribution, you can use the no-input version of randn to yield a scalar
value = (randn * sigma) + mu;

Just for the fun of it, you can generate a Gaussian random variable using a uniform random generator:
The logarithm of a uniform random variable on (0,1) has an exponential distribution
The square root of that has a Rayleigh distribution
Multiply by the cosine (or sine) of a uniform random variable on (0,2*pi) and the result is Gaussian. You need to multiply by sqrt(2) to normalize.
The obtained Gaussian variable is normalized (zero mean, unit standard deviation). If you need specific mean and standard deviation, multiply by the latter and then add the former.
Example (normalized Gaussian):
m = 1; n = 1e5; % desired output size
x = sqrt(-2*log(rand(m,n))).*cos(2*pi*rand(m,n));
Check:
>> mean(x)
ans =
-0.001194631660594
>> std(x)
ans =
0.999770464360453
>> histogram(x,41)

Related

How to generate a vector of random numbers knowing the standard deviation and the mean (matlab)?

I would like to generate a vector of 20 random numbers knowing the standard deviation, the mean and contaning two 0 values. Is it possible?
These are the desired values of mean and standard deviation:
Mean: 3.3
Standard deviation: 25%
This seems to work fine: https://fr.mathworks.com/help/matlab/math/random-numbers-with-specific-mean-and-variance.html however, I need to have in my vector two 0 values.
You can do this in a few steps, as detailed in the comments. The "at least" two zeros condition is easier than "exactly" two zeros would be - in the latter case you would have to write a quick function to return randn values except zero and then make sure the distribution shifting doesn't create new zeros.
% Create an array of length N+z (=20 here), which is N=18 randn values and z zeros
% Could make this more complicated to limit/expand on specific values
N = 18;
z = 2;
v = [randn(N,1); zeros(z,1)];
% Define a target mean (mu) and standard dev (sd)
mu = 3.3;
sd = 25;
% We have to iterate several times (100 is arbitrary) to get closer to both
% the s.d. and mean criteria. More passes for arbitrary accuracy
for ii = 1:100
% Scale the vector to satisfy the standard dev
v = sd*v/std(v);
% Shift the vector to satisfy the mean, but only the non-zero randn values
v(1:N) = v(1:N) - mean(v(1:N)) + ((N+z)/N)*mu;
end
% Output check
fprintf( 'Standard dev: %.4f\nMean: %.4f\n', std(v), mean(v) );
% >> Standard dev: 25.0000
% >> Mean: 3.3000
Note that by forcing specific values this isn't necessarily a perfectly normally distributed set of numbers any more, but it does satisfy your mean and standard deviation conditions. This is an issue with your problem statement - any solution will have this footnote.

How to use the randn function in Matlab to create an array of values (range 0-10) of size 1,000 that follows a Gaussian distribution? [duplicate]

Matlab has the function randn to draw from a normal distribution e.g.
x = 0.5 + 0.1*randn()
draws a pseudorandom number from a normal distribution of mean 0.5 and standard deviation 0.1.
Given this, is the following Matlab code equivalent to sampling from a normal distribution truncated at 0 at 1?
while x <=0 || x > 1
x = 0.5 + 0.1*randn();
end
Using MATLAB's Probability Distribution Objects makes sampling from truncated distributions very easy.
You can use the makedist() and truncate() functions to define the object and then modify (truncate it) to prepare the object for the random() function which allows generating random variates from it.
% MATLAB R2017a
pd = makedist('Normal',0.5,0.1) % Normal(mu,sigma)
pdt = truncate(pd,0,1) % truncated to interval (0,1)
sample = random(pdt,numRows,numCols) % Sample from distribution `pdt`
Once the object is created (here it is pdt, the truncated version of pd), you can use it in a variety of function calls.
To generate samples, random(pdt,m,n) produces a m x n array of samples from pdt.
Further, if you want to avoid use of toolboxes, this answer from #Luis Mendo is correct (proof below).
figure, hold on
h = histogram(cr,'Normalization','pdf','DisplayName','#Luis Mendo samples');
X = 0:.01:1;
p = plot(X,pdf(pdt,X),'b-','DisplayName','Theoretical (w/ truncation)');
You need the following steps
1. Draw a random value from uniform distribution, u.
2. Assuming the normal distribution is truncated at a and b. get
u_bar = F(a)*u +F(b) *(1-u)
3. Use the inverse of F
epsilon= F^{-1}(u_bar)
epsilon is a random value for the truncated normal distribution.
Why don't you vectorize? It will probably be faster:
N = 1e5; % desired number of samples
m = .5; % desired mean of underlying Gaussian
s = .1; % desired std of underlying Gaussian
lower = 0; % lower value for truncation
upper = 1; % upper value for truncation
remaining = 1:N;
while remaining
result(remaining) = m + s*randn(1,numel(remaining)); % (pre)allocates the first time
remaining = find(result<=lower | result>upper);
end

How to simulate the Hypergeometric distribution in Matlab

i want to simulate in Matlab program the Hypergeometric distribution with probability mass function and parameters as described here : https://en.wikipedia.org/wiki/Hypergeometric_distribution
how can i code that while producing random numbers from uniform distribution.
Most sensible would be to use the builtin hypergeometric generator.
If you have to do this for an assignment or some other arbitrary reason, the generic solution when an inverse CDF exists is to do inversion—use the uniform generator to create a p-value (a value between 0 and 1), and plug that into the inverse CDF. Since Matlab provides an inverse CDF function, this should be straightforward.
This is easily done with the randperm function, which generates a sample without replacement.
Let the distribution parameters be defined as follows:
N = 10; % population size
K = 3; % number of success states in the population
n = 5; % number of draws
Then the variable k obtained as
k = sum(randperm(N,n)<=K);
has a hypergeometric distribution with parameters N,K,n.
If you really need to use a uniform random number generator (rand function):
[~, x] = sort(rand(1,N));
x = x(1:n); % this gives the same result as randperm(N,n)
k = sum(x<=K);

Random samples from Lognormal distribution

I have a parameter X that is lognormally distributed with mean 15 and standard deviation 0.48. For monte carlo simulation in MATLAB, I want to generate 40,000 samples from this distribution. How could be done in MATLAB?
To generate an MxN matrix of lognornally distributed random numbers with parameter mu and sigma, use lognrnd (Statistics Toolbox):
result = lognrnd(mu,sigma,M,N);
If you don't have the Statistics Toolbox, you can equivalently use randn and then take the exponential. This exploits the fact that, by definition, the logarithm of a lognormal random variable is a normal random variable:
result = exp(mu+sigma*randn(M,N));
The parameters mu and sigma of the lognormal distribution are the mean and standard deviation of the associated normal distribution. To see how the mean and standard deviarion of the lognormal distribution are related to parameters mu, sigma, see lognrnd documentation.
To generate random samples, you need the inverted cdf. If you have done this, generating samples is nothing more than 'my_icdf(rand(n, m))'
First get the cdf (integrating the pdf) and then invert the function to get the inverted cdf.
You can convert between the mean and variance of the Lognormal distribution and its parameters (mu,sigma) which correspond to the associated Normal (Gaussian) distribution using the formulas.
The approach below uses the Probability Distribution Objects introduced in MATLAB 2013a. More specifically, it uses the makedist, random, and pdf functions.
% Notation
% if X~Lognormal(mu,sigma) the E[X] = m & Var(X) = v
m = 15; % Target mean for Lognormal distribution
v = 0.48; % Target variance Lognormal distribution
getLmuh=#(m,v) log(m/sqrt(1+(v/(m^2))));
getLvarh=#(m,v) log(1 + (v/(m^2)));
mu = getLmuh(m,v);
sigma = sqrt(getLvarh(m,v));
% Generate Random Samples
pd = makedist('Lognormal',mu,sigma);
X = random(pd,1000,1); % Generates a 1000 x 1 vector of samples
You can verify the correctness via the mean and var functions and the distribution object:
>> mean(pd)
ans =
15
>> var(pd)
ans =
0.4800
Generating samples via the inverse transform is also made easy using the icdf (inverse CDF) function.
% Alternate way to generate X~Lognormal(mu,sigma)
U = rand(1000,1); % U ~ Uniform(0,1)
X = icdf(pd,U); % Inverse Transform
The graphic generated by following code (MATLAB 2018a).
Xrng = [0:.01:20]';
figure, hold on, box on
h(1) = histogram(X,'DisplayName','Random Sample (N = 1000)');
h(2) = plot(Xrng,pdf(pd,Xrng),'b-','DisplayName','Theoretical PDF');
legend('show','Location','northwest')
title('Lognormal')
xlabel('X')
ylabel('Probability Density Function')
% Options
h(1).Normalization = 'pdf';
h(1).FaceColor = 'k';
h(1).FaceAlpha = 0.35;
h(2).LineWidth = 2;

Lognormal random numbers in specific range in Matlab

I want to develop a lognormal distribution with range [0.42,1.19], whose few elements are given as D=[1.19,1.00,0.84,0.71,0.59,0.50,0.42]. The mean should be 0.84 and standard deviation as small as possible. Also given is that the 90% of cdf (=90% of the grains) lies between 0.59 and 1.19.
Once I know all the elements of this lognormal distribution which incorporate the given conditions I can find its pdf, which is what I require. Here are simple steps I tried:
D=[1.19,1.00,0.84,0.71,0.59,0.50,0.42];
s=0.30; % std dev of the lognormal distribution
m=0.84; % mean of the lognormal distribution
mu=log(m^2/sqrt(s^2+m^2)); % mean of the associated normal dist.
sigma=sqrt(log((s^2/m^2)+1)); % std dev of the associated normal dist.
[r,c]=size(D);
for i=1:c
D_normal(i)=mu+(sigma.*randn(1));
w(i)=(D_normal(i)-mu)/sigma; % the probability or the wt. percentage
end
sizes=exp(D_normal);
If you have the statistics toolbox and you want to draw random values from the lognormal distribution, you can simply call LOGNRND. If you want to know the density of the lognormal distribution with a given mean and sigma at a specific value, you use LOGNPDF.
Since you're calculating weights, you may be looking for the density. These would be, in your example:
weights = lognpdf([1.19,1.00,0.84,0.71,0.59,0.50,0.42],0.84,0.3)
weights =
0.095039 0.026385 0.005212 0.00079218 6.9197e-05 5.6697e-06 2.9244e-07
EDIT
If you want to know what percentage of grains falls into the range of 0.59 to 1.19, you use LOGNCDF:
100*diff(logncdf([0.59,1.19],0.84,0.3))
ans =
1.3202
That's not a lot. If you plot the distribution, you'll notice that the lognormal distribution with your values peaks a bit above 2
x = 0:0.01:10;
figure
plot(x,lognpdf(x,0.84,0.3))
It seems that you are looking to generate truncated lognormal random numbers. If my assumption is correct you can either use the rejection sampling or inverse transform sampling to generate the necessary samples. Caveat: Rejection sampling is very inefficient if your bounds are very far from the mean.
Rejection Sampling
If x ~ LogNormal(mu,sigma) I(lb < x < ub )
Then generate, x ~ LogNormal(mu,sigma) and accept the draw if lb < x < ub.
Inverse Transform Sampling
If x ~ LogNormal(mu,sigma) I(lb < x < ub ) then
CDF(x) = phi((log(x) - mu)/sigma) /( phi((log(ub) - mu)/sigma) - phi((log(lb) - mu)/sigma))
Generate, u ~ Uniform(0,1).
Set, CDF(x) = u and invert for x.
In other words,
x = exp( mu + sigma * phi_inverse( u * ( phi((log(ub) - mu)/sigma) - phi((log(lb) - mu)/sigma)) ) )