Mathew K Analytics

Lesson 38 · Mastering Pandas

Mastering Time-Based Grouping and Aggregations in Pandas for Effective Data Analysis

In this lesson, we will unlock the power of Pandas for handling time-series data. You will learn how to group, resample, and aggregate data by dates,…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Time-Based Grouping and Aggregations with Pandas#

In this lesson, we will unlock the power of Pandas for handling time-series data.

You will learn how to group, resample, and aggregate data by dates, months, or years.

We will use the classic 'Flights' dataset. This dataset contains airline passenger numbers over time.

By the end, you will build your own mini time-series analysis in Python!

import warnings; warnings.filterwarnings("ignore")
# Data setup (Airline Passenger Flights Dataset)
import seaborn as sns
import numpy as np
np.random.seed(42)
df = sns.load_dataset('flights')
print(df.shape)
print(df.head(3))
(144, 3)
   year month  passengers
0  1949   Jan         112
1  1949   Feb         118
2  1949   Mar         132

Why Time-Based Grouping?#

Many real-life datasets track things over time: sales, weather, traffic, or stock prices.

We want to answer questions like:

  • How many passengers flew each year?
  • Which month is the busiest?
  • Are there seasonal trends?

To do this, we need to group and summarize by time with Pandas.

# Check the columns and data types
print(df.dtypes)

# Preview the columns
print(df.columns)
year             int64
month         category
passengers       int64
dtype: object
Index(['year', 'month', 'passengers'], dtype='object')
# Combine 'year' and 'month' into a single datetime column
import pandas as pd
df['date'] = pd.to_datetime(df['year'].astype(str) + '-' + df['month'].astype(str) + '-01')
print(df[['year', 'month', 'date']].head())
   year month       date
0  1949   Jan 1949-01-01
1  1949   Feb 1949-02-01
2  1949   Mar 1949-03-01
3  1949   Apr 1949-04-01
4  1949   May 1949-05-01
# Sort data by date just in case
df = df.sort_values('date')
print(df.head(3))
   year month  passengers       date
0  1949   Jan         112 1949-01-01
1  1949   Feb         118 1949-02-01
2  1949   Mar         132 1949-03-01

Visualizing Time-Series Data: First Look#

Before grouping or aggregating, it is helpful to draw a simple time-series chart.

This quickly shows any patterns, outliers, or trends in the data.

import matplotlib.pyplot as plt
# Plot the number of passengers over time
plt.figure(figsize=(10,4))
plt.plot(df['date'], df['passengers'], marker='o', linestyle='-')
plt.title('Monthly Air Passengers Over Time')
plt.xlabel('Date')
plt.ylabel('Number of Passengers')
plt.tight_layout()
plt.show()
No description has been provided for this image
# Group by year to see total flights per year
yearly = df.groupby('year')['passengers'].sum().reset_index()
print(yearly)
    year  passengers
0   1949        1520
1   1950        1676
2   1951        2042
3   1952        2364
4   1953        2700
5   1954        2867
6   1955        3408
7   1956        3939
8   1957        4421
9   1958        4572
10  1959        5140
11  1960        5714
# Find the month with the highest average passengers
monthly_avg = df.groupby('month')['passengers'].mean().sort_values(ascending=False)
print(monthly_avg)
month
Jul    351.333333
Aug    351.083333
Jun    311.666667
Sep    302.416667
May    271.833333
Mar    270.166667
Apr    267.083333
Oct    266.583333
Dec    261.833333
Jan    241.750000
Feb    235.000000
Nov    232.833333
Name: passengers, dtype: float64

Using Datetime as Index#

Setting datetime as the index unlocks powerful time-based features: resampling, shifting, rolling, and more.

Let us make 'date' the index for our DataFrame.

# Set date as the index
df_ts = df.set_index('date')
print(df_ts.head(3))
            year month  passengers
date                              
1949-01-01  1949   Jan         112
1949-02-01  1949   Feb         118
1949-03-01  1949   Mar         132
# Resample by year and sum passengers
annual = df_ts['passengers'].resample('Y').sum()
print(annual)
date
1949-12-31    1520
1950-12-31    1676
1951-12-31    2042
1952-12-31    2364
1953-12-31    2700
1954-12-31    2867
1955-12-31    3408
1956-12-31    3939
1957-12-31    4421
1958-12-31    4572
1959-12-31    5140
1960-12-31    5714
Freq: YE-DEC, Name: passengers, dtype: int64
# Calculate moving average over 12 months
df_ts['rolling_mean'] = df_ts['passengers'].rolling(window=12).mean()
print(df_ts[['passengers', 'rolling_mean']].head(15))
            passengers  rolling_mean
date                                
1949-01-01         112           NaN
1949-02-01         118           NaN
1949-03-01         132           NaN
1949-04-01         129           NaN
1949-05-01         121           NaN
1949-06-01         135           NaN
1949-07-01         148           NaN
1949-08-01         148           NaN
1949-09-01         136           NaN
1949-10-01         119           NaN
1949-11-01         104           NaN
1949-12-01         118    126.666667
1950-01-01         115    126.916667
1950-02-01         126    127.583333
1950-03-01         141    128.333333
# Plot original vs. rolling mean
plt.figure(figsize=(10,4))
plt.plot(df_ts.index, df_ts['passengers'], label='Original', color='blue')
plt.plot(df_ts.index, df_ts['rolling_mean'], label='12-Month Moving Avg', color='red')
plt.title('Passengers: Original vs. 12-Month Moving Average')
plt.xlabel('Date')
plt.ylabel('Passengers')
plt.legend()
plt.tight_layout()
plt.show()
No description has been provided for this image

Mini-Project: Find Peak Travel Season#

Let us combine what you have learned.

Your task:

Find the month and year when air travel peaked.

Tip: You can use idxmax() and loc to solve this in code!

# Solution: Find the date with max passengers
peak_month = df_ts['passengers'].idxmax()
peak_value = df_ts['passengers'].max()
print(f'Peak month: {peak_month.strftime("%Y-%m")}, Passengers: {peak_value}')
Peak month: 1960-07, Passengers: 622
# Group passengers by quarter
quarterly = df_ts['passengers'].resample('Q').mean()
print(quarterly.head())
date
1949-03-31    120.666667
1949-06-30    128.333333
1949-09-30    144.000000
1949-12-31    113.666667
1950-03-31    127.333333
Freq: QE-DEC, Name: passengers, dtype: float64
# Add a column for year and month name (with dt accessor)
df_ts['year'] = df_ts.index.year
df_ts['month_name'] = df_ts.index.month_name()
print(df_ts[['year', 'month_name', 'passengers']].head())
            year month_name  passengers
date                                   
1949-01-01  1949    January         112
1949-02-01  1949   February         118
1949-03-01  1949      March         132
1949-04-01  1949      April         129
1949-05-01  1949        May         121
# Aggregate: Find average passengers per year per month
pivot = df_ts.pivot_table(index='year', columns='month_name', values='passengers', aggfunc='mean')
print(pivot.head())
month_name  April  August  December  February  January   July   June  March  \
year                                                                          
1949        129.0   148.0     118.0     118.0    112.0  148.0  135.0  132.0   
1950        135.0   170.0     140.0     126.0    115.0  170.0  149.0  141.0   
1951        163.0   199.0     166.0     150.0    145.0  199.0  178.0  178.0   
1952        181.0   242.0     194.0     180.0    171.0  230.0  218.0  193.0   
1953        235.0   272.0     201.0     196.0    196.0  264.0  243.0  236.0   

month_name    May  November  October  September  
year                                             
1949        121.0     104.0    119.0      136.0  
1950        125.0     114.0    133.0      158.0  
1951        172.0     146.0    162.0      184.0  
1952        183.0     172.0    191.0      209.0  
1953        229.0     180.0    211.0      237.0  

Troubleshooting Tips#

  • If your resample gives errors, double-check that your index is datetime.
  • If you get missing data or NaN, inspect your data for gaps.
  • Always preview your new tables after any operation.

Learning to fix common bugs makes you a real pandas pro!

# Speed tip: Use categorical dtype for month_name if you will use it often
df_ts['month_name'] = pd.Categorical(df_ts['month_name'], categories=['January','February','March','April','May','June','July','August','September','October','November','December'], ordered=True)
print(df_ts['month_name'].head())
date
1949-01-01     January
1949-02-01    February
1949-03-01       March
1949-04-01       April
1949-05-01         May
Name: month_name, dtype: category
Categories (12, object): ['January' < 'February' < 'March' < 'April' ... 'September' < 'October' < 'November' < 'December']

Recap: What Did You Learn?#

  • How to create datetime columns and sort by date
  • Grouping and aggregating by year, month, or quarter
  • Resampling, moving averages, and pivot tables for time-series
  • Troubleshooting index and data-type issues

With these tools, you can explore trends in almost any time-based data!

Next Steps: Like, Comment, and Subscribe!#

Practice these ideas with your favorite datasetssales, weather, or personal logs.

Let us know in the comments what time-series you want to tackle next.

For more data skills, make sure to like and subscribe for future lessons!

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.