{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Coverage and dropout rate by facility\n",
    "\n",
    "*Routine vaccination coverage, 2024 · R*\n",
    "\n",
    "Cassion · data-analysis.cassion.dev\n",
    "\n",
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/thecassion/cassion-learning-platform/blob/main/apps/data-analysis/public/datasets/examples/routine-vaccination-coverage-2024/coverage-dropout.r.en.ipynb)"
   ],
   "id": "cell-000"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What this produces\n",
    "\n",
    "The same dropout calculation and flagging logic as the Python example, written\n",
    "with tidyverse verbs.\n",
    "\n",
    "Every dataset on this platform is synthetic. Coverage here describes no real\n",
    "district.\n",
    "\n",
    "## Setup"
   ],
   "id": "cell-001"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| message: false\n",
    "library(readr)\n",
    "library(dplyr)\n",
    "library(tidyr)\n",
    "\n",
    "URL <- paste0(\n",
    "  \"https://data-analysis.cassion.dev/datasets/files/\",\n",
    "  \"vaccination-coverage-2024.v1.csv\"\n",
    ")\n",
    "\n",
    "epi <- read_csv(URL, col_types = cols(\n",
    "  facility_id = col_character(),\n",
    "  period      = col_date(),\n",
    "  .default    = col_guess()\n",
    ")) |>\n",
    "  mutate(month = format(period, \"%Y-%m\"))\n",
    "\n",
    "glimpse(epi)"
   ],
   "id": "cell-002"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A non-report is not zero children vaccinated"
   ],
   "id": "cell-003"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "epi |>\n",
    "  filter(!report_submitted) |>\n",
    "  summarise(\n",
    "    rows            = n(),\n",
    "    rows_with_zero  = sum(doses_administered == 0),\n",
    "    facility_months = n_distinct(paste(facility_id, month))\n",
    "  )"
   ],
   "id": "cell-004"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Every non-reporting row carries a zero. Sum without filtering and you have\n",
    "asserted that no child in that catchment was vaccinated that month.\n",
    "\n",
    "## The denominator is annual, the reporting is monthly\n",
    "\n",
    "`target_population` is the annual target repeated on every row. Monthly coverage\n",
    "divides by that figure over twelve; dividing by the full annual figure\n",
    "understates coverage twelvefold."
   ],
   "id": "cell-005"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "MONTHS_IN_YEAR <- 12\n",
    "\n",
    "epi |>\n",
    "  filter(antigen == \"penta3\") |>\n",
    "  group_by(month) |>\n",
    "  summarise(\n",
    "    doses         = sum(doses_administered),\n",
    "    annual_target = sum(target_population),\n",
    "    completeness  = round(mean(report_submitted), 3),\n",
    "    .groups = \"drop\"\n",
    "  ) |>\n",
    "  mutate(\n",
    "    wrong_annual_denominator    = round(doses / annual_target, 3),\n",
    "    correct_monthly_denominator = round(doses / (annual_target / MONTHS_IN_YEAR), 3)\n",
    "  )"
   ],
   "id": "cell-006"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dropout between penta1 and penta3\n",
    "\n",
    "Dropout does not depend on a population estimate at all — both terms come from\n",
    "the same register, which is why it is a better programme signal than coverage."
   ],
   "id": "cell-007"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "series <- epi |>\n",
    "  filter(report_submitted, antigen %in% c(\"penta1\", \"penta3\")) |>\n",
    "  group_by(facility_id, antigen) |>\n",
    "  summarise(doses = sum(doses_administered), .groups = \"drop\") |>\n",
    "  pivot_wider(names_from = antigen, values_from = doses) |>\n",
    "  filter(!is.na(penta1), !is.na(penta3)) |>\n",
    "  mutate(dropout = (penta1 - penta3) / penta1) |>\n",
    "  arrange(desc(dropout))\n",
    "\n",
    "cat(\"median dropout:\", round(100 * median(series$dropout), 1), \"%\\n\")\n",
    "head(series, 10)"
   ],
   "id": "cell-008"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A facility reporting near-zero dropout deserves as much suspicion as one\n",
    "reporting a very high figure. Near-zero usually means penta3 was reconstructed\n",
    "from penta1 rather than counted.\n",
    "\n",
    "## The over-reporting flag, applied at the right level"
   ],
   "id": "cell-009"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "by_month <- epi |>\n",
    "  filter(report_submitted, antigen %in% c(\"penta1\", \"penta3\")) |>\n",
    "  select(facility_id, month, antigen, doses_administered) |>\n",
    "  pivot_wider(names_from = antigen, values_from = doses_administered) |>\n",
    "  filter(!is.na(penta1), !is.na(penta3)) |>\n",
    "  mutate(impossible = penta3 > penta1)\n",
    "\n",
    "by_month |>\n",
    "  group_by(facility_id) |>\n",
    "  summarise(ever_flagged = any(impossible), .groups = \"drop\") |>\n",
    "  summarise(\n",
    "    flagged    = sum(ever_flagged),\n",
    "    facilities = n()\n",
    "  )"
   ],
   "id": "cell-010"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Thirty-seven of thirty-eight. A check that flags almost the whole district\n",
    "identifies nothing: the two doses go to different children in different months\n",
    "and the counts have no reason to move together, so ordinary noise crosses the\n",
    "line constantly."
   ],
   "id": "cell-011"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "persistent <- series |> filter(dropout < 0)\n",
    "persistent"
   ],
   "id": "cell-012"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "by_month |>\n",
    "  filter(facility_id %in% persistent$facility_id) |>\n",
    "  group_by(facility_id) |>\n",
    "  summarise(\n",
    "    months_flagged  = sum(impossible),\n",
    "    months_reported = n(),\n",
    "    .groups = \"drop\"\n",
    "  ) |>\n",
    "  arrange(desc(months_flagged))"
   ],
   "id": "cell-013"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Six facilities on the annual total. That is a list a supervisor can act on.\n",
    "\n",
    "## Coverage by antigen"
   ],
   "id": "cell-014"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "epi |>\n",
    "  filter(report_submitted) |>\n",
    "  group_by(antigen) |>\n",
    "  summarise(\n",
    "    coverage = round(\n",
    "      sum(doses_administered) / (sum(target_population) / MONTHS_IN_YEAR), 3\n",
    "    ),\n",
    "    .groups = \"drop\"\n",
    "  ) |>\n",
    "  arrange(desc(coverage))"
   ],
   "id": "cell-015"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The denominator counts only facilities that reported, keeping numerator and\n",
    "denominator on the same set of facilities. That is the subject of the\n",
    "completeness-adjustment example.\n",
    "\n",
    "## What to report\n",
    "\n",
    "Coverage with its denominator stated, dropout as the signal that does not depend\n",
    "on a population estimate, and the over-reporting list with the aggregation level\n",
    "it was computed at."
   ],
   "id": "cell-016"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "R",
   "language": "R",
   "name": "ir"
  },
  "language_info": {
   "name": "R",
   "file_extension": ".r"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
