COVID-19 Exploratory Data Analysis Project in Python

Data Science project 02

COVID-19 Exploratory Data Analysis Project in Python

Build a complete exploratory data analysis (eda) on covid-19 workflow with reproducible Python code, traceable calculations, validation checks, and honest limitations.

Explore Data Science training in VizagView all project ideas

Analysis question

How can daily surveillance counts be checked, smoothed, normalised by population, and summarised without presenting synthetic values as official statistics?

Dataset

A seeded, synthetic COVID-like surveillance time series for two fictional regions. It contains dates, population, daily cases, and daily deaths and is clearly labelled as teaching data.

Requirements

  • Python 3.10 or later
  • A terminal or command prompt
  • python -m pip install numpy pandas
  • About 45-60 minutes to build and review

Method and data checks

Sort by region and date, calculate a seven-day moving average within each region, compute cases per 100,000, and aggregate totals and observed ratios with safe zero handling.

  • Every row is marked as synthetic in the lesson
  • Rolling averages never cross region boundaries
  • Population-normalised rates use the matching row population
  • Ratios avoid division by zero

Complete Python code

Save the program as ds_covid19_eda.py. The dataset generator or loader, analysis functions, output, and reproducibility controls are included.

"""EDA workflow using clearly labelled synthetic COVID-like surveillance data."""

from __future__ import annotations

import numpy as np
import pandas as pd


def make_demo_surveillance(days: int = 120, seed: int = 42) -> pd.DataFrame:
    rng = np.random.default_rng(seed)
    dates = pd.date_range("2025-01-01", periods=days)
    rows: list[dict[str, object]] = []
    for country, population, phase in [("Region A", 3_000_000, 0.0), ("Region B", 5_000_000, 0.9)]:
        x = np.arange(days)
        wave = 25 + 80 * np.exp(-((x - (55 + phase * 10)) / 20) ** 2)
        cases = rng.poisson(wave)
        deaths = rng.binomial(np.maximum(cases, 1), 0.008)
        for date, daily_cases, daily_deaths in zip(dates, cases, deaths):
            rows.append({"date": date, "region": country, "population": population, "new_cases": int(daily_cases), "new_deaths": int(daily_deaths)})
    return pd.DataFrame(rows)


def analyse_surveillance(data: pd.DataFrame) -> tuple[pd.DataFrame, pd.DataFrame]:
    required = {"date", "region", "population", "new_cases", "new_deaths"}
    if missing := required.difference(data.columns):
        raise ValueError(f"Missing columns: {sorted(missing)}")
    daily = data.copy().sort_values(["region", "date"])
    daily["cases_7d_avg"] = daily.groupby("region")["new_cases"].transform(lambda s: s.rolling(7, min_periods=1).mean())
    daily["cases_per_100k"] = daily["new_cases"] / daily["population"] * 100_000
    summary = daily.groupby("region", as_index=False).agg(
        total_cases=("new_cases", "sum"), total_deaths=("new_deaths", "sum"),
        peak_daily_cases=("new_cases", "max"), mean_daily_cases_per_100k=("cases_per_100k", "mean"),
    )
    summary["observed_deaths_per_100_cases"] = np.where(summary["total_cases"] > 0, summary["total_deaths"] / summary["total_cases"] * 100, np.nan)
    return daily, summary


def main() -> None:
    _, summary = analyse_surveillance(make_demo_surveillance())
    print("SYNTHETIC TEACHING DATA — not official case counts")
    print(summary.round(3).to_string(index=False))


if __name__ == "__main__":
    main()

Run the project

  1. Create and activate a virtual environment.
  2. Install dependencies with python -m pip install numpy pandas.
  3. Run python ds_covid19_eda.py.
  4. Reconcile row counts and totals before interpreting patterns.
  5. Read the limitations before substituting any real dataset.

Expected analytical output

A daily analysis table and a region summary with total cases, total deaths, peak cases, mean daily cases per 100,000, and observed deaths per 100 cases.

Interpretation and responsible-use limits

These are not official case counts and must not support health, travel, policy, or personal-risk decisions. Real surveillance analysis requires authoritative sources, definitions, revision handling, and epidemiological review.

Ways to extend the project

Load a documented official dataset, preserve revision dates, compare reporting calendars, add uncertainty notes, and build small-multiple time-series charts.

Continue learning Data Science

Try the next project, return to the Softenant project library, or explore the Data Science course in Vizag for guided data cleaning, analysis, visualisation, and portfolio feedback.