Skip to content
C.W.K.
Stream
Lesson 01 of 04 · published

How a Number Becomes Meaning Without Becoming a Command

~13 min · percentile, descriptive, context, design

Level 0Raw Ore
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Percentile context is how a number becomes meaning without becoming advice."

Three ways to present the same fact

Suppose the cyclically adjusted price-to-earnings ratio for the US market reads 43.19. You have three choices about how to put that on a screen, and they are not variations of one design — they are three different products.

Present the raw number. "CAPE: 43.19." This is honest and nearly useless. A reader who does not already know the historical range of that series learns nothing; a reader who does did not need your dashboard. Raw numbers without context are not neutral, they are just unhelpful, and unhelpfulness has its own failure mode: the reader supplies context from memory, badly.

Present a threshold. "CAPE: 43.19 ⚠️ DANGER ZONE." Now the number means something, and the meaning was manufactured by you. Where did 40 come from? Who decided the color? A threshold is a judgement wearing a fact's clothes, and worse, it is a judgement designed to produce a feeling — which is precisely the mechanism this product exists to refuse.

Present position within its own history. "CAPE: 43.19 — 99.7th percentile of its own recorded history, 145.6 years, first reading 1881." The number now means something, and every part of the meaning is checkable. The reader knows exactly what claim is being made and exactly how much history stands behind it. Nothing has been decided for them.

Context, not thresholds. Both a threshold and a percentile turn a number into meaning. The difference is who supplied the meaning: a threshold supplies yours, a percentile supplies the series' own. One is an opinion rendered as a color; the other is a measurement you can go and check.

Why this is not merely a softer threshold

It would be easy to argue that a 99.7th percentile is alarming, so this is a threshold with extra steps. It isn't, and the difference shows up in three places.

First, it is falsifiable. If the history is short, or starts at an unrepresentative moment, the reader can see that and discount accordingly — which they can never do with a hand-picked threshold. Second, it moves. A percentile updates as history accumulates, without anyone editing a constant. Third, and most important, it does not carry a direction. "Near the top of its own history" is compatible with many different next moves, and the surface does not pretend otherwise.

The honest bit: percentiles have their own trap

A percentile is only as good as the window it was measured over, and this app's windows are wildly unequal — some series carry a century and a half, others carry three years, because a data licence trims them. Printing two percentiles side by side in identical type asserts that they are comparable claims. They are not.

That is the entire subject of a later track, and it is the reason percentile is treated here as a mechanism rather than as a solution. The mechanism is right. Making it honest takes more work than the mechanism itself.

The trap this lesson sets up. Everything above is true and still incomplete. A percentile printed without its window is a claim wearing a measurement's clothes, exactly like the threshold it replaced — just harder to notice, because it looks so much more rigorous.

Code

Percentile within a series' own history — inclusive rank, and a minimum·python
PERCENTILE_MIN_POINTS = 20  # below this, a percentile is noise


def percentile(series_values: list[float],
               current: float) -> float | None:
    """Percentile of `current` within its own history (inclusive rank).
    None until the series has enough points to mean anything. Public:
    the ticker read model applies the same bar."""
    # Read what that first sentence is NOT saying: None, rather than
    # zero or 50. An honest absence beats a confident number computed
    # from four observations -- and a caller that renders None as 0
    # has quietly undone the whole guard.
    if len(series_values) < PERCENTILE_MIN_POINTS:
        return None
    below = sum(1 for v in series_values if v <= current)
    return round(100.0 * below / len(series_values), 1)


# A live reading, US CAPE:
#   value 43.19, percentile 99.7, window 145.6 years, first row 1881
#
# Every one of those four numbers is part of the claim.
# Drop any one of them and the remaining three overstate what is known.

External links

Exercise

Find a number in a product you use that is presented with a threshold — a colored badge, a warning icon, a 'high/normal/low' label. Rewrite its presentation as a percentile statement instead: the value, the reference series, the window, and the position. Then ask which version you would rather defend to someone who disagreed with it, and why.
Hint
The tell for a manufactured threshold is that you cannot find where the boundary came from. If the docs do not say why the line sits at that value, the line is somebody's taste rendered as a color.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.