Random Numbers with Gaussian and Uniform Distributions in matlab - matlab

I want generate a number in Gaussian and Uniform distributions in matlab.
I know this function randi and rand() but all of them are in normal (Gaussian) distribution. How can a generate a random number in uniform distribution?

Use rand(dimensions) for a Uniform Distribution between 0 and 1.
Use randn(dimensions) * sqrt(sigma) + mu for a Gaussian Distribution with a mean of mu and standard deviation of sigma.

randn is the function to generate Gaussian distributed variables (randi and rand produce uniformly distributed ones).

You can generate any distribution from rand().
For example , lets say you want to generate 100000 samples for rayleigh dist.The way to do this is that you invert the cdf of that particular function.The basic idea is that since the cdf has to be between 0 and 1 , we can find the value of the random variable by inputting the value of cdf b/w 0 and 1. So for rayleigh, it would be
for i = 1:100000
data(i) = (2*sigma^2 *(-(log(1 - rand(1,1)))))^.5;
end
You can do something similar for gaussian distribution.

Congrulations, you already generating pseudo-random numbers with a gaussian distribution. Normal distribution is a synonym for it.
The only other possible interpretation I can get from your question is that you want something that has mean != 0 and/or variance != 1. To do that, simply perform mean + sqrt(var) * randn(X).

It is true you can generate just about anything from rand but that it isn't always convenient, especially for some complicated distributions.
MATLAB has introduced Probability Distribution Objects which make this a lot easier and allow you to seamlessly access mean, var, truncate, pdf, cdf, icdf (inverse transform), median, and other functions.
You can fit a distribution to data. In this case, we use makedist to define the probability distribution object. Then we can generate using random.
% Parameters
mu = 10;
sigma = 3;
a = 5; b = 15;
N = 5000;
% Older Approaches Still Work
rng(1775)
Z = randn(N,1); % Standard Normal Z~N(0,1)
X = mu + Z*sigma; % X ~ Normal(mu,sigma)
U = rand(N,1); % U ~ Uniform(0,1)
V = a + (b-a)*U; % V ~ Uniform(a,b)
% New Approaches Are Convenient
rng(1775)
pdX = makedist('Normal',mu,sigma);
X2 = random(pdX,N,1);
pdV = makedist('Uniform',a,b);
V2 = random(pdV,N,1);
A reproducible example:
Support = (0:0.01:20)';
figure
s(1) = subplot(2,2,1)
h(1) = histogram(X,'Normalization','pdf')
xlabel('Normal')
s(2) = subplot(2,2,2)
h(2) = histogram(V,'Normalization','pdf')
xlabel('Uniform')
s(3) = subplot(2,2,3), hold on, box on
h(3) = histogram(X2,'Normalization','pdf')
plot(Support,pdf(pdX,Support),'r-','LineWidth',1.2)
xlabel('Normal (new)')
s(4) = subplot(2,2,4), hold on, box on
h(4) = histogram(V2,'Normalization','pdf')
plot(Support,pdf(pdV,Support),'r-','LineWidth',1.2)
xlabel('Uniform (new)')
xlim(s,[0 20])
References:
Uniform Distribution
Normal (Gaussian) Distribution

Following raj's answer: by using the Box-Muller Transform you can generate independent standard Normal/Gaussian random numbers:
N = 1e6; z = sqrt(-2*log(rand(N, 1))) .* cos(2*pi * rand(N, 1)); figure; hist(z, 100)
N = 1e6; z = sqrt(-2*log(rand(N, 1))) .* sin(2*pi * rand(N, 1)); figure; hist(z, 100)
If you want to apply the Inverse Transformation Method, you can use the Inverse Complementary Error Function (erfcinv):
N = 1e6; z = -sqrt(2) * erfcinv(2 * rand(1e6, 1)); figure; hist(z, 100)
But I hope randn works better.

Related

Vectors must be the same length error in Curve Fitting in Matlab

I'm having problems in curve fitting my randomized data for the function
Here is my code
N = 100;
mu = 5; stdev = 2;
x = mu+stdev*randn(N,1);
bin=mu-6*stdev:0.5:mu+6*stdev;
f=hist(x,bin);
plot(bin,f,'bo'); hold on;
x_ = x(1):0.1:x(end);
y_ = (1./sqrt(8.*pi)).*exp(-((x_-mu).^2)./8);
plot(x_,y_,'b-'); hold on;
It seems like I'm having vector size problems since it is giving me the error
Error using plot
Vectors must be the same length.
Note that I simplified y_ since mu and the standard deviation is known.
Plot:
Well first of all some adjustments to your question:
You are not trying to do curve fitting. What you are trying to do (in my opinion) is to overlay a probability density function on an histogram obtained by taking random points from the same distribution (A normal distribution with parameters (mu,sigma)). These two curve should indeed overlay, as they represent the same thing, only one is analytical and the other one is obtained numerically.
As seen in the hist documentation, hist is not recommended and you should use histogram instead
First step: Generating your random data
Knowing the distribution is the Normal distribution, we can use MATLAB's random function to do that :
N = 150;
rng('default') % For reproducibility
mu = 5;
sigma = 2;
r = random('Normal',mu,sigma,N,1);
Second step: Plot the histogram
Because we don't just want a count of the elements in each bin, but a feel of the probability density function, we can use the 'Normalization' 'pdf' arguments
Nbins = 25;
f=histogram(r,Nbins,'Normalization','pdf');
hold on
Here I'd rather specify a number of bins than specifying the bins themselves, because you never know in advance how far from the mean your data is going to be.
Last step: overlay the probability density function over the histogram
The histogram being already consistent with a probability density function, it is sufficient to just overlay the density function:
x_ = linspace(min(r),max(r),100);
y_ = (1./sqrt(2*sigma^2*pi)).*exp(-((x_-mu).^2)./(2*sigma^2));
plot(x_,y_,'b-');
With N = 150
With N = 1500
With N = 150.000 and Nbins = 50
If for some obscure reason you want to use old hist() function
The old hist() function can't handle normalization, so you'll have to do it by hand, by normalizing your density function to fit your histogram:
N = 1500;
% rng('default') % For reproducibility
mu = 5;
sigma = 2;
r = random('Normal',mu,sigma,1,N);
Nbins = 50;
[~,centers]=hist(r,Nbins);
hist(r,Nbins); hold on
% Width of bins
Widths = diff(centers);
x_ = linspace(min(r),max(r),100);
y_ = N*mean(Widths)*(1./sqrt(2*sigma^2*pi)).*exp(-((x_-mu).^2)./(2*sigma^2));
plot(x_,y_,'r-');

how do you generate random numbers from a bimodal Gaussian Probability Density Function in MATLAB?

How do you generate numbers from a bimodal Gaussian PDF in MATLAB?
For a unimodal symmetric Gaussian PDF it is really easy:
x=randn(1000,1);
But now I want to draw 1000 numbers from a Gaussian PDF that has two peaks (or two means). How do I do this?
You can generate the bimodal Normal (Gaussian) distribution by combining two Normal distributions with different mean and standard deviation (as explained in this comment).
In MATLAB you can do this in several ways:
First, we need to specify the mean (mu) and standard deviation (sigma) that characterize our Normal distributions, usually noted as N(mu, sigma).
Normal distribution a: N(-1, 0.5)
mu_a = -1; % Mean (a).
sigma_a = 0.5; % Standard deviation (a).
Normal distribution b: N(2, 1)
mu_b = 2; % Mean (b).
sigma_b = 1; % Standard deviation (b).
Finally, let's define the size of our random vectors:
sz = [1e4, 1]; % Size vector.
Now let's generate the bimodal random values by concatenating two vectors of Normally distributed random numbers:
OPTION 1: using randn
x_1 = [sigma_a*randn(sz) + mu_a, sigma_b*randn(sz) + mu_b];
OPTION 2: using normrnd
x_2 = [normrnd(mu_a, sigma_a, sz), normrnd(mu_b, sigma_b, sz)];
OPTION 3: using random
x_3 = [random('Normal', mu_a, sigma_a, sz), random('Normal', mu_b, sigma_b, sz)];
Let's visualize the results:
subplot(1, 3, 1); histogram(x_1);
subplot(1, 3, 2); histogram(x_2);
subplot(1, 3, 3); histogram(x_3);
I propose you an alternative that uses gmdistribution:
% Means (X1 -> -0.5 and X2 -> 1.2)
m = [-0.5; 1.2];
% Standard Deviations (X1 -> 2.1 and X2 -> 1.3)
s = cat(3,2.1,1.3);
% Weights (X1 and X2 Equally Weighted 0.5)
w = ones(1,2) / 2;
% Create the Gaussian Mixture Model...
gmd = gmdistribution(m,s,w);
% Draw 1000 random numbers from it...
x = random(gmd,1000);
% Plot a histogram...
histogram(x,100);

How to draw random numbers from a gamma distribution without the Statistics Toolbox?

I am varying the signal strength for synthetic images. I need the signal to vary between 0 and 0.1, but I need to do this with a gamma distribution so that more of them fall around the .01/.02 range. The problem is that I am using the 2010 version of Matlab without the Statistics Toolbox that doesn't have the gamrnd function a part of its library.
Any and all help is greatly appreciated.
You can use the Inverse transform sampling method to convert a uniform distribution to any other distribution:
P = rand(1000);
X = gaminv(P(:),2,2); % with k = 2 and theta = 2
Here is a litle demonstration:
for k = [1 3 9]
for theta = [0.5 1 2]
X = gaminv(P(:),k,theta);
histogram(X,50)
hold on
end
end
Which gives:
Edit:
Without the statistics toolbox, you can use the Marsaglia's simple transformation-rejection method to generate random numbers from gamma distribution with rand and randn:
N = 10000; % no. of tries
% distribution parameters:
a = 0.5;
b = 0.1;
% Marsaglia's simple transformation-rejection:
d = a - 1/3;
x = randn(N,1);
U = rand(N,1);
v = (1+x./sqrt(9*d)).^3;
accept = log(U)<(0.5*x.^2+d-d*v+d*log(v));
Y = d*(v(accept)).*b;
Now Y is distributed like gamma(a,b). We can test the result using the gamrnd function:
n = size(Y,1);
X = gamrnd(a,b,n,1);
And the histograms of Y, and X are:
However, keep in mind that gamma distribution might not fit your needs because it has no specific upper bound (i.e. goes to infinity). So you may want to use another (bounded) distribution, like beta divided by 10.

Given a covarince matrix, generate a Gaussian random variable in Matlab

Given a M x M desired covariance, R, and a desired number of sample vectors, N calculate a N x M Gaussian random vector, X in vanilla MATLAB (i.e. can't use r = mvnrnd(MU,SIGMA,cases)).
Not really sure how to tackle this, usually you need a covariance AND mean to generate a Gaussian random variable. I think sqrtm and chol could be useful.
If you have access to the MATLAB statistics toolbox you can type edit mvnrnd in MATLAB to see their solution.
[T p] = chol(sigma);
if m1 == c
mu = mu';
end
mu = mu(ones(cases,1),:);
r = randn(cases,c) * T + mu;
It feels almost like cheating to point this out, but editing MATLAB's source is very useful to understand things in general. You can also search for mvnrnd.m on google if you don't have the toolbox.
Example:
% Gaussian mean and covariance
d = 2; % number of dimensions
mu = rand(1,d);
sigma = rand(d,d); sigma = sigma*sigma';
% generate 100 samples from above distribution
num = 100;
X = mvnrnd(mu, sigma, num);
% plot samples (only for 2D case)
scatter(X(:,1), X(:,2), 'filled'), hold on
ezcontour(#(x,y) mvnpdf([x y], mu, sigma), xlim(), ylim())
title('X~N(\mu,\sigma)')
xlabel('X_1'), ylabel('X_2')
The above code uses functions from the Statistics toolbox (mvnrnd and mvnpdf). If you don't have access to it, consider these replacements (using the same concepts mentioned by others):
mvnrnd = #(mu,S,num) bsxfun(#plus, randn(num,numel(mu))*cholcov(S), mu);
mvnpdf = #(x,mu,S) exp(-0.5*(x-mu)*(S\(x-mu)')) / sqrt((2*pi)^d*det(S));

Creating Gaussian random variable with MATLAB

By using randn function I want to create a Gaussian random variable X such that X ~ N(2,4) and plot this simulated PDF together with theoretic curve.
Matlab randn generates realisations from a normal distribution with zero mean and a standard deviation of 1.
Samples from any other normal distribution can simply be generated via:
numSamples = 1000;
mu = 2;
sigma = 4;
samples = mu + sigma.*randn(numSamples, 1);
You can verify this by plotting the histogram:
figure;hist(samples(:));
See the matlab help.
N = 1000;
x = [-20:20];
samples = 2 + 4*randn(N, 1);
ySamples = histc(samples,x) / N;
yTheoretical = pdf('norm', x, 2, 4);
plot(x, yTheoretical, x, ySamples)
randn(N, 1) creates an N-by-1 vector.
histc is histogram count by bins given in x - you can use hist to plot the result immediately, but here we want to divide it by N.
pdf contains many useful PDFs, normal is just one example.
remember this: X ~ N(mean, variance)
randn in matlab produces normal distributed random variables W with zero mean and unit variance.
To change the mean and variance to be the random variable X (with custom mean and variance), follow this equation:
X = mean + standard_deviation*W
Please be aware of that standard_deviation is square root of variance.
N = 1000;
x = [-20:20];
samples = 2 + sqrt(4)*randn(N, 1);
ySamples = histc(samples,x) / N;
yTheoretical = pdf('norm', x, 2, sqrt(4)); %put std_deviation not variance
plot(x, yTheoretical, x, ySamples)
A quick and easy way to achieve this using one line of code is to use :
mu = 2;
sigma = 2;
samples = normrnd(mu,sigma,M,N);
This will generate an MxN matrix, sampled from N(μ,𝜎), (= N(2,2) in this particular case).
For additional information, see normrnd.