Distributions and Descriptive Statistics in Python

This tutorial introduces distributions and descriptive statistics in Python using pandas and helper functions that mirror R's syntax.

Getting Started

Install and Import Packages

%pip install pandas plotnine scipy
import os, sys
import pandas as p
from plotnine import *
sys.path.append(os.path.abspath('functions'))
from functions_distributions import *

Our Data

sw = p.Series([4.5, 5, 5.5, 5, 5.5, 6.5, 6.5, 6, 5, 4])
sw

Size

Length

len(sw)

Location

Mean and Median

sw.mean()
sw.median()

Mode

sw.mode()

Spread (1)

Percentiles

sw.quantile(q=0)  # min
sw.quantile(q=1)  # max
sw.quantile(q=.75)

Spread (2)

Standard Deviation, Variance, CV, SE

# Manual SD (sample)
x = ((sw - sw.mean())**2).sum()
x = x / (len(sw) - 1)
x**0.5
sw.std()
sw.var()
sw.std()**2
sw.std() / sw.mean()  # CV
se = sw.std() / (len(sw)**0.5)
se
LC 02
Cheesy goodness

Suppose we collected data on 10 randomly selected chunks of cheese from a production line! We measured their moisture in grams (g) in each product. We want to make sure we're making some quality cheesy goodness, so let's find out how much those moisture (cheesiness) levels vary!

The moisture in our cheese weighed 5.52 g, 5.71 g, 5.06 g, 5.10 g, 4.98 g, 5.50 g, 4.81 g, 5.55 g, 4.74 g, & 5.39 g.

  1. Please convert the following values into a Series named cheese!
  2. What was the average moisture level in the sample?
  3. How much did moisture levels vary, on average?
  4. We need to compare these levels with cheese produced in Vermont, France, and elsewhere. What's the coefficient of variation and standard error for these moisture levels?

📝 Quick check: Which single statistic reports how much the moisture levels varied, on average, from the mean?

A the mean, cheese.mean()
B the median, cheese.median()
C the standard deviation, cheese.std()
D the coefficient of variation, cheese.std() / cheese.mean()

Shape

Skewness and Kurtosis

diff = sw - sw.mean()
n = len(sw) - 1
sigma = sw.std()
sum(diff**3) / (n * sigma**3)
sum(diff**4) / (n * sigma**4)
# Using helper functions mirroring R
skewness(sw)
kurtosis(sw)
LC 03
A contractor's seawalls

A contractor is concerned that the majority of seawalls in her region might skew lower than their region's vulnerability to storms requires. Assume (hypothetically) that our sample's seawalls are the appropriate height for our level of vulnerability, and that both regions share the same level of vulnerability.

  • The mean seawall in her region is about the same height as in our sample (~5.35), but how do the skewness and kurtosis of her region's seawalls compare to our sample?
  • Her region has 12 seawalls! Their height (in meters) are 4.15, 4.35, 4.47, 4.74, 4.92, 5.19, 5.23, 5.35, 5.55, 5.70, 5.78, & 7.16.

Calculate these statistics and interpret your results in a sentence or two.

📝 Quick check: Using the by-hand formula on her 12 seawall heights, the skewness is…

A clearly negative (left-skewed) — most walls sit on the tall side
B essentially zero (symmetric) — walls are spread evenly around the mean
C clearly positive (right-skewed) — a cluster of shorter walls with a few tall outliers, so most walls skew low

Finding Parameters for Your Distributions

sw = p.Series([4.5, 5, 5.5, 5, 5.5, 6.5, 6.5, 6, 5, 4])
mymean = sw.mean()
mysd = sw.std()

Common Distributions

Normal

mynorm = rnorm(n=1000, mean=mymean, sd=mysd)
h1 = hist(mynorm)
h1.save("plotnine_figures/02_hist_normal.png", dpi=100, width=6, height=4)
Normal distribution histogram
Normal distribution histogram

Poisson

mypois = rpois(n=1000, mu=mymean)
h2 = hist(mypois)
h2.save("plotnine_figures/02_hist_poisson.png", dpi=100, width=6, height=4)
Poisson distribution histogram
Poisson distribution histogram

Exponential

myrate_e = 1 / sw.mean()
myexp = rexp(n=1000, rate=myrate_e)
h3 = hist(myexp)
h3.save("plotnine_figures/02_hist_exponential.png", dpi=100, width=6, height=4)
Exponential distribution histogram
Exponential distribution histogram

Gamma

myshape = sw.mean()**2 / sw.var()
myrate = 1 / (sw.var() / sw.mean())
mygamma = rgamma(n=1000, shape=myshape, rate=myrate)
h4 = hist(mygamma)
h4.save("plotnine_figures/02_hist_gamma.png", dpi=100, width=6, height=4)
Gamma distribution histogram
Gamma distribution histogram

Weibull

from scipy import stats as fitdistr
myshape_w, loc, myscale_w = fitdistr.weibull_min.fit(sw, floc=0)
myweibull = rweibull(n=1000, shape=myshape_w, scale=myscale_w)
h5 = hist(myweibull)
h5.save("plotnine_figures/02_hist_weibull.png", dpi=100, width=6, height=4)
Weibull distribution histogram
Weibull distribution histogram

Comparing Distributions

mysim = p.concat([
  p.DataFrame({'x': sw, 'type': "Observed"}),
  p.DataFrame({'x': mynorm, 'type': "Normal"}),
  p.DataFrame({'x': mypois, 'type': "Poisson"}),
  p.DataFrame({'x': mygamma, 'type': "Gamma"}),
  p.DataFrame({'x': myexp, 'type': "Exponential"}),
  p.DataFrame({'x': myweibull, 'type': "Weibull"})
])

g1 = (ggplot(mysim, aes(x='x', fill='type')) +
  geom_density(alpha=0.5) +
  labs(x='Seawall Height (m)', y='Density (Frequency)', subtitle='Which distribution fits best?', fill='Type'))
g1.save("plotnine_figures/02_density_comparison.png", dpi=100, width=8, height=6)
Distribution comparison
Distribution comparison
g2 = g1 + xlim(0,10)
g2.save("plotnine_figures/02_density_comparison_xlim.png", dpi=100, width=8, height=6)
Distribution comparison with x-axis limits
Distribution comparison with x-axis limits
LC 01
Simulating a normal distribution from sw

Simulate 1000 draws from a normal distribution using your sw mean and standard deviation. What are the simulated mean and sd? How close are they to sw's?

LC 04
Corgi sightings in Ithaca

You've been recruited to evaluate the frequency of Corgi sightings in the Ithaca Downtown. A sample of 10 students each reported the number of corgis they saw last Tuesday in town. Using the method of moments (or weibull_min.fit() for Weibull) and ggplot(), find out which type of distribution best matches the observed corgi distribution!

Beth saw 5, Javier saw 1, June saw 10(!), Tim saw 3, Melanie saw 4, Mohammad saw 3, Jenny saw 6, Yosuke saw 4, Jimena saw 5, and David saw 2.

Conclusion

You computed size, location, spread, and shape statistics and compared common simulated distributions using helper functions that mirror R.