Lesson 10 · Pandas Projects
Weather Data Analysis with Python Pandas: Real Project Walkthrough
A complete, standalone tutorial: build a synthetic year of daily weather, then clean, resample, and analyze it with pandas. No prior pandas experience…
- CoursePandas Projects
- Lesson10 of 10
- Video17 min
- FormatJupyter notebook · 15 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbPandas for Weather Data: A Full Year of Daily Records#
- A complete, standalone tutorial: build a synthetic year of daily weather, then clean, resample, and analyze it with pandas.
- No prior pandas experience needed. Let's jump straight in.
Before You Start#
- Open a new Jupyter Notebook in VS Code and select your Python interpreter as the kernel.
- If pandas isn't installed yet, open a terminal in VS Code and run: pip install pandas
Part 1: Building the Dataset#
import pandas as pd
import numpy as np
print(pd.__version__)
Generating a Synthetic Year of Weather#
rng = np.random.default_rng(seed=33)
dates = pd.date_range('2026-01-01', periods=365, freq='D')
day_of_year = np.arange(365)
seasonal_swing = 12 * np.sin(2 * np.pi * (day_of_year - 80) / 365)
avg_temp = 18 + seasonal_swing + rng.normal(0, 2.5, size=365)
avg_temp = avg_temp.round(1)
print(avg_temp[:5])
min_temp = (avg_temp - rng.uniform(3, 7, size=365)).round(1)
max_temp = (avg_temp + rng.uniform(3, 7, size=365)).round(1)
precipitation = np.where(rng.random(365) < 0.3, rng.exponential(6, size=365).round(1), 0.0)
humidity = np.clip(rng.normal(60, 12, size=365), 20, 100).round(0)
weather = pd.DataFrame({
'date': dates,
'avg_temp_c': avg_temp,
'min_temp_c': min_temp,
'max_temp_c': max_temp,
'precipitation_mm': precipitation,
'humidity_pct': humidity
})
print(weather.shape)
Injecting a Few Missing Readings#
missing_idx = rng.choice(weather.index, size=8, replace=False)
weather.loc[missing_idx, 'avg_temp_c'] = np.nan
weather.to_csv('daily_weather.csv', index=False)
weather = pd.read_csv('daily_weather.csv', parse_dates=['date'])
weather.head()
Part 2: First Look and Cleaning#
print(weather.shape)
weather.info()
weather.isna().sum()
Filling Missing Temperatures#
weather = weather.sort_values('date').reset_index(drop=True)
weather['avg_temp_c'] = weather['avg_temp_c'].interpolate()
weather['avg_temp_c'].isna().sum()
Part 3: Working with Dates#
weather = weather.set_index('date')
weather.loc['2026-07'].head()
print(weather.loc['2026-07', 'avg_temp_c'].mean().round(1))
print(weather.loc['2026-01', 'avg_temp_c'].mean().round(1))
Part 4: Resampling to Monthly Totals#
monthly = weather.resample('ME').agg(
avg_temp_c=('avg_temp_c', 'mean'),
total_precip_mm=('precipitation_mm', 'sum'),
avg_humidity_pct=('humidity_pct', 'mean')
).round(1)
monthly
Part 5: Rolling Averages#
weather['rolling_7d_temp'] = weather['avg_temp_c'].rolling(window=7).mean()
weather[['avg_temp_c', 'rolling_7d_temp']].tail()
Flagging Extreme Weather Days#
weather['is_extreme'] = (weather['max_temp_c'] > 28) | (weather['precipitation_mm'] > 15)
print(weather['is_extreme'].sum())
weather[weather['is_extreme']][['max_temp_c', 'precipitation_mm']].head()
Part 6: Seasonal Patterns#
weather_reset = weather.reset_index()
weather_reset['month'] = weather_reset['date'].dt.month_name()
monthly_avg_temp = weather_reset.groupby('month')['avg_temp_c'].mean().round(1)
monthly_avg_temp = monthly_avg_temp.reindex(['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'])
monthly_avg_temp
Part 7: Visualizing the Results#
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(weather.index, weather['avg_temp_c'], color='gray', alpha=0.4, label='Daily avg temp')
ax.plot(weather.index, weather['rolling_7d_temp'], color='crimson', linewidth=2, label='7-day rolling average')
ax.set_title('Daily Temperature Across the Year')
ax.set_ylabel('Temperature (C)')
ax.legend()
plt.tight_layout()
plt.savefig('temperature_trend.png', dpi=150)
plt.close(fig)
print('Saved temperature_trend.png')
fig, ax = plt.subplots(figsize=(8, 5))
monthly['total_precip_mm'].plot(kind='bar', ax=ax, color='steelblue')
ax.set_title('Total Precipitation by Month')
ax.set_ylabel('Precipitation (mm)')
ax.set_xticklabels([d.strftime('%b') for d in monthly.index], rotation=45)
plt.tight_layout()
plt.savefig('monthly_precipitation.png', dpi=150)
plt.close(fig)
print('Saved monthly_precipitation.png')
Wrap-Up: What You Learned#
- Generating a realistic synthetic year of weather with a seasonal sine wave, then saving and reloading with to_csv and read_csv.
- Spotting and cleaning missing values with isna and interpolate.
- Setting a datetime index and slicing it with partial strings like '2026-07'.
- Resampling to monthly totals and averages with resample plus agg.
- Rolling averages for smoothing noisy daily data, and boolean flags for extreme days.
- Seasonal analysis with dt.month_name, groupby, and reindex for correct calendar order.
- You went from a raw synthetic weather feed to a full seasonal analysis with charts. If you want the next dataset in this series to land in your feed automatically, subscribing is the move see you in the next one.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



