Counting Cases

How Epidemics Spread ๐Ÿ†

Chapter 1 ยท Counting Cases

Before you can ask how a disease spreads, you have to count it, and counting is harder than it sounds. Do you count people who feel ill, people who have been tested, or people who were infected last week and have already recovered? Do you count new cases or all current cases? Every model in this course, from the doubling of a first outbreak to the networks of later chapters, is fed by numbers that someone had to decide how to count. This chapter fixes the vocabulary and the habits: what an epidemic is, the difference between incidence and prevalence, how to draw an epidemic curve, and how to read one from real data. There is no calculus anywhere in this course. You need arithmetic, a little algebra, and a willingness to run small Python programs.

What was run, and what to trust
Every Python snippet in this chapter and in the three exercise solutions was executed, and the output in the comments is what Python printed. Definitions come from the Wikipedia articles on epidemics, incidence and epidemic curves, fetched with a tool that often returns truncated pages or model-written summaries, so treat the wording as a paraphrase, not a quotation. The daily counts for the school outbreak were read from the data file of the outbreaks R package, which says that the original report gave them only as a figure, so exact numbers differ between sources. Numbers labelled assumed or illustrative are invented to show a method and are not measurements of any real disease.

What Is an Epidemic?

The Wikipedia article on epidemics defines an epidemic as the rapid spread of disease to a large number of hosts in a given population within a short period of time. The US Centers for Disease Control give a broader version: a sudden rise in cases above what is normally expected (as summarised by the same article). Both definitions hide a comparison. An epidemic is not a fixed number of cases; it is more than usual for that place and time, so you must know what “usual” is before you can call anything an epidemic. A handful of cases of a disease that never occurs in a region may be an outbreak worth investigating, while a thousand cases of a common cold in a winter week is routine.

TermMeaningHow it is used
Outbreaka rise in cases, often local or smallthe article says it is usually restricted to smaller events, and can also apply to an epidemic
Epidemiccases well above what is expected, over a short timedepends on the baseline for that population
Endemica disease that is present at a steady, expected levelthe article gives no formal modern definition; this is the usual sense (check)
Pandemican epidemic that spreads to other countries or continents and affects a substantial number of peopledefined by geography as well as size

Incidence and Prevalence

These two words are the most commonly confused in the whole subject. Incidence counts new cases in a period. Prevalence counts existing cases at a moment. Think of a bath: incidence is the water coming in from the tap, and prevalence is the depth of the water now. The Wikipedia article on incidence describes incidence as the number of new cases in a population and prevalence as the proportion of cases in the population at a given time. It also separates two forms of incidence: the cumulative incidence (or incidence proportion), which is new cases divided by the number of people followed, and the incidence rate, which divides new cases by the total person-time at risk, so people need not be watched for equally long.

IncidencePrevalence
Countsnew casesall current cases
Timeover a period (a day, a week)at one moment (point) or over a period
Tells youhow fast the disease is arriving, the risk of catching ithow much disease there is, the burden at a time
Falls whenfewer people are being infectedpeople recover, die, or fewer are infected
Bath picturethe tapthe water level

The two are linked. In a steady state, where incidence stays roughly constant, the article gives prevalence = incidence × duration. A tap that adds 20 litres a minute to a bath that holds each litre for 6 minutes keeps 120 litres in the bath. The same arithmetic applies to people:

# Prevalence is roughly incidence x average duration (steady state). # Illustrative numbers: assumed, not taken from a real disease. population = 100_000 new_cases_per_day = 20 # incidence: assumed mean_duration_days = 6 # assumed incidence_rate = new_cases_per_day / population ill_at_any_moment = new_cases_per_day * mean_duration_days prevalence = ill_at_any_moment / population print(f"incidence: {incidence_rate * 100_000:.0f} new cases per 100,000 per day") print(f"ill at any moment: {ill_at_any_moment}") print(f"point prevalence: {prevalence:.2%}") yearly = new_cases_per_day * 365 print(f"new cases in a year: {yearly} ({yearly / population:.1%} of the population)") # incidence: 20 new cases per 100,000 per day # ill at any moment: 120 # point prevalence: 0.12% # new cases in a year: 7300 (7.3% of the population)

With 20 new cases a day and an illness lasting 6 days, 120 people are ill at any moment, a prevalence of 0.12%. Note how different the two views look: a year of that incidence infects 7.3% of the population, while only 0.12% is ill on any given day. A disease with a long duration can have a high prevalence from a modest incidence, and a short, sharp illness can sweep through a town while its prevalence stays low on most days.

A Real Outbreak: The Boarding School

In 1978 an influenza outbreak struck a boys’ boarding school in northern England. The R package documentation for the dataset (the pomp package calls it bsflu) says that 763 boys were at risk, that the index case was a boy who came back from holiday six days before the next case, and that 512 boys spent between 3 and 7 days away from class. The original report is an anonymous note in the British Medical Journal in 1978. One dataset entry words the 512 differently from the others (as the number who became ill), another sign that sources disagree in detail.

The data record, for each of 14 days, how many boys were confined to bed. That is a prevalence, not an incidence: a boy who was in bed for three days appears in three daily counts. The code below finds the peak, draws the curve in text, and then uses the relation above in reverse.

# Daily counts of boys confined to bed in a 1978 boarding-school outbreak # (read from the 'outbreaks' R package data; the original was a figure). in_bed = [3, 8, 26, 76, 225, 298, 258, 233, 189, 128, 68, 29, 14, 4] convalescent = [0, 0, 0, 0, 9, 17, 105, 162, 176, 166, 150, 85, 47, 20] boys = 763 cases = 512 # boys who were ill at some point (sources differ) peak = max(in_bed) peak_day = in_bed.index(peak) + 1 print("peak day:", peak_day, "| in bed:", peak, f"({peak / boys:.1%} of the school)") print("sum of the daily counts:", sum(in_bed)) print(f"average days in bed per case: {sum(in_bed) / cases:.2f}") print(f"attack rate: {cases / boys:.1%}") for day, n in enumerate(in_bed, start=1): print(f"day {day:2d} {n:3d} " + "#" * round(n / 6)) # peak day: 6 | in bed: 298 (39.1% of the school) # sum of the daily counts: 1559 # average days in bed per case: 3.04 # attack rate: 67.1% # day 1 3 # day 2 8 # # day 3 26 #### # day 4 76 ############# # day 5 225 ###################################### # day 6 298 ################################################## # day 7 258 ########################################### # day 8 233 ####################################### # day 9 189 ################################ # day 10 128 ##################### # day 11 68 ########### # day 12 29 ##### # day 13 14 ## # day 14 4 #

The peak came on day 6, when 298 boys, 39.1% of the school, were in bed. Adding up the 14 daily counts gives 1,559, which is more than twice the 763 boys in the school, precisely because the counts are prevalences and add each boy once for every day. Dividing by the 512 cases gives an average of 3.04 days in bed per case, which is plausible against the statement that the cases lost 3 to 7 days of school. That is the identity at work: total person-days of illness equals cases times average duration. If 512 is right, the attack rate was 67.1%, an enormous share of a closed community for a single outbreak in about two weeks. Notice the shape of the curve: a slow start (3, 8, 26), a steep climb that roughly triples each day for the first four days, a peak, and a fall that is slower than the rise. How Epidemics Spread 2 turns that steep climb into a number.

Reading an Epidemic Curve

An epidemic curve (or epi curve) is a chart of the number of new cases against the date of onset, according to the Wikipedia article. It shows the size of the outbreak, its trend over time, whether cases cluster, the likely incubation period, and the likely mode of transmission. The article names three typical shapes.

ShapeSource of exposureWhat the curve looks like
Point sourceeveryone exposed at about the same time, such as one meala sharp rise to one peak and a fall; the width of the curve matches the spread of incubation times
Continuous common sourceexposure carries on, such as contaminated water that is not fixeda rise followed by a plateau or a long, ragged tail
Propagatedperson to personsuccessive waves, each starting from the cases of the one before; the generations may show as humps

A real curve is evidence, not proof. The boarding-school curve above is a prevalence, plotted by day; a proper epi curve plots new onsets. The simulation below builds both from the same invented outbreak so you can see how they differ. It is a simple day-by-day bookkeeping model: each day, the new cases are proportional to the number of people still susceptible multiplied by the fraction of the school that is infectious. Each case stays infectious for 3 days. The transmission rate beta of 0.9 and the 3-day duration are assumed; they are not a fit to the real data. Because it divides cases into fractions of people, it is a model, not a head count. How Epidemics Spread 3 builds this idea properly as the SIR model.

# A bookkeeping simulation: how incidence (new cases per day) and # prevalence (people infectious right now) relate. All parameters are assumed. def simulate(population=763, beta=0.9, duration=3, days=28): susceptible = population - 1.0 infectious = [1.0] # one cohort per day; each stays 'duration' days rows = [] for day in range(1, days + 1): prevalence = sum(infectious[-duration:]) incidence = min(susceptible, beta * susceptible * prevalence / population) susceptible -= incidence infectious.append(incidence) rows.append((day, incidence, sum(infectious[-duration:]))) return rows rows = simulate() for day, inc, prev in rows[:14]: print(f"day {day:2d} new {inc:6.1f} infectious now {prev:6.1f}") peak_inc = max(rows, key=lambda r: r[1]) peak_prev = max(rows, key=lambda r: r[2]) print("incidence peaks on day", peak_inc[0], "| prevalence peaks on day", peak_prev[0]) print(f"total ever infected: {sum(r[1] for r in rows) + 1:.0f} of 763") # day 1 new 0.9 infectious now 1.9 # day 2 new 1.7 infectious now 3.6 # day 3 new 3.2 infectious now 5.8 # day 4 new 5.2 infectious now 10.1 # day 5 new 9.0 infectious now 17.4 # day 6 new 15.2 infectious now 29.4 # day 7 new 25.2 infectious now 49.4 # day 8 new 40.9 infectious now 81.3 # day 9 new 63.4 infectious now 129.5 # day 10 new 91.2 infectious now 195.5 # day 11 new 116.7 infectious now 271.3 # day 12 new 124.6 infectious now 332.5 # day 13 new 103.8 infectious now 345.1 # day 14 new 65.5 infectious now 293.9 # incidence peaks on day 12 | prevalence peaks on day 13 # total ever infected: 726 of 763

Incidence peaks on day 12 with about 125 new cases, and prevalence peaks a day later at about 345 people infectious, because the people infected at the peak are still infectious on the next day. This is the general pattern: prevalence lags incidence by an amount that depends on the duration of the illness. By the end about 726 of the 763 are infected in this model, whereas the real outbreak is recorded at 512, so the invented parameters overshoot; the real school may have had immune boys or a lower transmission rate (an assumption; the sources do not say).

Old Habits: Snow and the Pump

Counting by place and time is as old as the subject. In the 1854 Broad Street cholera outbreak in Soho, London, John Snow mapped the deaths and traced them to a water pump. The Wikipedia article says that within three days of the start of the major outbreak on 31 August, 127 people on or near Broad Street died, that more than 300 had died by 10 September, and that the pump handle was removed on 8 September. Total death figures differ between accounts: the page as fetched gave 420, and other accounts I remember give higher numbers (check). The lesson for this chapter is the method: Snow counted who was ill and where, and the concentration of the counts around one pump pointed to a single common source.

What Can Go Wrong When You Count

Common mistakes
Treating prevalence as incidence (adding up daily “currently ill” counts as if they were new cases, which counts each person many times); mixing the date of onset with the date of report or test (a curve by report date is shifted and lumpy, and weekends can hide cases); assuming that every case is counted (mild or symptom-free cases are often missed, so counts are a lower bound); comparing raw numbers between places of different size (use a rate, such as cases per 100,000); and calling a number an epidemic without knowing the baseline for that population.
Exercise 1

A village of 200 people (assumed) has 12 cases, each described by the first and last day of illness. For days 1 to 12, find the incidence (new cases) and the prevalence (people ill that day), check that prevalence equals the cases started so far minus those already recovered, and find the cumulative incidence, the mean duration and the peak prevalence.

๐Ÿ“„ View solution
Exercise 2

Using the 14 daily in-bed counts from the boarding school, find the day-to-day ratio for days 1 to 6, the days of the largest rise and the largest fall, the days on which more than half the peak number were in bed, and the day when most boys were in convalescence. Why does the convalescence peak come after the in-bed peak?

๐Ÿ“„ View solution
Exercise 3

Simulate a point-source outbreak: 80 guests share a dinner, each falls ill with probability 0.4 and the time to onset is between 6 and 48 hours (all assumed). Draw the epidemic curve in 6-hour bins and decide whether its shape looks like a point-source or a propagated outbreak, and why it is not a perfect bell.

๐Ÿ“„ View solution

Quick Reference

  • Epidemic: cases above what is expected for that population and time
  • Incidence: new cases in a period (cumulative incidence is a proportion; the incidence rate uses person-time)
  • Prevalence: existing cases at a moment; in a steady state, prevalence = incidence × duration
  • Epidemic curve: new cases against date of onset; shapes are point source, continuous common source and propagated
  • Prevalence lags incidence: by roughly the duration of the illness
  • Check before trusting a count: onset or report date, missed cases, rate or raw number
Coming next
How Epidemics Spread 2 is about growth and doubling: exponential growth, doubling time, the reproduction number R0, and a first Python growth simulation.