LottoPickle is a data science platform built on top of a publicly available lottery dataset. Each view in the app applies a distinct analytical technique — from descriptive statistics and time series analysis to combinatorics and probabilistic modeling. This page documents the methodology, implementation decisions, and underlying concepts.
All analysis is performed on historical Powerball and Mega Millions draw data sourced from the New York State government open data portal (data.ny.gov). The dataset is publicly available, machine-readable, and updated after each draw.
Data is fetched via the SODA (Socrata Open Data API) REST interface, requesting up to 5,000 records ordered chronologically. Each record contains a draw date and space-delimited winning numbers. Parsing, filtering, and normalization happen client-side in the browser.
Each tab in the app applies a distinct data science concept to the same underlying dataset, demonstrating how a single data source can be interrogated from multiple analytical angles.
Every lottery number is assigned a draw count across the full historical dataset. By plotting these counts as a bar chart ordered by number, we reveal the raw empirical distribution — a foundational step in any statistical exploration. Color encoding (hot/warm/neutral/cold) maps percentile rank to visual temperature, making outliers immediately apparent without needing to read axis values.
The heatmap maps the same frequency data onto a spatial grid, using color intensity as the data channel. The color scale interpolates through indigo → purple → green, creating perceptually uniform transitions. This technique — common in genomics, financial analysis, and web analytics — lets viewers scan a two-dimensional structure and identify clusters of high or low activity instantly.
Cumulative frequency curves are computed for individual numbers across 2,800+ chronologically ordered draws. A single-pass O(n·k) algorithm builds the running totals efficiently. The resulting multi-line chart reveals convergence behavior — numbers tend toward the mean frequency over time, a classic demonstration of the Law of Large Numbers. Users can inject arbitrary numbers to compare trajectories.
The distribution tab answers a meta-question: how are the frequencies themselves distributed? A histogram of frequencies exposes whether the draw process produces a normal distribution (expected under true randomness) or a skewed one. Four statistics are computed: mean, median, standard deviation, and Fisher-Pearson skewness coefficient. Deviation from symmetry (|skewness| > 0.5) is flagged as noteworthy.
Each 5-number draw contains C(5,2) = 10 unique pairs. Across 2,800+ draws, this yields ~28,000 pair observations. A hash map accumulates co-occurrence counts in O(n) time. The result is a frequency table of number pairs — a form of association analysis. Users can query any number to retrieve its top co-occurring partners, a technique directly analogous to market basket analysis in retail data science.
Gap analysis tracks the number of draws since each ball last appeared — its "gap" or recency score. Numbers are sorted by gap descending to surface the most overdue. This is a form of recency weighting, a technique used in recommendation systems (RFM analysis), inventory management, and time-decay models. The visual gap bar provides an immediate proportional comparison.
The number picker implements three sampling strategies: (1) weighted sampling where each number appears in the pool proportionally to its historical frequency — a basic Monte Carlo approach; (2) overdue-biased sampling from the top 40% most-gapped numbers; (3) uniform random sampling as a baseline. These represent the spectrum from data-informed to purely stochastic selection.
Raw draw data is presented in reverse-chronological order with frequency-aware ball coloring, grounding all analysis in the actual source records. Each ball is colored by its overall temperature — a cross-reference between historical context and aggregate statistics. This data provenance view is essential in any analytical workflow: always trace aggregate conclusions back to the raw data.
Built entirely client-side — no backend required. All computation runs in the browser using standard React patterns.
All statistical computation happens in the browser via React useMemo hooks. For a dataset of ~5,000 rows and up to 70 numbers, this is well within browser capabilities and eliminates the need for a backend API — reducing infrastructure cost and latency to zero.
Derived data (freq, lastSeen, pairs, distribution) is computed once per data+filter change using useMemo with precise dependency arrays. This prevents O(n) recomputation on every render. The pairs computation — O(10n) — runs in a single pass rather than nested lookups.
Free views (Frequency, Hot/Cold, Heatmap, History) are chosen to showcase the depth of data without requiring payment. Pro views (Trends, Distribution, Pairs, Gap Analysis, Picker) represent deeper analytical capability and personalized features, aligning paywall placement with perceived value.
Filtering by 1, 3, or 5 years is implemented as a useMemo over the raw draws array — all downstream computations automatically recompute from the filtered slice. This architecture means adding new filter dimensions requires zero changes to the visualization components.
All eight analytical views are live in the app — free to explore.
Open LottoPickle