Sitemap
Ja X

Ja X

Normal Distribution with Python

7 min readJan 24, 2024

--

The normal distribution, also known as the Gaussian Distribution or bell curve, is a fundamental statistical concept widely used in various fields. It is characterized by a symmetric, bell-shaped curve that is completely determined by its mean (average) and standard deviation. Normal distributions are prevalent in nature and human activities, making them a valuable tool for understanding and analyzing random variables in diverse areas such as statistics, finance, biology, and psychology.

1. Mathematical formulations

The probability density function (PDF) that describes the normal distribution is given by the formula:

Where:

  • f(x∣μ,σ) is the probability density function at the point x, given the mean μ and the standard deviation σ.
  • μ is the mean (average) of the distribution.
  • σ is the standard deviation, representing the measure of the spread or dispersion of the distribution.
  • e is the mathematical constant approximately equal to 2.71828.

This formula describes the shape of the normal distribution curve.
The term:

is a normalisation factor [2] ensuring that the total area under the curve equals 1, indicating the probability of any possible outcome in the distribution.

The exponent in the formula:

is what gives the normal distribution its characteristic bell shape. The argument of the exponent is a z-score, representing how many standard deviations away a given x value is from the mean (μ). The exponent term essentially measures the likelihood of a specific x value occurring in the distribution.

It’s important to note that while this formula provides a continuous description of the normal distribution, when working with specific values or ranges, the cumulative distribution function (CDF) is often used. The CDF gives the probability that a random variable takes on a value less than or equal to a given point.

2. Practical Example with Python

To initiate the process, we’ll import the required libraries and establish a connection to the drive. Afterward, we can proceed to read and visualize the data.

import pandas as pd
import numpy as np

# to cennect google drive
# if you are using Jupyter Notebook ignore this step
from google.colab import drive
drive.mount('/content/drive')

# read the data
sat_score = pd.read_csv("/content/drive/path/to_your_file/sat_score.csv")
sat_score.head()
Press enter or click to view image in full size

The dataset comprises 1000 records of SAT scores for students in the exam. Given the data, we need to:
1. Before performing calculations, let’s initially determine the mean and standard deviation of the data.
2. Determine the probability that a student will score less than 800 in the SAT exam.
3. Calculate the probability that a student will score more than 1250 in the SAT exam.
4. Identify the minimum marks a student must attain to be in the top 5%.

2.1 Calculating Mean and Standard Deviation & Distribution Visualisation

Get Ja X’s stories in your inbox

Join Medium for free to get updates from this writer.

Additionally, visualising the data will enhance our understanding of its nature.

# lets import the required function
from scipy.stats import norm

# CALCUATING MEAN AND STANDARD DEVIATION
mu = sat_score["score"].mean()
sigma = sat_score["score"].std()
print("The mean is", round(mu, 3))
print("The standard deviation is", round(sigma, 3))
The mean is 1007.46
The standard deviation is 204.426

Now, we’ll visualize the data to observe its distribution and assess whether it follows a normal pattern or not.

import seaborn as sns
import matplotlib.pyplot as plt

# defining theme
sns.set(style="white")
colors = sns.color_palette("viridis", n_colors=1)

# plotting the SAT score distribution using Seaborn with a KDE (Kernel Density Estimate) plot
plt.figure(figsize=(10, 6))
sns.histplot(sat_score['score'], kde=True, color=colors[0])

# Remove left and bottom spines to eliminate the box
sns.despine(left=True, bottom=True)

# set the title and labels
plt.title("SAT Score Distribution", fontsize=18, color='darkgreen')
plt.xlabel("SAT Scores", fontsize=14, color='darkgreen')
plt.ylabel("Density", fontsize=14, color='darkgreen')

# Set the color of tick labels on both axes
plt.xticks(color='orange')
plt.yticks(color='orange')

# display the plot
plt.show()
Press enter or click to view image in full size
SAT Score Normal Distribution by Javad Safarli

We can note that the data exhibits an almost normal distribution but doesn’t appear to be an exact match. Now, let’s compare the graph with the normal distribution line.

# Calculate the pdf of SAT scores using norm.pdf()
density = pd.DataFrame()
density["x"] = np.linspace(
sat_score["score"].min() - 0.01, sat_score["score"].max() + 0.01, 100
)
density["pdf"] = norm.pdf(density["x"], mu, sigma)

# Set a seaborn style
sns.set(style="white")

fig, ax = plt.subplots(figsize=(10, 6))

# Plot the distribution of data using a histogram and kernel density estimate (kde)
sns.histplot(sat_score["score"], ax=ax, kde=True, stat="density", color="darkgreen", alpha=0.5)

# Plot the pdf of the normal distribution
ax.plot(density["x"], density["pdf"], color="red", linewidth=2)

# Set plot labels and title
ax.set(xlabel="SAT Scores", ylabel="Density", title="Normal Distribution of SAT Scores")

ax.title.set_color("darkgreen")
ax.xaxis.label.set_color("darkgreen")
ax.yaxis.label.set_color("darkgreen")

# a legend
ax.legend(labels=['Normal Distribution', 'SAT Scores'], loc='upper left')

# Customize the grid lines
ax.grid(True, linestyle='--', alpha=0.7)

# Remove left and bottom spines to eliminate the box
sns.despine(left=True, bottom=True)

# Set the color of tick labels on both axes
plt.xticks(color='orange')
plt.yticks(color='orange')

# display the plot
plt.show()
Press enter or click to view image in full size
SAT Score Distribution vs Normal Distribution by Javad Safarli

The data demonstrates approximate normality. Consequently, we can presume the data distribution to be normal and proceed with our calculations based on this assumption.

2.2 Determine the probability that a student will score less than 800 in the SAT exam.


# norm.cdf() calculates the cumulative probability
prob_less_than_800 = norm.cdf(800, mu, sigma)
print(
"The probability that a student will score less than 800 is",
round(prob_less_than_800, 4),
)
The probability that a student will score less than 800 is 0.1551

Let’s create a plot for it.


# Calculate the area under the curve up to x = 800
area_under_curve = norm.cdf(800, mu, sigma)

fig, ax = plt.subplots(figsize=(10, 6))

# Plot the pdf of the normal distribution
ax.plot(density["x"], density["pdf"], color="red", label="Normal Distribution")

# Draw a red vertical line at x = 800
ax.axvline(x=800, color="darkgreen", linestyle="--", label="x = 800")

# Create an array of 50 numbers between min SAT score and 800
x1 = np.linspace(density["x"].min(), 800, 50)

# Fill the specified region with red color
ax.fill_between(x1, norm.pdf(x1, mu, sigma), color="red", alpha=0.3, label="Area under curve")

ax.set(xlabel="Score", ylabel="Probability")

ax.xaxis.label.set_color("darkgreen")
ax.yaxis.label.set_color("darkgreen")

ax.set_title("Normal Distribution", color="darkgreen")

# Add the percentage value on the plot
ax.text(700, 0.00015, f"{area_under_curve * 100:.2f}%", color="darkgreen", fontsize=10, ha='center')

ax.legend()

plt.xticks(color='orange')
plt.yticks(color='orange')

# Customize the grid lines
ax.grid(True, linestyle='--', alpha=0.7)

# Display the plot
plt.show()
Press enter or click to view image in full size
Normal Distribution with Python by Javad Safarli

2.3 Calculate the probability that a student will score more than 1250 in the SAT exam.
If we aim to calculate the probability that a student will score less than a specific value, we utilize the norm.cdf function. On the other hand, if we intend to calculate the probability that a student will score more than a specific value, we can directly calculate it with 1 - norm.cdf. This is because subtracting the cumulative distribution function (CDF) value from 1 yields the desired result, as 1 - norm.cdf represents the probability of scoring more than the specified value.

prob_1250 = 1 - norm.cdf(1250, mu, sigma)
print(
"The probability that a student will score more than 1250 is",
round(prob_1250, 4),
)
The probability that a student will score more than 1250 is 0.1177

2.4 Identify the minimum marks a student must attain to be in the top 5%. We’ve computed the probabilities for scores less than or more than a specified value. However, what if we aim to determine the score corresponding to, let’s say, the top 5% of the class?
For this purpose, we employ the ppf function, also known as the Percent-Point Function or Quantile Function, is used to find the value corresponding to a given cumulative probability in a probability distribution. In the context of our calculations, it helps determine the score associated with a specific percentile, such as the top 5% of the class.

top_5_percent = norm.ppf(0.95, mu, sigma)
print("The minimum score to be in top 5% should be", round(top_5_percent))
The minimum score to be in top 5% should be 1344

We determined that a student needs to score a minimum of 1344 to be in the top 5% of the class.

3. Standardisation of Normal Variables

Given normally distributed SAT scores (mean: 1000, standard deviation: 200) and ACT scores (mean: 20, standard deviation: 5), the college awards admission based on these scores. The top performer fellowship goes to the applicant with the highest combined score. The highest SAT score is 1350, and the highest ACT score is 30.

Press enter or click to view image in full size
Standardisation of Normal Variables by Javad Safarli

To facilitate a meaningful comparison between the raw highest scores in the given SAT and ACT plots, we must standardise the two scores and compare their Z-scores.

# find the Z-score of highest scorer in SAT among all the applicants
top_sat = (1350 - 1000) / 200
print('The Z-score of highest scorer in SAT among all the applicants', top_sat)
# find the Z-score of highest scorer in ACT among all the applicants
top_act = (30 - 20) / 5
print('The Z-score of highest scorer in ACT among all the applicants', top_act)
The Z-score of highest scorer in SAT among all the applicants 1.75
The Z-score of highest scorer in ACT among all the applicants 2.0

What we have calculated indicates the standard deviation above the mean. Therefore, the highest SAT score is 1.75 standard deviations above the mean, and the highest ACT score is 2.0 standard deviations above the mean. Consequently, among the applicants, the top scorer in ACT outperformed the top scorer in SAT.

--

--