Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Section 1.3 — Descriptive statistics

This notebook contains all the code from Section 1.3 Descriptive Statistics of the No Bullshit Guide to Statistics.

All the data manipulations are done using the pandas library, and data visualizations are based on the seaborn library.

Code cells containing an ALT comment and commented out show alternative way for computing the same quantities or additional details that were not included in the book. It’s up to you if you want to learn about these alternative options—just uncomment the code and execute.

Notebook setup

Note: you may need to restart the kernel to use updated packages.
<Figure size 640x480 with 0 Axes>
datasets/ directory present and ready.

\def\stderr#1{\mathbf{se}_{#1}} \def\stderrhat#1{\hat{\mathbf{se}}_{#1}} \def\Mean{\textbf{mean}} \def\Var{\textbf{var}} \def\Std{\textbf{std}} \def\Freq{\textbf{freq}} \def\RelFreq{\textbf{relfreq}} \def\CI#1{\textbf{CI}_{#1}} \def\CIL#1{\textbf{L}_{#1}} \def\CIU#1{\textbf{U}_{#1}} \def\ci#1{\textbf{ci}_{#1}} \def\cil#1{\textbf{l}_{#1}} \def\ciu#1{\textbf{u}_{#1}} \def\DMeans{\textbf{dmeans}} \def\Prop{\textbf{prop}} \def\DProps{\textbf{dprops}} \def\Err{ {\Large \varepsilon}} \def\calN{\mathcal{N}} \def\Tdist{\mathcal{T}} \def\Expon{\mathrm{Expon}}

(this cell contains the macro definitions like sex‾\stderr{\overline{\mathbf{x}}}, se^\stderrhat{}, mean\Mean, ...)

Numerical variables

Definitions

Descriptive statistics for the students dataset

Load the students dataset from CSV

Loading...
pandas.DataFrame
RangeIndex(start=0, stop=15, step=1)
Index(['student_ID', 'background', 'curriculum', 'effort', 'score'], dtype='str')
<class 'pandas.DataFrame'>
RangeIndex: 15 entries, 0 to 14
Data columns (total 5 columns):
 #   Column      Non-Null Count  Dtype  
---  ------      --------------  -----  
 0   student_ID  15 non-null     int64  
 1   background  15 non-null     str    
 2   curriculum  15 non-null     str    
 3   effort      15 non-null     float64
 4   score       15 non-null     float64
dtypes: float64(2), int64(1), str(2)
memory usage: 923.0 bytes

Focus on the score variable

Let’s look at the score variable.

0 75.0 1 75.0 2 67.0 3 70.3 4 76.1 5 79.8 6 72.7 7 75.4 8 57.0 9 69.0 10 70.4 11 96.2 12 62.9 13 57.6 14 84.3 Name: score, dtype: float64
15
[57.0, 57.6, 62.9, 67.0, 69.0, 70.3, 70.4, 72.7, 75.0, 75.0, 75.4, 76.1, 79.8, 84.3, 96.2]

Min, max, and median

57.0
96.2
39.2
72.7

Strip plot

<Figure size 500x200 with 1 Axes>

We used the option jitter=0 to disable the seaborn default behaviour of adding a small amount of random vertical displacement to each data point, which we don’t need for this plot.

Here is a version of the strip plot that also shows a solid vertical line at the mean mean(s)\mathbf{mean}(\mathbf{s}), and dashed vertical lines at mean(s)−std(s)\mathbf{mean}(\mathbf{s}) - \mathbf{std}(\mathbf{s}) and mean(s)+std(s)\mathbf{mean}(\mathbf{s}) + \mathbf{std}(\mathbf{s}).

<Figure size 500x200 with 1 Axes>

Mean, variance, and standard deviation

72.58
99.58600000000001
9.979278531036199

Histograms

score [50, 60) 2 [60, 70) 3 [70, 80) 8 [80, 90) 1 [90, 100) 1 Name: count, dtype: int64
<Figure size 500x200 with 1 Axes>

Quartiles

68.0
72.7
75.75
7.75

Box plots

<Figure size 500x200 with 1 Axes>

The score 96.2 is drawn is drawn as a separate point because it falls outside the interval [Q1−1.5⋅IQR,Q3+1.5⋅IQR][\mathbf{Q}_{1} - 1.5 \cdot \mathbf{IQR}, \mathbf{Q}_{3} + 1.5 \cdot \mathbf{IQR}].

(56.375, 87.375)

All summary statistics

count 15.00 mean 72.58 std 9.98 min 57.00 25% 68.00 50% 72.70 75% 75.75 max 96.20 Name: score, dtype: float64
Loading...

Comparing two numeric variables

Loading...
<Figure size 500x200 with 1 Axes>

Covariance and correlation

Loading...
Loading...
0.8794375135614693

Multiple numerical variables

Extract data for the two groups:

Loading...
76.4625
68.14285714285714

Strip plots

<Figure size 500x200 with 1 Axes>

Histograms

<Figure size 500x200 with 1 Axes>
<Figure size 500x200 with 1 Axes>

Box plots

<Figure size 500x200 with 1 Axes>

Categorical data

Definitions

  • freq

  • relfreq

  • mode

(see text)

Analysis of the background variable

The pandas methods .value_counts() can be used to compute the frequencies of any series or data frame.

background science 6 arts 5 business 4 Name: count, dtype: int64

Use the option normalize=True for the methods .value_counts() to compute relative frequencies.

background science 0.40 arts 0.33 business 0.27 Name: proportion, dtype: float64

The method .describe() shows some useful facts about the variable.

count 15 unique 3 top science freq 6 Name: background, dtype: object
<Figure size 500x200 with 1 Axes>

Comparing two categodescribeal variables

Loading...
Loading...
Loading...
<Figure size 500x200 with 1 Axes>
<Figure size 500x200 with 1 Axes>
Loading...
<Figure size 500x200 with 1 Axes>
Loading...
<Figure size 500x200 with 1 Axes>

Explanations

Kernel density plots

<Figure size 500x200 with 1 Axes>

Discussion

Code implementations of median and quantile functions (bonus material)

There are multiple methods for computing quantiles, which are well described in this Wikipedia article. Quantile#Estimating quantiles from a sample

Linear interpolation for the median

When computing the median of a list of values, it’s not always possible to find a value from the list that satisfies the definition “splits the list into equal parts.” For example, if the list has an even number of elements, then there is no single “middle” number. The convention in this situation is to create a new number that consists of a 50-50 mix of the two middle numbers, a process known as linear interpolation.

The code below shows the procedure for calculating the median:

The logic in the above function splits into two cases, depending on nn, the length of the list of values. If nn is odd, we return the middle value from the list of sorted values svalues[mid]. If nn is even, we return a mixture of the two values straddling the midpoint.

It’s not important that you understand the details of the above code snippet, since pandas will perform median calculations for you. I just want you to be aware this interpolation is happening behind the scenes, so you won’t be surprised if the Med\mathbf{Med} value you obtain is not one of the observations in your dataset. For example, the median of a list of integers is a decimal median([1,2]) = 1.5.

Linear interpolation for quantiles

Linear interpolation is also used when computing quartiles, percentiles, and quantiles. In this section, we’ll explain the calculations and code for computing the qqth quantile for the dataset for anyone interested in learning the technical details. Feel free to skip if you’re not passionate about code.

Suppose we want to compute the qqth quantile for a list of nn values x=[x0,x1,x2,…,xn−1]\mathbf{x}=[x_0, x_1, x_2, \ldots, x_{n-1}]. We’ll assume the values are already in sorted order. The qqth quantile corresponds to the position p=q(n−1)p = q(n-1) within the list, where pp is a decimal number between 0 (index of the first element) and n−1n-1 (index of the last element). We can split the position into an integer part ii and a fractional part gg, where i=⌊p⌋i = \lfloor p \rfloor is the greatest integer that’s less than or equal to pp, and g=p−⌊p⌋g = p - \lfloor p \rfloor is what remains of pp once we remove the integer part.

The qqth quantile lies somewhere between the values xix_i and xi+1x_{i+1} in the list. Specifically, the quantile computed by linear interpolation is a mixture with proportion gg of xi+1x_{i+1} and (1−g)(1-g) of xix_i:

quantile(x,q)=(1−g)xi+gxi+1.\texttt{quantile}(\mathbf{x}, q) = (1-g) x_i + g x_{i+1}.

The code below shows the practical implementation of the math calculations described above.

The function we defined above is equivalent to the np.quantile(q) method in pandas and NumPy, which uses the linear interpolation by default. Note however, there are other valid interpolation methods for computing quantiles that may be used in other statistics software, so don’t freak out if you get different values when computing quantiles.

Everything we discussed about the quantile function also applies to percentiles and quartiles. For example, the kk^th^ quartile is given by quantile(q=k/4), and the kk^th^ percentile is quantile(q=k/100).

The function quantile we defined above:

  • Equivalent to quantile(values, q, method="linear") in numpy.

  • Equivalent to quantile(values, q, type=7) in R.