1.8. Python: Descriptives and Indexing#

In this notebook we cover some key Pandas syntax and functions:

  • Syntax for getting various descriptive statistics from a Pandas dataframe

  • Syntax for indexing a dataframe - finding the rows and columns that you need

    • this allows you to get descriptives for specific rows and columns

Here we meet indexing in the context of descriptive statistics, but indexing is something you will do every single time you write code for data analysis. Incorrect syntax in indexing is the number one biggest source of bugs for student on this course, so it is well worth spending the time to get to grips with it.

You absolutely should work through all the exercises in this notebook in advance of the tutorial.

1.8.1. Set up Python Libraries#

As usual you will need to run this code block to import the relevant Python libraries

# Set-up Python libraries - you need to run this but you don't need to change it
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
import pandas as pd
import seaborn as sns
sns.set_theme(style='white')
import statsmodels.api as sm
import statsmodels.formula.api as smf

1.8.2. Import a dataset to work with#

We will work with weather data from the Oxford weather station. This code block will read it automatically from the internet.

weather = pd.read_csv("https://raw.githubusercontent.com/jillxoreilly/StatsCourseBook_2024/main/data/OxfordWeather.csv")
display(weather)
YYYY Month MM DD DD365 Tmax Tmin Tmean Trange Rainfall_mm
0 1827 Jan 1 1 1 8.3 5.6 7.0 2.7 0.0
1 1827 Jan 1 2 2 2.2 0.0 1.1 2.2 0.0
2 1827 Jan 1 3 3 -2.2 -8.3 -5.3 6.1 9.7
3 1827 Jan 1 4 4 -1.7 -7.8 -4.8 6.1 0.0
4 1827 Jan 1 5 5 0.0 -10.6 -5.3 10.6 0.0
... ... ... ... ... ... ... ... ... ... ...
71338 2022 Apr 4 26 116 15.2 4.1 9.7 11.1 0.0
71339 2022 Apr 4 27 117 10.7 2.6 6.7 8.1 0.0
71340 2022 Apr 4 28 118 12.7 3.9 8.3 8.8 0.0
71341 2022 Apr 4 29 119 11.7 6.7 9.2 5.0 0.0
71342 2022 Apr 4 30 120 17.6 1.0 9.3 16.6 0.0

71343 rows × 10 columns

1.8.3. Get descriptive statistics#

We will look at indexing in the context of getting descriptive statistics for the different variables in a dataframe, and/or for a selection of rows.

Pandas has a number of built-in functions to get descriptive statistics:

  • df.mean() - gets the mean

  • df.median() - gets the median

  • df.var() - gets the variance

  • df.std() - gets the standard deviation

  • df.min() - gets the minimum value

  • df.max() - gets the maximum value

  • df.corr() - gets the correlation coefficient (Pearson or Spearman)

in the function names above, df is just a placeholder for “dataframe”

You can replace df with the name of your dataframe (and we need to tell the function to use only columns containing numerical data)

weather.mean(numeric_only=True)
YYYY           1924.165174
MM                6.516210
DD               15.729154
DD365           182.917077
Tmax             13.890153
Tmin              6.156018
Tmean            10.046208
Trange            7.734244
Rainfall_mm       1.786964
dtype: float64

Which columns from the dataframe are missing from the table of means?

  • Month is missing because the values are strings (words); we only get the mean for numerical columns

1.8.4. Decriptives for a single column#

Format:

  • df.column.mean()

You might just want the mean for one column, in which case you can include the column name as follows:

weather.Tmax.mean()
13.890153065515406

Instead of a whole table of means, many of which were irrelevant, we now just have the single number we wanted - the mean of Tmax

  • Think check that the value obtained this way matches the one in the table above.

Why does it work?#

The commmand weather.Tmax.mean() has two steps.

Step 1:

The syntax weather.Tmax (or more generally, df.column) returns just the one column of the dataframe as a series (essentially a one-column table).

Look:

weather.Tmax
0         8.3
1         2.2
2        -2.2
3        -1.7
4         0.0
         ... 
71338    15.2
71339    10.7
71340    12.7
71341    11.7
71342    17.6
Name: Tmax, Length: 71343, dtype: float64

If we liked, we could give this single-column series a name a ‘save’ it:

DailyMaxima  = weather.Tmax
print(DailyMaxima)
0         8.3
1         2.2
2        -2.2
3        -1.7
4         0.0
         ... 
71338    15.2
71339    10.7
71340    12.7
71341    11.7
71342    17.6
Name: Tmax, Length: 71343, dtype: float64

However, we don’t need to do that as we can just tack the .mean() function onto it directly as follows:

Step 2:

The syntax .mean() gets the mean of the thing before the dot (i.e. the series you created with the command weather.Tmax)

weather.Tmax.mean()
13.890153065515406

Exercises#

Complete the following quick practice questions:

# get the mean daily rainfall
# get the median daily rainfall
# get the standard deviation of the maximum daily temperature
# find the minimum value of "year" (you will need two separate commands)

1.8.5. Get descriptives for a subset of rows#

  • df.query('columnname == number')

  • df.query('columnname == "string"')

  • df.query('columnname1 == value1 and columnname2 == value2')

Say I want to know the mean daily maximum temperatures for the year 1921.

Step 1: find the relevant rows#

I first need to somehow pull out the rows of the table where the value for YYYY is 1921

I can do this using the function df.query, for example weather.query(‘YYYY == 1921’)

  • note the quote marks surrounding the whole query

  • note the double equals sign ==, which is used for checking if two bvalues are equal (as opposed to setting a value)

# get all the rows where year is 1921
weather.loc[weather.YYYY == 1921]
YYYY Month MM DD DD365 Tmax Tmin Tmean Trange Rainfall_mm
34333 1921 Dec 12 31 1 9.1 3.3 6.2 5.8 0.0
34334 1921 Jan 1 1 2 12.2 7.1 9.7 5.1 9.7
34335 1921 Jan 1 2 3 11.9 8.7 10.3 3.2 6.1
34336 1921 Jan 1 3 4 9.9 5.9 7.9 4.0 0.0
34337 1921 Jan 1 4 5 12.3 9.8 11.1 2.5 5.5
... ... ... ... ... ... ... ... ... ... ...
34693 1921 Dec 12 26 361 10.8 -3.1 3.9 13.9 5.6
34694 1921 Dec 12 27 362 11.2 5.4 8.3 5.8 1.3
34695 1921 Dec 12 28 363 13.9 3.9 8.9 10.0 0.0
34696 1921 Dec 12 29 364 7.6 1.7 4.7 5.9 0.8
34697 1921 Dec 12 30 365 11.7 1.9 6.8 9.8 4.5

365 rows × 10 columns

Note the size of this table - there are 365 rows. Why?

  • In the original table weather, there is one row per day

  • 365 of those rows (days) match the criterion ‘YYYY = 1921’ because there are 365 days in a year.

If I wanted to, I could give this table a name and ‘save’ it for later use:

weather1921 = weather.query('YYYY == 1921') # create a new dataframe for just 1921
weather1921 # look at my new dataframe
YYYY Month MM DD DD365 Tmax Tmin Tmean Trange Rainfall_mm
34333 1921 Dec 12 31 1 9.1 3.3 6.2 5.8 0.0
34334 1921 Jan 1 1 2 12.2 7.1 9.7 5.1 9.7
34335 1921 Jan 1 2 3 11.9 8.7 10.3 3.2 6.1
34336 1921 Jan 1 3 4 9.9 5.9 7.9 4.0 0.0
34337 1921 Jan 1 4 5 12.3 9.8 11.1 2.5 5.5
... ... ... ... ... ... ... ... ... ... ...
34693 1921 Dec 12 26 361 10.8 -3.1 3.9 13.9 5.6
34694 1921 Dec 12 27 362 11.2 5.4 8.3 5.8 1.3
34695 1921 Dec 12 28 363 13.9 3.9 8.9 10.0 0.0
34696 1921 Dec 12 29 364 7.6 1.7 4.7 5.9 0.8
34697 1921 Dec 12 30 365 11.7 1.9 6.8 9.8 4.5

365 rows × 10 columns

… but I don’t need to do this as I can tack on more commands to complete my goal in a single line of code.

Step 2: find the relevant column#

Now that I have grabbed the relevant rows, I narrow it down to column Tmax

weather.query('YYYY == 1920').Tmax
33967     3.2
33968    13.2
33969     4.5
33970     3.7
33971     3.7
         ... 
34328    12.1
34329    11.9
34330    12.3
34331    12.4
34332    12.1
Name: Tmax, Length: 366, dtype: float64

Step 4: add in the actual function#

FInally, I can tack on teh function I want to run on my selected rows and column: mean():

weather.query('YYYY == 1920').Tmax.mean()
13.701092896174861

Exercises#

Complete the following quick practice questions:

# Get the mean daily maximum temperature in 2006
# Get the mean daily minimum temperature in 1947

1.8.6. Get descriptives for one category#

What about getting the mean daily maximum temperatures for, say, October? So I need to pull out all the rows in which ’MM’ matches ’Oct’

The syntax is very similar, but now I am matching a string "Oct", so it needs to be in quotes:

weather.query('Month == "Oct"').Tmax.mean()
14.112638544251446
  • note you can actually use single and double quotes interchangeably in Python, but in cases like this where you have quotes within quotes, it is better to use both types to avoid the computer getting confused about which opening and closing quotes to pair up.

so you could do either of these

  • weather.query(‘MM == “Oct”’).Tmax.mean()

  • weather.query(“MM == ‘Oct’”).Tmax.mean()

but not these

  • weather.query(‘MM == ‘Oct’’).Tmax.mean()

  • weather.query(“MM == “Oct””).Tmax.mean()

Exercises#

Complete the following quick practice questions:

# Get the mean daily rainfall in January
# Get the mean daily rainfall in June

1.8.7. Match multiple conditions#

What if I want to know the mean daily maximum temperature in 1920 for June only?

We can simply use and or & to pass df.query() multiple conditions:

# mean daily maximum temperature in 1920
weather.query('YYYY == 1920').Tmax.mean()
13.701092896174861
# mean daily maximumm temperature in 1920
weather.query('YYYY == 1920 & MM == 6').Tmax.mean()
19.553333333333335
  • Think hopefully the value for June is higher than the average for the whole year? If not something has gone wrong!

Exercises#

Complete the following quick practice questions:

# Get the mean daily rainfall in June 2007
# Get the minimum temperature in January 1947

1.8.8. Syntax for correlation#

When we run a correlation, we need to index two columns - the two we are correlating.

Using the pandas function df.corr() we can do so as follows:

# get the correlation between columns Tmin and Tmax of dataframe weather
weather.Tmin.corr(weather.Tmax)
0.8414800914062084

We can set the type of correlation to Pearson or Spearman as appropriate (the default is Pearson’s \(r\)):

# get the correlation between columns Tmin and Tmax of dataframe weather
weather.Tmin.corr(weather.Tmax, method='spearman')
0.8438796074978867

Exercises#

Complete the following practice questions to help you get to grips with the syntax for correlation:

# Find the Spearman correlation between daily mean temperature Tmean, and rainfall
weather.Tmean.corr(weather.Rainfall_mm, method='spearman')
-0.019287092574398337
# Find the correlation between year and daily mean temperature
weather.Tmean.corr(weather.YYYY)
0.08304423160159409

All-by-all correlation matrix#

We can also quickly output all the correlations between all possible pairs of columns in a dataframe by simply not giving any column index (but we do have to tell it to only use the numeric columns):

weather.corr(numeric_only=True)
YYYY MM DD DD365 Tmax Tmin Tmean Trange Rainfall_mm
YYYY 1.000000 -0.003411 -0.000059 -0.003372 0.071631 0.089683 0.083044 -0.001257 0.008117
MM -0.003411 1.000000 0.010567 0.995580 0.179681 0.235401 0.213082 -0.018820 0.043672
DD -0.000059 0.010567 1.000000 0.092771 0.001217 0.002876 0.002035 -0.002055 0.005315
DD365 -0.003372 0.995580 0.092771 1.000000 0.177016 0.233248 0.210545 -0.020536 0.043925
Tmax 0.071631 0.179681 0.001217 0.177016 1.000000 0.841480 0.967881 0.593339 -0.008807
Tmin 0.089683 0.235401 0.002876 0.233248 0.841480 1.000000 0.950248 0.064379 0.086181
Tmean 0.083044 0.213082 0.002035 0.210545 0.967881 0.950248 1.000000 0.371965 0.035037
Trange -0.001257 -0.018820 -0.002055 -0.020536 0.593339 0.064379 0.371965 1.000000 -0.144654
Rainfall_mm 0.008117 0.043672 0.005315 0.043925 -0.008807 0.086181 0.035037 -0.144654 1.000000

The problem with this is that the figure we want is often buried amongst a lot of irrelevant correlation coefficients.

Correlation using scipy.stats#

Note that here we aare using the pandas function df.corr()

Later in the course we will use two functions from a library called scipy.stats:

  • stats.pearsonr()

  • stats.spearmanr()

These are actually a bit more useful as they give us a \(p\)-value for the correlation as well as the correlation coefficient

  • don’t worry if you don’t know what a \(p\)-value is yet - this will be covered later in the course

scipy.stats will be used extensively in the module on hypothesis testing