Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
| Download

📚 The CoCalc Library - books, templates and other resources

Views: 96140
License: OTHER
Kernel: Python 3

Example from Think Stats

http://thinkstats2.com

Copyright 2019 Allen B. Downey

MIT License: https://opensource.org/licenses/MIT

%matplotlib inline import numpy as np import pandas as pd import random import thinkstats2 import thinkplot from matplotlib import MatplotlibDeprecationWarning from warnings import simplefilter simplefilter('ignore', MatplotlibDeprecationWarning)

Central Limit Theorem

If you add up independent variates from a distribution with finite mean and variance, the sum converges on a normal distribution.

The following function generates samples with difference sizes from an exponential distribution.

def MakeExpoSamples(beta=2.0, iters=1000): """Generates samples from an exponential distribution. beta: parameter iters: number of samples to generate for each size returns: list of samples """ samples = [] for n in [1, 10, 100]: sample = [np.sum(np.random.exponential(beta, n)) for _ in range(iters)] samples.append((n, sample)) return samples

This function generates normal probability plots for samples with various sizes.

def NormalPlotSamples(samples, plot=1, ylabel=''): """Makes normal probability plots for samples. samples: list of samples label: string """ for n, sample in samples: thinkplot.SubPlot(plot) thinkstats2.NormalProbabilityPlot(sample) thinkplot.Config(title='n=%d' % n, legend=False, xticks=[], yticks=[], xlabel='Random normal variate', ylabel=ylabel) plot += 1

The following plot shows how the sum of exponential variates converges to normal as sample size increases.

thinkplot.PrePlot(num=3, rows=2, cols=3) samples = MakeExpoSamples() NormalPlotSamples(samples, plot=1, ylabel='Sum of expo values')
Image in a Jupyter notebook

The lognormal distribution has higher variance, so it requires a larger sample size before it converges to normal.

def MakeLognormalSamples(mu=1.0, sigma=1.0, iters=1000): """Generates samples from a lognormal distribution. mu: parmeter sigma: parameter iters: number of samples to generate for each size returns: list of samples """ samples = [] for n in [1, 10, 100]: sample = [np.sum(np.random.lognormal(mu, sigma, n)) for _ in range(iters)] samples.append((n, sample)) return samples
thinkplot.PrePlot(num=3, rows=2, cols=3) samples = MakeLognormalSamples() NormalPlotSamples(samples, ylabel='sum of lognormal values')
Image in a Jupyter notebook

The Pareto distribution has infinite variance, and sometimes infinite mean, depending on the parameters. It violates the requirements of the CLT and does not generally converge to normal.

def MakeParetoSamples(alpha=1.0, iters=1000): """Generates samples from a Pareto distribution. alpha: parameter iters: number of samples to generate for each size returns: list of samples """ samples = [] for n in [1, 10, 100]: sample = [np.sum(np.random.pareto(alpha, n)) for _ in range(iters)] samples.append((n, sample)) return samples
thinkplot.PrePlot(num=3, rows=2, cols=3) samples = MakeParetoSamples() NormalPlotSamples(samples, ylabel='sum of Pareto values')
Image in a Jupyter notebook

If the random variates are correlated, that also violates the CLT, so the sums don't generally converge.

To generate correlated values, we generate correlated normal values and then transform to whatever distribution we want.

def GenerateCorrelated(rho, n): """Generates a sequence of correlated values from a standard normal dist. rho: coefficient of correlation n: length of sequence returns: iterator """ x = random.gauss(0, 1) yield x sigma = np.sqrt(1 - rho**2) for _ in range(n-1): x = random.gauss(x * rho, sigma) yield x
from scipy.stats import norm from scipy.stats import expon def GenerateExpoCorrelated(rho, n): """Generates a sequence of correlated values from an exponential dist. rho: coefficient of correlation n: length of sequence returns: NumPy array """ normal = list(GenerateCorrelated(rho, n)) uniform = norm.cdf(normal) expo = expon.ppf(uniform) return expo
def MakeCorrelatedSamples(rho=0.9, iters=1000): """Generates samples from a correlated exponential distribution. rho: correlation iters: number of samples to generate for each size returns: list of samples """ samples = [] for n in [1, 10, 100]: sample = [np.sum(GenerateExpoCorrelated(rho, n)) for _ in range(iters)] samples.append((n, sample)) return samples
thinkplot.PrePlot(num=3, rows=2, cols=3) samples = MakeCorrelatedSamples() NormalPlotSamples(samples, ylabel='Sum of correlated exponential values')
Image in a Jupyter notebook

Exercises

Exercise: In Section 5.4, we saw that the distribution of adult weights is approximately lognormal. One possible explanation is that the weight a person gains each year is proportional to their current weight. In that case, adult weight is the product of a large number of multiplicative factors:

w = w0 f1 f2 ... fn

where w is adult weight, w0 is birth weight, and fi is the weight gain factor for year i.

The log of a product is the sum of the logs of the factors:

logw = logw0 + logf1 + logf2 + ... + logfn

So by the Central Limit Theorem, the distribution of logw is approximately normal for large n, which implies that the distribution of w is lognormal.

To model this phenomenon, choose a distribution for f that seems reasonable, then generate a sample of adult weights by choosing a random value from the distribution of birth weights, choosing a sequence of factors from the distribution of f, and computing the product. What value of n is needed to converge to a lognormal distribution?

# Solution goes here
# Solution goes here
# Solution goes here
# Solution goes here