# Normalize counts into per-capita rates

Paste label, count and population rows and get population-adjusted rates per capita, per 1,000, per 100,000 or a custom base.

## Run it

- **CLI:** `gizza tool per-capita-normalizer "region,cases,population
Northbridge,120,400000
Eastvale,45,150000
Westport,18,900000"`
- **Web:** https://gizza.ai/tools/per-capita-normalizer/
- **Agents:** machine-readable descriptor (parameters JSON Schema) at https://gizza.ai/tools/per-capita-normalizer/tool.json

## Inputs

- `data` — Rows (label, count, population) _(field)_
- `delimiter` — Delimiter _(field)_
- `header` — Header row _(field)_
- `per` — Rate base _(field)_
- `custom_per` — Custom base (only when Rate base = Custom) _(field)_
- `population_unit` — Population column is in _(field)_
- `decimals` — Decimal places _(field)_
- `sort` — Sort _(field)_
- `unstable_below` — Flag rows with a count below (0 = off) _(field)_
- `output` — Output format _(field)_

## Output

- Normalized rate table (text)

## Query parameters

Open the tool pre-filled and auto-run via URL:

- `data` — Rows (label, count, population)
- `delimiter` — Delimiter
- `header` — Header row
- `per` — Rate base
- `custom_per` — Custom base (only when Rate base = Custom)
- `population_unit` — Population column is in
- `decimals` — Decimal places
- `sort` — Sort
- `unstable_below` — Flag rows with a count below (0 = off)
- `output` — Output format

Example: `https://gizza.ai/tools/per-capita-normalizer/?data=region%2Ccases%2Cpopulation%0ANorthbridge%2C120%2C400000%0AEastvale%2C45%2C150000%0AWestport%2C18%2C900000&delimiter=auto&header=auto&per=100000&custom_per=500&population_unit=ones&decimals=2&sort=rate_desc&unstable_below=20&output=table`

---

## About this tool

Raw counts lie when the groups behind them are different sizes. A city of two million will report more cases, crimes, complaints or sign-ups than a town of forty thousand even when the underlying risk is identical. Per Capita Normalizer divides each count by its own population and rescales it to a shared reporting base, so the numbers become comparable.

Paste one `label, count, population` row per line, pick a base — per person, per 1,000, per 10,000, per 100,000 (the public-health convention), per 1,000,000, or a custom base such as "per 500 residents" — and the tool returns a ranked table with:

- **rate** — the count divided by population, scaled to your base;
- **index** — that rate against the combined rate of every row you pasted, where `1.00` is the overall average, `2.00` is twice the average and `0.50` is half;
- **flag** — `unstable` when a row's raw count is below your small-count threshold (20 by default), the usual warning that a rate built on a handful of events swings wildly.

Everything runs locally in your browser; nothing is uploaded.

### Worked example

Input (comma-delimited, first row is a header):

```text
region,cases,population
Northbridge,120,400000
Eastvale,45,150000
Westport,18,900000
```

Output at `per 100,000` with 2 decimals:

```text
per 100000 · rows: 3 · total count: 183 · total population: 1450000 · overall rate: 12.62 · flagged unstable (count < 20): 1

rank	label	count	population	rate_per_100000	index	flag
1	Eastvale	45	150000	30.00	2.38	ok
2	Northbridge	120	400000	30.00	2.38	ok
3	Westport	18	900000	2.00	0.16	unstable
```

Northbridge has by far the biggest raw count, but Eastvale — under half its size — carries the exact same rate of 30 per 100,000. Westport looks busy at 18 cases until you notice it is spread across 900,000 people, giving a rate 84% below the overall average, and its 18 events sit under the 20-event threshold, so it is flagged as unstable.

### Reading population tables that aren't in people

International statistics often publish population in thousands or millions. Set **Population column is in** to `Thousands` or `Millions` and the tool multiplies the column for you, instead of forcing you to expand `8,175` into `8175000` by hand.

### Limits and conventions

- Up to 10,000 rows per run; each row needs a count of zero or more and a population greater than zero.
- The last two fields on a row are read as count and population, so labels may contain the delimiter (`Springfield, IL,10,1000` works).
- Numbers may include `$`, `£`, `€`, thousands separators and underscores — but with the comma delimiter, a value written `8,175,133` splits into separate fields, so use tabs (or paste straight from a spreadsheet) for comma-separated numbers.
- Counts and population must describe the same period. Mixing a full year of events with a mid-year population is fine; mixing three years of events with one year of population inflates the rate.
- These are **crude** rates: they do not adjust for age or any other structure in the population. A retirement town and a university town can differ on crude rates while having identical risk at every age.

## FAQ

<details>
<summary>Why per 100,000 rather than a percentage?</summary>

A percentage is just a rate per 100. For events that are rare relative to the population — disease cases, homicides, fatal accidents — a percentage collapses into a string of zeros (`0.003%`), while per 100,000 gives a readable `3.0`. Pick the base that puts your typical value in the 1–1000 range: per 1,000 for births, deaths or defects, per 100,000 for rarer events, per person for things everybody does several times.

</details>

<details>
<summary>What does the index column mean?</summary>

It is each row's rate divided by the overall rate of everything you pasted, so `1.00` means "exactly the pooled average". A row at `2.38` is 138% above average; a row at `0.16` is 84% below. It saves you a second pass of mental arithmetic when comparing a region against the group instead of against the top row.

</details>

<details>
<summary>Why is a row flagged unstable?</summary>

Rates built on very few events are noisy: with 3 events, one more or fewer moves the rate by a third. Statistical agencies commonly suppress or asterisk rates under about 20 events for that reason, so this tool flags them by default. Change the threshold in **Flag rows with a count below**, or set it to `0` to turn flagging off entirely — every row then reads `ok`.

</details>

<details>
<summary>Can I paste straight from a spreadsheet?</summary>

Yes. Copy the three columns and leave the delimiter on Auto (or choose Tab). Auto-detect also handles semicolon and pipe files, and falls back to whitespace when a row contains no separator at all. Header rows are detected automatically when the count or population cell isn't a number, and you can force the choice with the Header row control.

</details>

<details>
<summary>What if my rows have no label?</summary>

A two-field row is read as `count, population` and labelled `row 1`, `row 2`, and so on, so you can paste two bare columns. Single-row input works too — the index is then `1.00`, since the one row is the whole population.

</details>

<details>
<summary>Does it do age-standardized rates?</summary>

No. It computes crude rates only. Age standardization needs an external standard population broken into age bands and the same age breakdown for your own data, which is a different input shape. If you need age-adjusted comparisons, compute the rate per age band here and weight them yourself.

</details>

<details>
<summary>How do I get the result into a report?</summary>

Choose the output format: `CSV` for a spreadsheet (it starts with a small metric block, then the row table), `Markdown` for a documentation or ticket table, or `JSON` for scripts and dashboards. The text format adds a fixed-width rate chart for a quick visual scan, and every format can be copied with one click.

</details>

## Related tools

- [Bitwise Calculator](https://gizza.ai/tools/bitwise-calculator/): Bitwise calculator: AND, OR, XOR, NOT, shifts, rotates and popcount on 8–64-bit integers in binary, hex, octal or decimal. Free, private, in your browser.
- [Bollinger Bands calculator](https://gizza.ai/tools/bollinger-bands/): Compute Bollinger Bands (SMA plus/minus standard deviations) for a price series, plus %B and bandwidth, in your browser. Free, private, no upload.
- [Boxplot Chart Generator](https://gizza.ai/tools/boxplot-chart/): Paste values or grouped CSV data and render a box-and-whisker SVG with quartiles, whiskers, mean markers, notches, outliers, and summary stats.
- [CAGR Calculator](https://gizza.ai/tools/cagr-calculator/): Paste a series of values and get the compound annual growth rate, total growth, the multiple, doubling time and a period-by-period growth table.
- [Free Online Calculator](https://gizza.ai/tools/calculator/): Evaluate any arithmetic expression instantly in your browser. Supports +, −, ×, ÷, parentheses and functions. No sign-up, runs offline.
