Goal
Build a small Covid-19 analysis project:
- Load time series case data
- Clean/parse dates
- Plot trends and moving averages
- Compare regions
Analysis pipeline
flowchart LR A["Raw time series
(daily cases)"] --> B["Clean
(parse dates, filter country)"] B --> C["Smooth
(7-day rolling average)"] C --> D["Visualize
(trend, region comparison)"] D --> E["Conclude
(peaks, seasonality)"]
Data sources
Possible sources:
- Our World in Data (OWID)
- Johns Hopkins dataset
Step 1: Load and inspect
import pandas as pd
df = pd.read_csv("data/covid.csv")
print(df.shape)
print(df.head())Step 2: Parse dates and subset
import pandas as pd
if "date" in df.columns:
df["date"] = pd.to_datetime(df["date"], errors="coerce")Step 3: Trend plot
import matplotlib.pyplot as plt
country = "India"
sub = df[df["location"] == country].sort_values("date")
plt.figure(figsize=(10, 4))
plt.plot(sub["date"], sub["new_cases"], label="new_cases")
plt.title(f"New cases over time - {country}")
plt.xlabel("Date")
plt.ylabel("New cases")
plt.xticks(rotation=20)
plt.tight_layout()
plt.show()Step 4: Moving average
sub = sub.copy()
sub["new_cases_ma7"] = sub["new_cases"].rolling(7).mean()
plt.figure(figsize=(10, 4))
plt.plot(sub["date"], sub["new_cases"], alpha=0.4, label="daily")
plt.plot(sub["date"], sub["new_cases_ma7"], label="7-day avg")
plt.title(f"New cases (7-day avg) - {country}")
plt.legend()
plt.tight_layout()
plt.show()Step 5: Compare regions
import seaborn as sns
import matplotlib.pyplot as plt
countries = ["India", "United States", "Brazil"]
sub = df[df["location"].isin(countries)].copy()
sub = sub.sort_values("date")
plt.figure(figsize=(10, 4))
sns.lineplot(data=sub, x="date", y="new_cases", hue="location")
plt.title("New cases comparison")
plt.xticks(rotation=20)
plt.tight_layout()
plt.show()Visualize it
Deliverable
Write a short report:
- When did peaks occur?
- Is the trend seasonal?
- What data quality issues exist (missing dates/values)?
Check your understanding
Why does the project parse the date column with pd.to_datetime(df["date"], errors="coerce")?
Real datetimes are needed for sorting and time plots, and coerce flags bad values as NaT rather than raising an error.
Show answer
A โ It turns text into real datetimes and sets unparseable values to NaT instead of crashing โ Real datetimes are needed for sorting and time plots, and coerce flags bad values as NaT rather than raising an error.
Why add new_cases_ma7 = new_cases.rolling(7).mean()?
A single day tells you little, and a weekly window also evens out reporting cycles.
Show answer
A โ Daily counts are noisy, and a 7-day window smooths them so the trend shows โ A single day tells you little, and a weekly window also evens out reporting cycles.
Before computing the rolling average for India, what does the project do to the subset?
Rolling windows assume ordered rows, so the subset is sorted by date first.
Show answer
A โ Sorts it by date โ Rolling windows assume ordered rows, so the subset is sorted by date first.
Which data quality issue does the deliverable ask you to look for?
Gaps in dates or values distort trends and moving averages.
Show answer
A โ Missing dates or values โ Gaps in dates or values distort trends and moving averages.
๐งช Try It Yourself
Exercise 1 โ Parse dates
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 2 โ 7-day rolling average
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 3 โ Filter one country's data
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.