ENFR
Stat Questions / Multiple comparisons

Is that lucky streak real - or did you just look hard enough?

A real question from the wild, worked the way a biostatistician would. The trap behind it is the one that also quietly wrecks subgroup results in clinical trials.

From the wild: r/AskStatistics

Suppose you observe a person over a long period and notice that certain contexts repeatedly produce better-than-usual outcomes - at particular hours of the day, on specific weekdays, or on certain days of the month, over months of repeated events. My question isn't how to predict future outcomes. It's how statisticians decide when a pattern becomes worth taking seriously. Is there a commonly accepted way to distinguish an ordinary random fluctuation, a streak that is interesting but still expected under randomness, and a pattern that deserves further investigation?
Screenshot of a Reddit post on r/AskStatistics titled: At what point does an observed streak become statistically interesting?
The original thread on r/AskStatistics.

☝ Before you read on: how would you answer this? Pick the reply closest to yours - then see how it holds up.

The quick read

The question asks when the evidence for a lucky context gets strong enough. That's the wrong question. With this setup you're not measuring whether a pattern is real - you're measuring how hard you looked. Scanning dozens of time-contexts, re-checking as data pile up, and crowning the best one after the fact is a machine for turning pure noise into “significant” luck.

  • Look-everywhere. 24 hours + 7 weekdays + 31 days of the month = 62 contexts tested at once. At the usual 5% bar, pure noise alone hands you about 3 “significant” ones.
  • Peeking. Re-testing as data accumulate is guaranteed to eventually cross any fixed threshold, even when nothing is there.
  • Pick-the-winner. Choosing the best context after seeing the data means it will disappoint next period - plain regression to the mean.

So the honest question is not “when is the evidence strong enough?” but “is my best context stronger than what chance would throw up across 62 tries - and does it hold up on fresh data?”

Why this fools careful people too

The instinct - “collect more data until the pattern is undeniable” - feels rigorous and is exactly backwards. More data does not rescue you here, because the problem isn't the sample size of any one context; it's the number of contexts and the freedom to pick the best.

The medical version: in the ISIS-2 trial (1988, ~17,000 heart-attack patients), aspirin clearly cut deaths. To show reviewers the danger of subgroup analysis, the authors split patients by astrological birth sign - and aspirin “did not work” for those born under Gemini and Libra, while helping every other sign. Slice a real effect into enough arbitrary buckets and chance alone builds ones where it “fails.” A lucky Tuesday at 3pm and an aspirin that skips Geminis are the same mistake. More documented cases of this family live in Stat Fails.

Same shape in the clinic every day: many patients, many lab values, checked over and over. Watch enough dials long enough and some will alarm for no reason - it is part of how a sepsis alarm that cried wolf ended up ignored by the very clinicians it was built for.

What to actually do: a 5-step plan

This is the simplest disciplined approach. Each step is plain first, with the maths and numbers a click away.

1Count how many patterns you could have found

Before testing anything, list every context you scan - and include the ones you glanced at and dropped. Hours, weekdays, days of the month: 24 + 7 + 31 = 62. Look at combinations (“Friday evenings”) and you are into the hundreds.

The number that matters

Call it m, the number of tests. At a 5% threshold, the expected count of false alarms is m times 0.05. For m = 62 that is about 3 - so finding three “lucky” contexts is exactly what noise produces. Counting the tests you never formally ran (the garden of forking paths) is the hard, honest part.

2Give each context a score

For each context, turn the average outcome into a z-score: how many standard errors above “no effect” it sits. Under the null of no luck, every context's z behaves like a draw from a standard bell curve. Say your best context lands at z = 2.6 - a raw p-value near 0.005, which looks impressive against 0.05.

The formula

For a context with mean score x-bar over n observations and spread s:

$$z = \frac{\bar{x}}{s/\sqrt{n}}$$

More observations shrink the denominator, so the same real edge shows up as a bigger z. That is the grain of truth in “collect more data” - but it does nothing about the 62 looks in the next step.

Where the numbers come from: three worked examples

Three small datasets, three shapes of data - and the same recipe every time: (observed average − average expected under no luck), divided by the standard error.

For each dataset we walk the path an analyst would walk at the keyboard: look at a few raw rows, sanity-check the file as a whole, group by the context, then turn each group into one z. The highlighted rows are the numbers the rest of the page keeps reusing.

Example 1 - a continuous score with a known expectation. Six months of the asker's simulated-lottery log: 1,800 rows, one per play, with columns date, hour, weekday and score - the outcome already normalized against the game's known expectation, so “no luck” means an average score of 0, and single plays scatter with spread s = 1. Context to test: “Tuesdays”, which holds n = 260 plays averaging x-bar = +0.16. Standard error = s/√n = 1/√260 ≈ 0.062, so z = 0.16/0.062 ≈ 2.6 - the z we carry through this whole page.

What the log actually looks like - the first rows of the file:

datehourweekdayscore
2026-01-0509:00Mon−0.42
2026-01-0514:00Mon+1.13
2026-01-0610:00Tue+0.77
2026-01-0615:00Tue−0.08
2026-01-0711:00Wed+0.31
… 1,795 more rows

Micro-EDA before any pattern hunting: the mean of all 1,800 scores is +0.004 with spread 1.00 - the normalization behaves, and a broken score column would show up right here. Now group by weekday and summarise each group: how many plays it holds, their average, and that average divided by its own standard error:

weekdaynmeanz
Mon258−0.03−0.5
Tue260+0.16+2.6
Wed255+0.05+0.8
Thu259−0.11−1.8
Fri254+0.02+0.3
Sat257−0.07−1.1
Sun257+0.01+0.2

Six weekdays hover where noise lives; Tuesday pokes out at z = 2.6. Repeat the same group-and-summarise for the 24 hours and the 31 days of the month, and you hold all 62 z's - the column that steps 3 to 5 will judge.

Example 2 - win/lose outcomes. A game where each try wins with a known probability of 20% - the expectation is known by design, as in the asker's lottery simulations. 2,100 rows: timestamp, hour, win (1 or 0). Context: “the 3pm hour”, with n = 150 tries and 41 wins - a rate of 27.3% against the expected 20%. For a proportion the standard error is √(p(1−p)/n) with p the expected rate: √(0.20 × 0.80/150) ≈ 0.033, so z = (0.273 − 0.200)/0.033 ≈ 2.2. Same recipe - only the standard-error formula changes with the data type.

The raw log:

timestamphourwin
2026-02-03 15:12151
2026-02-03 18:40180
2026-02-04 11:05110
… 2,097 more rows

Micro-EDA: 424 wins out of 2,100 tries - an overall rate of 20.2%, sitting right on the designed 20%, so the game is fair overall and any luck must hide in the slices. Note the unequal group sizes: plays cluster in waking hours, so busy hours hold about 150 tries and early-morning ones far fewer - which is exactly why the summary keeps n visible. Group by hour:

hournwinsratez
09:001382618.8%−0.3
12:001423021.1%+0.3
15:001504127.3%+2.2
18:001472718.4%−0.5
21:001312821.4%+0.4
… 19 more hours

Only 15:00 leaves the pack - and the rest of this page is about deciding whether even that is anything.

Example 3 - sparse subjective ratings. The asker's second stream: 400 evening self-assessments, columns date and rating - −1 (worse than usual), 0 (as expected), +1 (better). Here no external expectation exists, so “no luck” is the person's own long-run average - subtract it first; say the centered ratings scatter with s = 0.75. Context: “the 13th of the month” - only n = 13 evenings, but they average x-bar = +0.31, and it feels like “the 13th is my day”. Standard error = 0.75/√13 ≈ 0.21, so z = 0.31/0.21 ≈ 1.5. The lesson: rare contexts have tiny n, so even a big-looking average sits comfortably inside noise - and that is before the 62-contexts correction.

The raw log:

daterating
2026-03-05+1
2026-03-060
2026-03-07−1
… 397 more rows

Micro-EDA: the 400 ratings split into 118 × (−1), 172 × 0 and 110 × (+1) - overall mean −0.02, spread s = 0.75. No designed expectation exists here, so that −0.02 is the person's own baseline: subtract it from everything before comparing contexts, otherwise a generally gloomy or cheerful rater fakes a signal in every slice. Group by day of the month:

day of monthncentered meanz
313−0.12−0.6
814+0.06+0.3
1313+0.31+1.5
2113+0.17+0.8
2713−0.23−1.1
… 26 more days

Look at what this table quietly teaches: with n around 13 per day, the centered means swing between −0.23 and +0.31 while nothing real is going on anywhere - single days of the month are simply that noisy. The 13th's +0.31 feels like a lot; z = 1.5 says a 13-evening average wanders that far routinely.

Whatever the shape of the data, the same three ingredients: an observed average, the average you would expect under no luck, and a standard error that shrinks like the square root of n. That z is what steps 3 to 5 judge.

The whole procedure in one line, runnable on any log: group rows by context; count n and average each group; subtract the no-luck average; divide by the standard error (s/√n for scores, √(p(1−p)/n) for win/lose) - and you hold one z per context. If your data can produce tables like the ones above, you can run every step on this page yourself.

3Simulate the ceiling of pure luck

This is the heart of it - and the playground below does it live. Shuffle which hour and day each outcome belongs to (this breaks any real time link but keeps the data's shape), recompute all 62 contexts, and record the best z. Repeat thousands of times, and you get the distribution of “the luckiest of 62 contexts under pure noise.” Compare your real best to it.

The numbers, and the quick shortcut

For 62 contexts, the best-of-62 z under pure noise has a median near 2.3 and a 95th percentile near 3.1. Your 2.6 sits around the 75th percentile - noise matches or beats it roughly one run in four. Not interesting. The “worth a look” line is about z = 3.1. Shortcut without simulating: Bonferroni asks each context to clear 0.05 divided by 62, about 0.0008 (z above 3.2) - your 2.6 fails. If you would rather screen many candidates than make one hard claim, control the false discovery rate (Benjamini-Hochberg) instead. Medical scale-up: genome studies test about a million sites and use a threshold of 5 in 100 million.

Is this a bootstrap?

A close cousin, but no. The bootstrap resamples your data with replacement to ask “how much would my estimate wobble in a fresh sample from the same world?” - it measures the uncertainty around a value. What step 3 does is a permutation test: shuffle the time labels without replacement to build the world where luck definitely does not exist, then see where your real result falls in it. And taking the best of all 62 contexts in every shuffled run is the classic max-T scheme (Westfall-Young) - it handles multiplicity more honestly than Bonferroni, because the shuffles automatically respect the overlap between contexts (the same play sits in both “Tuesday” and “3pm”), where Bonferroni over-corrects.

And yes - the verdict needs no bell-curve table at all: you simply check whether your real best lands in the top 5% tail of the shuffled distribution (one-sided, because “lucky” is a directional claim). One catch stops you from dropping the z-score entirely: contexts come in very different sizes, and raw averages are not comparable across them. Take the two contexts from step 2. “Tuesdays” holds n = 260 plays, so its average wobbles with a standard error of about 0.062 - under pure noise it stays roughly within ±0.12 of zero (two standard errors). “The 13th of the month” holds only n = 13 evenings, standard error about 0.21 - an average roughly 3.4 times noisier, which the same pure chance routinely swings out to ±0.4. Rank contexts by raw average and the rare ones win almost every shuffled run, simply because they are noisier - your 260-play Tuesdays can never out-wobble a 13-evening context, no matter how real their edge is. Dividing each average by its own standard error (that is all the z-score is) puts every context on one ruler: one z unit now costs the same amount of surprise everywhere, and the maximum becomes a fair contest. Any statistic with that property works - including each context's own permutation p-value (the min-p variant).

Full disclosure: the playground below draws independent bell-curve z's rather than shuffling a real dataset - the right simplification for a lesson. On your own data, the real permutation is strictly better: it inherits your data's odd distributions and the dependence between contexts for free.

4Confirm on data you didn't use to find it

The big one, and the line between “interesting” and “real.” The pattern you spotted is a hypothesis, not evidence. Freeze the surviving context as one pre-named claim, then test only that context on the second half of your history - or, better, on new observations going forward - at a plain 5%.

Why this fixes almost everything

At the confirmation stage there is no multiplicity - you test one thing you named in advance, so a plain 5% is honest again. This is also what defeats peeking and regression to the mean in one move: a fluke found by looking everywhere will not repeat on data it never touched. If it replicates, it earns further study; if it evaporates, it was noise all along. Pre-registering the hypothesis, or an N-of-1 design, formalises the same idea.

5Ask how big, not just whether

Report the size of the edge and its confidence interval, not only a p-value. Over months of data even a microscopic effect becomes “significant” - so significant and worth acting on are not the same thing.

Three roads, one verdict. The simulation puts z = 2.6 around the 75th percentile of pure noise; Bonferroni demands z above 3.2; and expecting three false alarms among 62 contexts means finding a few “lucky” ones is the default, not a discovery. When independent methods agree this cleanly, trust the agreement.

Try it: the look-everywhere simulator

Set how many contexts you scan, how many observations each holds, and how strong your best one looks. The chart is 4,000 runs of pure noise - the distribution of the luckiest context when nothing real is going on. See where your result lands.

A subtlety worth noticing: push observations up and, with the average edge held fixed, the result rightly gets more impressive - a real effect can clear even the raised bar, given enough data. The catch is that a noise-born pattern won't hold its average: it melts toward zero as observations pile up. Prolonging the same exploration never settles it - which is why fresh data (step 4) is the decider.

The three buckets, answered

Ordinary fluctuationthe best context sits inside the noise range (fails step 3).
Interesting but expectedclears the exploration but does not replicate on fresh data (fails step 4). This is the trap the asker is in.
Deserves investigationclears the simulated ceiling AND replicates out of sample AND the effect isn't microscopic.
This is the simplest disciplined approach. Depending on how deep your statistics go, you can push further - permutation tests across the whole search, false-discovery-rate control, Bayesian hierarchical shrinkage (regression to the mean, done on purpose), always-valid confidence sequences that let you peek legitimately, and sequential designs. And for live monitoring - watching a stream as it arrives rather than hunting patterns after the fact - statistical process control has ready-made rules of thumb, like the Western Electric “seven points on one side” rule. More on all of those in a later Stat Question.

Two of those get built rather than promised in our Monte Carlo series - sequential designs, calibrated by simulation, where the very move this page runs - simulate the null, take the quantile of the maximum - comes back to fix the peeking problem for real.

Frequently asked

When does a streak become statistically significant?

There is no fixed amount of data that turns a streak into a real signal. If you scan many contexts (hours, weekdays, days of the month), pure chance guarantees a few will look significant. Significance for a hand-picked context is meaningless until you correct for how many patterns you tested and confirm the winner on data you did not use to find it.

What is the multiple comparisons problem?

When you run many tests at once, each has its own chance of a false positive. Testing 62 contexts at the 5 percent level produces about three significant results from pure noise. Corrections such as Bonferroni or the false discovery rate keep the overall false-positive rate under control.

How do you tell a real pattern from random noise?

Count how many patterns you tested, shrink your threshold or simulate the best result pure noise would produce across that many tries, then confirm any surviving pattern on fresh data. A pattern that clears the noise ceiling and replicates out of sample deserves investigation; one that does not is regression to the mean.

Sources

Traps like this one are a whole section of Stat Exam Pro - exam-style questions with worked answers, in English and French.

Get it on iPhone