How a match is computed
Overview
Section titled “Overview”LookAlike scores every continental US census tract by how closely its observable characteristics resemble a brand’s “archetype” — the average profile of the neighborhoods where the brand already has stores. The method is transparent and reproducible; this page walks through every step, from raw data to the 0–100 similarity percentile you see on the map.
The data: 21 features in 6 thematic groups
Section titled “The data: 21 features in 6 thematic groups”Every tract is described by 21 observable features, organized into 6 thematic groups. This grouping is central to the method: it prevents correlated features (like income, per-capita income, home value, and rent, which all correlate r > 0.7) from being counted as separate evidence and dominating the score.
1. Income, wealth & housing cost (5 features)
Section titled “1. Income, wealth & housing cost (5 features)”- Median household income ($)
- Per-capita income ($)
- Median home value ($)
- Median gross rent ($/month)
- Poverty rate (%)
2. Education (1 feature)
Section titled “2. Education (1 feature)”- Bachelor’s degree or higher (%)
3. Density & transportation (4 features)
Section titled “3. Density & transportation (4 features)”- Population density (people/km²)
- Households without a vehicle (%)
- Walk/bike/transit commute (%)
- Renter-occupied housing (%)
4. Age & household type (3 features)
Section titled “4. Age & household type (3 features)”- Median age (years)
- Average household size (people)
- Households with children (%)
5. Race & ethnicity (3 features)
Section titled “5. Race & ethnicity (3 features)”- White non-Hispanic (%)
- Hispanic/Latino (%)
- Asian non-Hispanic (%)
6. Retail & dining context (5 features)
Section titled “6. Retail & dining context (5 features)”From Overture Maps Places, aggregated per km²:
- All points of interest
- Grocery stores
- Restaurants
- Cafés & coffee
- Shopping & apparel
These features are drawn from the US Census American Community Survey (ACS 2023, 5-year estimates), Census TIGER/Line tract boundaries, and Overture Maps Places. See data sources for full provenance.
Building the archetype
Section titled “Building the archetype”For a brand, the archetype is the average of the features across every unique census tract the brand occupies — one observation per tract, so co-located facilities (like a Costco gas station and warehouse at the same location) are counted only once.
For the 11 built-in brands:
- Trader Joe’s (603 stores in 597 unique tracts)
- Whole Foods Market (525 stores in 524 tracts)
- Sprouts Farmers Market (448 stores in 448 tracts)
- Chipotle Mexican Grill (3,068 stores in 2,998 tracts)
- Starbucks (10,984 stores in 9,119 tracts)
- Costco Wholesale (1,225 stores in 618 tracts)
- Dollar General (11,136 stores in 10,299 tracts)
- Tractor Supply Co. (1,554 stores in 1,550 tracts)
- Sweetgreen (167 stores in 166 tracts)
- H Mart (96 stores in 96 tracts)
- Cracker Barrel (639 stores in 634 tracts)
These counts are OpenStreetMap-derived, after two cleaning steps: co-located sub-features are collapsed on a 150 m grid, and each surviving point is assigned to the nearest continental-US tract within 1 km, with anything farther dropped (removing Canada and Mexico bounding-box slop and geocode errors). They reflect OpenStreetMap coverage, which is strong for large chains but not exhaustive.
For a custom upload, the archetype is computed the same way from your lat/lon points, with optional weighting by a performance column (revenue, sales, etc.) so the profile leans toward your best locations.
Clipping extremes
Section titled “Clipping extremes”Before any scaling, all feature values are clipped to the national 1st–99th percentile (computed across all ~83,000 CONUS tracts). This prevents a handful of extreme neighborhoods — tracts with very high incomes (top-coded in census data), ultra-dense urban cores, or rural sparsity — from distorting the scale. The clipping is applied per feature, so each feature uses its own p1 and p99 bounds.
Computing distance
Section titled “Computing distance”For each tract and each feature, the method computes a standardized deviation from the archetype:
z = (clipped_value − archetype_mean) / sigma_effwhere sigma_eff is the effective standard deviation with a per-feature variance floor:
sigma_eff = sqrt(sigma_brand² + (λ × sigma_national)²)with floor parameter λ = 0.5.
This is a variance floor, not a blend toward the national spread. It raises the effective spread of a feature the brand is artificially tight on — so that one feature cannot dominate the distance — and it never reduces the spread of a feature the brand is already wider on than the nation. The quantity λ × sigma_national is the smallest effective spread any feature can have; sigma_brand above it is passed through unchanged.
Group averaging
Section titled “Group averaging”Each feature’s squared standardized deviation z² is averaged within its thematic group:
group_distance = mean(z² for all features in the group)Missing features (e.g., a tract with no renter-occupied housing data) are skipped; the mean is taken over available features only.
Then distances are averaged across the 6 groups with equal weight:
distance = sqrt(mean(group_distance for all 6 groups))A tract must have valid data in at least 4 of the 6 groups to be scored; otherwise it receives a missing value.
This within-group-then-across-group structure ensures each theme (income, density, household, race, education, retail context) counts once, not as many times as it has correlated features.
Distance to percentile
Section titled “Distance to percentile”The distance computed above is turned into a 0–100 similarity percentile, where 100 = the closest tract(s) to the archetype and 0 = the most distant:
rank = percentile rank of distance (ascending; ties get average rank)similarity = 100 × (1 − (rank − 0.5) / n_tracts)For example:
- A tract with the lowest distance ranks 1st and scores 100 (or close to it, after tie-breaking).
- A tract with the median distance ranks ~41,000th (out of ~83,000) and scores ~50.
- Ties are broken using average ranks, so multiple tracts with identical distance values receive the same percentile.
Worked example
Section titled “Worked example”Suppose a brand’s archetype has:
- Median household income: $100,000
- sigma_eff for income: $10,000
A candidate tract has a (clipped) median household income of $105,000.
z = (105,000 − 100,000) / 10,000 = 0.5contrib = 0.5² = 0.25This tract is 0.5 standard deviations above the archetype’s income — a modest match on that feature. The contribution (0.25) is averaged into the “Income, wealth & housing cost” group with the other features in that group, and the resulting group distance is combined with the other five groups to produce the final distance, which is then percentile-ranked.
Absolute-fit bands
Section titled “Absolute-fit bands”The percentile answers “how does this tract rank against every other tract, for this brand?” — but by construction a brand’s best tract always sits near the 100th percentile, even if that best tract is only a mediocre absolute match. To answer “how good is this match in absolute terms?”, the detail panel also shows an absolute-fit band: Strong, Moderate, or Weak.
The band compares the tract’s raw grouped distance d (under equal weighting) against the distribution of the brand’s own occupied-tract distances. The pipeline records four quantiles of that distribution per brand (dist_ref: p50, p75, p90, p95), and the band is:
- Strong —
d ≤ p75(as close as the brand’s own typical store neighborhood). - Moderate —
d ≤ p95(within the range the brand already operates in). - Weak — farther than that.
- No band — when the distance or the reference quantiles are missing (an honest blank rather than a guess).
Unlike the percentile, the band is grounded in the brand’s real footprint, so it does not inflate every brand’s top tract to “Strong.” For a custom upload, the browser computes the same quantiles from your own uploaded locations’ distances, so the band means the same thing for your footprint. The band is still descriptive resemblance distance, not a viability score.
Validation: k-fold archetype coherence
Section titled “Validation: k-fold archetype coherence”To check whether the resemblance score actually captures anything meaningful, the pipeline uses out-of-sample k-fold validation. For each of 5 folds:
- Hold out a deterministic ~20% of the brand’s store locations.
- Rebuild the archetype using only the remaining ~80% of stores.
- Score every tract with this reduced archetype.
- Record the percentile rank of the held-out stores’ neighborhoods.
A high median held-out percentile means the archetype is coherent — the method re-finds the brand’s real neighborhoods even without seeing them. A low percentile means the brand’s locations are scattered across many neighborhood types.
The folds are blocked by county: whole counties are assigned to a fold together, rather than individual stores being split at random. This matters because a held-out store’s same-county neighbors have nearly identical demographics; if they stayed in training, the archetype would “recognize” the held-out neighborhood partly because it had already seen its next-door tracts, inflating the coherence number. County blocking removes that same-county leakage, so the number reported is honest.
Coherence scores (median held-out percentile, county-blocked)
Section titled “Coherence scores (median held-out percentile, county-blocked)”| Brand | Coherence | Interpretation |
|---|---|---|
| Whole Foods | 83rd | Distinctive archetype; high signal. |
| Trader Joe’s | 77th | Distinctive. |
| Sprouts | 77th | Distinctive. |
| Costco | 67th | Diffuse footprint. |
| Chipotle | 63rd | Diffuse footprint. |
| Starbucks | 57th | Ubiquitous; weak signal (operates in many neighborhood types). |
| Dollar General | 77th | Distinctive rural/small-town signal. |
| Tractor Supply Co. | 75th | Distinctive rural/exurban signal. |
| Sweetgreen | 90th | Very distinctive urban signal. |
| H Mart | 84th | Distinctive metro-community signal. |
| Cracker Barrel | 73rd | Moderate. |
County blocking barely moved the original six-brand numbers from the earlier stride-based folds. That is itself an honest result: most of these chains span hundreds to over a thousand counties, so holding out whole counties still leaves demographically similar training data. Same-county autocorrelation was not heavily inflating coherence for these multi-metro brands. A brand concentrated in a handful of counties would show a larger drop.
The app displays each brand’s coherence score so you know how much weight to place on resemblance for each brand. Starbucks’ low coherence doesn’t mean the tool is broken; it reflects reality — Starbucks is strategically designed to be everywhere.
Explainability: per-feature contributions
Section titled “Explainability: per-feature contributions”When you click a tract in the detail panel, the app computes which features drive the match. It reports:
- “Closest features” — the features where the tract most closely matches the archetype (smallest z²).
- “Where it differs — check these” — the features where the tract deviates most (largest z²).
Each feature shows the tract’s value, the archetype’s mean, and the standardized deviation (z). These match the Python pipeline exactly — the browser scorer is a faithful re-implementation of pipeline/build_scores.py and is validated by a consistency test against all built-in brands.
How group weighting works (tuning scenario assumptions)
Section titled “How group weighting works (tuning scenario assumptions)”The detail panel includes sliders to adjust each group’s weight (0–2×). The weights are applied during group averaging:
distance = sqrt(weighted_mean(group_distances))where each group’s contribution is scaled by its weight. A weight of 0 turns off the group entirely; the affected features never appear in explanations. A weight > 1 amplifies that theme.
Preset scenarios (Balanced, Affluence-led, Urbanism-led, Community-led) adjust all six group weights as shortcuts.
Each group also has an advanced per-feature layer: you can set a weight on a single feature within a group. The effective weight of a feature is its group’s weight multiplied by its per-feature weight, and the within-group aggregation becomes a weighted mean of the squared deviations. With every per-feature weight left at its default of 1, the scores are exactly the equal-weight scores above, so the advanced layer only changes results when you deliberately move a per-feature slider.
Custom uploads: the scoring stays the same
Section titled “Custom uploads: the scoring stays the same”When you upload your own store data, the scoring math is identical to the built-in brands:
- Each point is assigned to the nearest tract centroid. This is an approximation of the pipeline’s step, which assigns each point to the tract polygon that contains it (in an equal-area projection). The two agree for almost every point and disagree only for a point that sits inside one large tract but nearer a small neighboring tract’s centroid. The archetype-mean effect of the rare disagreement is negligible; the scoring after assignment is exactly the same formula.
- The archetype is computed as the mean over unique occupied tracts.
- If you provide a performance column (revenue, sales, etc.), the archetype is a weighted mean, leaning toward your higher-performing stores.
- If you provide a status column (closed, failed, low), a second “failure” archetype is built, and tracts are scored as:
score = resemblance_to_winners − (penalty strength) × resemblance_to_failures
- The result is re-expressed as a 0–100 percentile, just like the built-in brands, and an absolute-fit band is computed from your own uploaded locations’ distances.
Winners are shown as colored dots; failures as red-ringed dots. The score is still descriptive — the labels are your own ground truth, not a sales prediction model. A custom upload can also be compared against a built-in brand — the compare view uses the upload’s plain resemblance percentiles, not the avoid-failures score.
Browser scoring: client-side re-implementation
Section titled “Browser scoring: client-side re-implementation”The entire scoring pipeline is re-implemented in JavaScript (web/src/lib/scoring.ts) so that:
- The detail panel can show per-feature explanations consistent with the map.
- Custom uploads compute the archetype and scores in the browser. In the authenticated product, the source file, normalized rows, metric definition, tract assignments, and analysis lineage are persisted privately so teams can return to a reproducible version.
The browser scorer reproduces the Python pipeline’s results to >99.9% accuracy across all built-in brands (within 1 percentile point for >99.9% of tracts; max difference ≤ 2 points). This is verified by web/src/lib/consistency.test.ts at each build.
Future methodology work
Section titled “Future methodology work”Several of the design choices above are deliberate simplifications with known trade-offs. Each of the following would change scores and so needs its own validation before shipping; they are recorded here as candidate improvements, not defects:
- Store-count-weighted archetype. Weight each occupied tract by how many of the brand’s stores it holds, so the profile reflects where store volume concentrates rather than only which neighborhood types the brand occupies. The store-to-tract assignments already exist; this is a weighting change (see the equal-weighting note).
- Per-brand or gentler winsorization. Clip each brand against its own distribution, or clip more gently, so a premium brand’s above-p99 archetype is not flattened (see the clipping ceiling note).
- Sample-size-aware regularization. Scale the variance-floor λ by footprint size, applying a stronger floor to brands with few occupied tracts whose own spread is estimated less reliably (see the fixed-floor note).
- Multi-archetype clustering for diffuse brands. For a brand whose stores span very different neighborhood types (low coherence, like Starbucks), a single mean archetype is an “average neighborhood” that may match no real operating pattern. Clustering the occupied tracts into two or three archetypes and scoring against the nearest would describe such brands more faithfully.
- Trajectory: “becoming like the archetype.” Add a second ACS vintage and show resemblance drift per tract, describing observed demographic change (not future sales). This is deferred because ACS 2018 5-year uses 2010 tract boundaries while 2023 uses 2020 boundaries; an honest trend signal first needs a 2010-to-2020 tract crosswalk (interpolation weights), which is a substantial project of its own.
Summary: what the score means
Section titled “Summary: what the score means”A tract’s similarity percentile reflects how closely its observable census demographics and commercial context resemble the brand’s archetype. High scores mean “looks like the neighborhoods where this brand already is.” They do not predict whether a store would be profitable, generate foot traffic, or succeed in that location. Use the resemblance score as a triage tool — a way to narrow a regional search from tens of thousands of tracts to hundreds of strong candidates — and combine it with local knowledge, real-estate expertise, and on-the-ground scouting.