Adverse childhood experiences and adult health
A verification companion to the US Atlas of Childhood Experiences, written for BRFSS data experts: every mapping, recode, formula, and threshold in the pipeline, with worked examples computed live from the same code and database that serve the Explore and Compare views. Numbers on this page are either imported from the production code or computed as you load it. The few hand-written claims are either re-derived by the project’s database-backed test suite, which is a release gate rather than a per-commit one, or dated measurements that say when they were taken (see versioning for exactly what is checked where).
Contents: What this page describes · What this audit found · The pipeline · Variable mappings and recodes · ACE-8 scoring · Statistic definitions · Suppression and rounding · How a value becomes a color · Worked examples (live) · Reproduce it yourself · Cross-checks against published estimates · Assumptions and limitations · Versioning
Every statistic on the dashboard is computed from one fact table seeded from one committed file. The fingerprint below identifies exactly which data this page (and the dashboard) is describing right now; all numbers on this page are computed live from that table or imported from the code that computes them.
prisma/data/brfss-ace.csv.gz (committed via Git LFS), extracted from 32 CDC files: the main file of each of the 10 ACE module years, plus 22 questionnaire-version and landline files for the 41 split-sample state-years (see the pipeline)7b29cdedbc41f0affefd10d78fd6fc161aad8581954164cf253407272c0e687dgit lfs pull, shasum -a 256 prisma/data/brfss-ace.csv.gz must print this value; it is also the file’s Git LFS object id, so the file you pull is verifiably the file we seeded.n < 30 suppresses a value (see the suppression section)Rows per year, the states and territories they come from, and the pooled survey weight each year contributes. How many jurisdictions fielded the ACE module changes from year to year, from 5 to 28, and that is most of why the respondent counts swing so widely: each year averages between 4,653 and 8,133 respondents per jurisdiction.
Every file’s weight is calibrated to its state’s whole adult population, whichever file a state-year was read from; the respondents who reached the ACE module carry most of that total, so each year’s weights sum to somewhat less than that year’s covered adult population. We pool them without renormalization, so the total weight is a person-years-style quantity of about 529,007,713 across 758,236 respondents, which should never be read as a population count.
The arbitrary scale cancels in every ratio we publish. What the pooling does decide is what each ratio averages over: a year enters in proportion to its own total weight, which is not its share of the respondents. In this seed the widest gap is 2020, which carries 21.8% of the pooled weight but 19.5% of the respondents. A state that fielded the module in 7 years therefore contributes far more weight than one that fielded it once, and the pooled figure is neither a single-year estimate nor an equal-weight average of the years. See the limitations register for what that means when comparing states.
| Year | States and territories | Respondents (asked population) | Sum of weights (full precision) |
|---|---|---|---|
| 2009 | 5 | 27,545 | 16050599.75487193 |
| 2010 | 11 | 57,703 | 34258199.93933596 |
| 2011 | 10 | 81,330 | 47687959.933243245 |
| 2012 | 5 | 32,824 | 20380761.3400466 |
| 2019 | 21 | 126,601 | 87657069.52163711 |
| 2020 | 28 | 147,616 | 115316853.11900647 |
| 2021 | 16 | 92,238 | 56855251.90099011 |
| 2022 | 12 | 65,348 | 45797414.40717754 |
| 2023 | 12 | 66,539 | 56384238.89290838 |
| 2024 | 13 | 60,492 | 48619364.08947311 |
Assembling this page in July 2026 surfaced a real extraction defect: the pipeline matched each CDC variable by a single name, but the CDC renames variables across years, so 14 columns were silently blank for whole year blocks. The worst case was the physical-abuse item, blank for all of 2009-2012, which made a complete ACE score impossible for 21% of the table and made six states (Louisiana, Minnesota, North Carolina, Oklahoma, Vermont, and Washington) appear to have no score data at all.
The fix (2026-07-30) repaired the alias lists, added era-aware recodes where a rename also changed response coding, and made the extractor refuse to write a CSV when a column resolves to nothing without a documented reason, so this class of defect now fails loudly instead of shipping silently. The scored population grew from 393,535 respondents (effectively 2019-2024) to 501,877 spanning 2009-2024, and the six states above went from N/A to real values.
What the recovered data changed, and the era-comparability questions it raised (a break in series in the physical-abuse item, a melanoma reclassification, definition drift in the drinking flags), are documented in the limitations register below; headline effects were modest (mean ACE score 1.634 to 1.605).
A second audit (2026-09-22) found that the dashboard had been missing ACE data CDC publishes outside its main annual files. When a state asks a module on only some versions of its questionnaire, CDC blanks those answers in the main file and publishes them in per-version files with their own weights, and in 2011 it did the same for modules asked on the landline survey only. The extractor read the main files alone, so 40 state-years never reached the dashboard, including every year of eight states (California, Kansas, Maine, Maryland, Massachusetts, Nebraska, New York, and Ohio). Oklahoma 2012 was loaded, but from the main file, where CDC had left its version-2 answers under the main-file weight: that weight summed to 1.34 million over those respondents, about half the state’s adults, where the version weight sums to 2.74 million.
The fix (2026-09-22) added a registry of which file each such state-year comes from (the last column of the pipeline’s source table), reads each from its version or landline file with that file’s own weight, rescales the two state-years asked on two versions, and makes the extractor stop with an error if any file it reads carries ACE answers the registry does not account for. Rows went from 557,014 to 758,236, jurisdictions with ACE data from 41 to 49, and state-years from 93 to 133; the scored population, 501,877 before, is 673,232 now (live). Every other state-year is unchanged row for row. Headline effects were again small (mean ACE score 1.605 to 1.600; one or more ACEs 64.45% to 64.40%), and the new state-years’ own caveats (subsample size, landline-only 2011 rows, California 2011’s missing incarceration item) are in the limitations register.
Until November 2026 the score grouped the 11 items into 7 categories, not the 8 CDC scores. It counted ACEPUNCH, which asks how often the adults in the respondent’s home slapped, hit, kicked, punched or beat each other up, as physical abuse alongside ACEHURT, which asks whether a parent or adult in the home hit, beat, kicked or physically hurt the respondent. CDC’s published BRFSS analyses, including both sources in the cross-checks section, score ACEPUNCH as a household-dysfunction category of its own, witnessed intimate partner violence. The grouping appears to trace to the prototype’s data dictionary, which gave ACEPUNCH the wording of the physical-abuse question.
An outside review of the dashboard’s maps in November 2026 recommended scoring the two separately, for two reasons. First, they are different experiences: physical abuse is violence aimed at the child, while witnessed partner violence is violence between the adults the child lived with. Counting them as one category treated a direct exposure and a vicarious one as the same thing. Second, merging them squeezed the top of the score. A respondent who reported both counted once, so the score stopped at 7 and every such adult scored a point lower than CDC’s method scores them, which put fewer people in the four-or-more band than belong there.
The score now runs 0-8, and the expanded score with the two neglect items 0-10. On the same respondents, physical abuse went from 31.08% to 24.65% (CDC: 23.3%), and witnessed intimate partner violence reads 17.58% (CDC: 17.2%). Respondents with both experiences now score one point higher, so the mean ACE score rose from 1.600 to 1.704, and four or more ACEs from 15.67% to 17.62% (CDC: 17.3%). The share with at least one ACE did not change, since anyone who reported either item already counted once, and neither did who is scored. The figures earlier in this section are on the old 7-category score; the new ones here are live.
scripts/process-brfss.ts). Every state-year is read from exactly one source: its year’s main file, unless the split-sample registry (src/lib/brfss/split-sample.ts, the last column below) lists it, in which case its rows come from the listed version or landline file(s) only and its copies in every other file are ignored. That is what keeps a respondent from being counted twice: version files repeat the states that asked the module on every version, and the 2012 main file repeats Oklahoma’s version-2 answers under the main-file weight. Each row keeps its own file’s final weight. For the state-years asked on two versions (CA 2011 and NE 2011), each version’s weight is multiplied by that version’s share of the state-year’s ACE respondents, P_k = n_k / (n_1 + n_2) (CDC’s rule for combining versions), so the two together sum to one state population rather than two. The run stops with an error if any file it reads carries ACE answers the registry does not account for, or a listed state-year yields no rows; that is the only reason the files that supply nothing are read. Within a file, each standardized column takes the first alias present (see the variable mapping table). A respondent’s row is kept if any ACE item cell is non-blank: BRFSS codes a refusal or “don’t know” as 7 or 9 and leaves a never-asked item blank, so non-blank-anywhere is exactly the asked population, refusers included. The two 2021+ neglect items count for this test even though they are not scored.src/lib/brfss/transform.ts, prisma/seed.ts). Recodes every demographic and outcome, derives the ACE-8 score and category flags (see scoring), derives ace_module_asked by testing that all 11 scored item cells are non-blank on the raw strings (a replication must test missingness on the raw variable, not the recode, to keep refusers in the asked base), then bulk-COPYs into the respondents table. Only two rules drop a row entirely: unknown state FIPS, or a missing/non-positive weight.src/lib/queries/sql.ts). One GROUPING SETS scan computes every weighted numerator, weighted denominator, and unweighted count the dashboard needs; there are no precomputed rollup tables. The worked examples below show the exact statements.src/lib/queries/shape.ts, suppress.ts). Numerator over denominator, suppression when the unweighted count is under the threshold, deterministic half-up rounding. Suppression happens only here, after aggregation; the database never stores a suppressed value.Survey weight: each row’s own file’s final weight, in the Weight column below. _LLCPWT (2011 onward) or _FINALWT (2009-2010) for a main file; _FINALQn (2009-2010), _LNDWTVn (2011) or _LCPWTVn (2012 onward) for questionnaire version n; _LANDWT for the landline file. CDC weights each of them to the whole state’s adult population, cell-only adults included even for the landline-only 2011 files, so a state-year read from a version or landline file is on the same scale as one read from a main file. The rows we keep, the respondents who reached the ACE module, carry most of that total but not all of it: interviews that ended before the module are not in the data, so a state-year’s weights sum to somewhat less than its adult population, by more where more interviews broke off. Weights are stored raw apart from the two-version rescale. Years are pooled with no renormalization, no year filter exists anywhere in the query layer, and no design variables (_STSTR, _PSU) are extracted.
The one state-year CDC did not blank in the main file is Oklahoma 2012: LLCP2012 carries its version-2 answers under _LLCPWT, which projects those respondents onto only about half the state’s adults. The same respondents are taken from LLCP12V2 with _LCPWTV2 instead, as CDC’s 2012 guidance directs.
41 state-years come from a version or landline file; the last column names them.
The CDC renames a variable whenever a question changes, so one concept can carry several names across 2009-2024. Each standardized column lists its CDC names newest first, and in each file it reads the extractor takes the first name present. A year’s version and landline files use that year’s names too, apart from the weight: the weight row lists the main files’ weights, and every other file is weighted by its own final weight instead (the Weight column of the pipeline’s source table). Where a rename also changed the response coding, the recode branches on year (see the outcome rules below) rather than pretending the codes are compatible. Years listed as “not asked” are documented absences; the extractor refuses to write a CSV if a column fails to resolve in any file of any other year, so a future CDC rename breaks the pipeline loudly instead of leaving a silently hollow column.
| Our column | CDC names, newest first | Not asked in |
|---|---|---|
state | _STATE | |
sex | SEXVAR, SEX1, SEX | |
age_group | _AGE_G | |
race | _RACE1, _RACE, RACE2 | |
education | EDUCA | |
income | INCOME3, INCOME2 | |
ace_depressed | ACEDEPRS | |
ace_alcoholic | ACEDRINK | |
ace_drugs | ACEDRUGS | |
ace_prison | ACEPRISN | |
ace_divorce | ACEDIVRC | |
ace_punch | ACEPUNCH | |
ace_hurt | ACEHURT1, ACEHURT | |
ace_swear | ACESWEAR | |
ace_touch | ACETOUCH | |
ace_touched | ACETTHEM | |
ace_sex | ACEHVSEX | |
ace_safe | ACEADSAF | 2009, 2010, 2011, 2012, 2019, 2020 |
ace_needs | ACEADNED | 2009, 2010, 2011, 2012, 2019, 2020 |
general_health | GENHLTH | |
mental_health_days | MENTHLTH | |
physical_health_days | PHYSHLTH | |
depression | ADDEPEV3, ADDEPEV2, ADDEPEV | 2009 |
smoking_status | SMOKE100 | |
smoking_current | SMOKDAY2 | |
bmi_category | _BMI5CAT, _BMI4CAT | |
heavy_drinker | _RFDRHV9, _RFDRHV8, _RFDRHV7, _RFDRHV6, _RFDRHV5, _RFDRHV4, _RFDRHV3 | |
binge_drinker | _RFBING6, _RFBING5, _RFBING4 | |
physical_activity | _TOTINDA | |
health_insurance | _HLTHPLN, HLTHPLN1, HLTHPLAN, PRIMINS2, PRIMINS1, PRIMINSR | |
cost_barrier | MEDCOST1, MEDCOST | |
diabetes | DIABETE4, DIABETE3, DIABETE2 | |
heart_disease | _MICHD | 2009, 2010, 2011, 2012 |
heart_attack | CVDINFR4 | |
angina_chd | CVDCRHD4 | |
stroke | CVDSTRK3 | |
asthma | ASTHMA3, ASTHMA2 | |
copd | CHCCOPD3, CHCCOPD2, CHCCOPD1, CHCCOPD | 2009, 2010 |
kidney_disease | CHCKDNY2, CHCKIDNY | 2009, 2010 |
arthritis | HAVARTH5, HAVARTH4, HAVARTH3, HAVARTH2 | |
skin_cancer | CHCSCNC1, CHCSCNCR | 2009, 2010 |
other_cancer | CHCOCNC1, CHCOCNCR | 2009, 2010 |
weight | _LLCPWT, _FINALWT |
Percent of that year’s respondents with a non-null recoded value, computed live from the database (for ace_module_asked, percent with the flag true). A 0.0 cell means the column is entirely absent for that year; every such cell carries a footnote. The practical consequence: each statistic has its own implicit year window, and therefore its own state mix.
| Column | 2009 | 2010 | 2011 | 2012 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 |
|---|---|---|---|---|---|---|---|---|---|---|
sex | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 |
age_group | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 |
race | 99.1 | 98.6 | 99.2 | 99.3 | 98.2 | 98.1 | 97.9 | 97.4 | 98.0 | 98.5 |
education | 99.8 | 99.8 | 99.6 | 99.7 | 99.7 | 99.7 | 99.6 | 99.6 | 99.6 | 99.7 |
income | 86.2 | 88.3 | 88.7 | 83.8 | 83.4 | 83.0 | 80.4 | 81.5 | 81.4 | 83.1 |
ace_score | 90.8 | 93.2 | 80.5 | 89.0 | 90.5 | 89.8 | 88.3 | 88.6 | 88.0 | 90.4 |
ace_score_10* | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 87.6 | 87.8 | 87.2 | 89.6 |
ace_module_asked | 99.7 | 99.8 | 86.2 | 99.6 | 99.4 | 99.3 | 99.1 | 99.0 | 98.9 | 99.0 |
ace_emotional_abuse | 96.1 | 98.2 | 96.2 | 94.3 | 97.3 | 96.6 | 96.0 | 96.0 | 96.5 | 97.3 |
ace_physical_abuse | 96.6 | 98.9 | 96.9 | 94.9 | 97.9 | 97.1 | 96.5 | 96.6 | 97.0 | 97.6 |
ace_sexual_abuse | 95.4 | 98.0 | 95.9 | 93.8 | 96.9 | 96.1 | 95.3 | 95.4 | 95.7 | 96.6 |
ace_emotional_neglect* | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 96.9 | 96.7 | 97.3 | 97.6 |
ace_physical_neglect* | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 97.0 | 96.8 | 97.3 | 97.7 |
ace_witnessed_violence | 96.0 | 98.1 | 96.3 | 94.1 | 97.3 | 96.6 | 96.1 | 96.2 | 96.5 | 97.1 |
ace_household_depression | 96.8 | 98.9 | 96.9 | 95.2 | 98.6 | 97.8 | 97.3 | 97.3 | 97.8 | 98.6 |
ace_incarceration | 97.4 | 99.5 | 85.8 | 95.5 | 99.1 | 98.3 | 97.9 | 97.9 | 98.4 | 98.9 |
ace_substance_abuse | 96.9 | 98.8 | 96.9 | 95.1 | 98.5 | 97.7 | 97.2 | 97.3 | 97.8 | 98.4 |
ace_divorce | 96.5 | 98.8 | 96.8 | 94.2 | 97.3 | 96.6 | 96.0 | 96.2 | 96.1 | 97.1 |
depression* | 0.0 | 41.1 | 99.6 | 99.6 | 99.5 | 99.5 | 99.5 | 99.4 | 99.4 | 99.5 |
frequent_mental_distress | 98.7 | 98.6 | 98.5 | 98.4 | 97.7 | 98.1 | 98.2 | 97.9 | 98.0 | 98.3 |
fair_poor_health | 99.8 | 99.7 | 99.7 | 99.7 | 99.7 | 99.8 | 99.7 | 99.7 | 99.7 | 99.7 |
frequent_physical_distress | 98.1 | 98.0 | 98.1 | 97.8 | 97.3 | 97.9 | 97.8 | 97.5 | 97.3 | 97.8 |
diabetes | 99.9 | 99.9 | 99.9 | 99.8 | 99.8 | 99.8 | 99.8 | 99.8 | 99.8 | 99.8 |
heart_disease | 99.2 | 98.9 | 99.2 | 99.3 | 99.0 | 99.1 | 98.9 | 98.9 | 98.9 | 98.9 |
stroke | 99.7 | 99.7 | 99.7 | 99.7 | 99.7 | 99.7 | 99.7 | 99.6 | 99.6 | 99.7 |
asthma | 99.7 | 99.6 | 99.7 | 99.7 | 99.7 | 99.7 | 99.6 | 99.6 | 99.6 | 99.7 |
copd* | 0.0 | 0.0 | 99.5 | 99.5 | 99.4 | 99.5 | 99.5 | 99.5 | 99.5 | 99.5 |
kidney_disease* | 0.0 | 0.0 | 99.7 | 99.7 | 99.6 | 99.6 | 99.5 | 99.5 | 99.5 | 99.6 |
arthritis | 99.2 | 7.4 | 99.4 | 99.5 | 99.4 | 99.5 | 99.3 | 99.4 | 99.4 | 99.4 |
skin_cancer* | 0.0 | 0.0 | 99.7 | 99.8 | 99.7 | 99.7 | 99.7 | 99.1 | 99.2 | 99.3 |
other_cancer* | 0.0 | 0.0 | 99.8 | 99.8 | 99.7 | 99.7 | 99.7 | 99.3 | 99.4 | 99.4 |
current_smoking | 99.6 | 99.5 | 99.6 | 98.8 | 99.4 | 99.2 | 99.2 | 99.1 | 99.2 | 99.3 |
obesity | 95.8 | 96.3 | 95.3 | 94.5 | 94.1 | 93.3 | 92.7 | 93.6 | 93.7 | 95.0 |
heavy_drinking | 98.0 | 98.3 | 97.6 | 97.1 | 98.0 | 97.8 | 97.8 | 97.9 | 98.4 | 98.4 |
binge_drinking | 98.7 | 99.0 | 97.7 | 97.1 | 97.9 | 97.8 | 97.9 | 97.6 | 98.3 | 98.4 |
no_insurance | 99.8 | 99.8 | 99.7 | 99.7 | 99.5 | 99.6 | 96.4 | 96.6 | 95.5 | 96.7 |
cost_barrier | 99.9 | 99.8 | 99.8 | 99.8 | 99.7 | 99.7 | 99.7 | 99.7 | 99.6 | 99.7 |
ace_score_10 (2009, 2010, 2011, 2012, 2019, 2020)ace_emotional_neglect (2009, 2010, 2011, 2012, 2019, 2020)ace_physical_neglect (2009, 2010, 2011, 2012, 2019, 2020)depression (2009)copd (2009, 2010)kidney_disease (2009, 2010)skin_cancer (2009, 2010)other_cancer (2009, 2010)SEXVAR, SEX1, SEX)| Raw code | Database label | Display label |
|---|---|---|
| 1 | male | Male |
| 2 | female | Female |
_AGE_G)| Raw code | Database label | Display label |
|---|---|---|
| 1 | 18_24 | 18-24 |
| 2 | 25_34 | 25-34 |
| 3 | 35_44 | 35-44 |
| 4 | 45_54 | 45-54 |
| 5 | 55_64 | 55-64 |
| 6 | 65_plus | 65+ |
_RACE1, _RACE, RACE2)| Raw code | Database label | Display label |
|---|---|---|
| 1 | white | White, non-Hispanic |
| 2 | black | Black, non-Hispanic |
| 3 | aian | American Indian/Alaska Native |
| 4 | asian | Asian, non-Hispanic |
| 5 | nhpi | Native Hawaiian/Pacific Islander |
| 6 | other | Other race |
| 7 | multiracial | Multiracial |
| 8 | hispanic | Hispanic |
EDUCA)| Raw code | Database label | Display label |
|---|---|---|
| 1 | never_attended | Never attended school |
| 2 | elementary | Elementary (Grades 1-8) |
| 3 | some_high_school | Some high school |
| 4 | high_school_grad | High school graduate/GED |
| 5 | some_college | Some college |
| 6 | college_grad | College graduate |
INCOME3, INCOME2)| Raw code | Database label | Display label |
|---|---|---|
| 1 | under_10k | <$10K |
| 2 | 10k_15k | $10-15K |
| 3 | 15k_20k | $15-20K |
| 4 | 20k_25k | $20-25K |
| 5 | 25k_35k | $25-35K |
| 6 | 35k_50k | $35-50K |
| 7 | 50k_75k | $50-75K |
| 8 | 75k_plus | $75K+ |
| 8 | 75k_100k | $75-100K |
| 9 | 100k_150k | $100-150K |
| 10 | 150k_200k | $150-200K |
| 11 | 200k_plus | $200K+ |
Race is era-switched on the row’s own year, and the tables above show the 2013+ codes. RACE2 (2009-2012) and _RACE (2013+) both carry eight categories, but three of them sit at different raw codes, so for a 2009-2012 row the extractor remaps before recoding. Every other code, and every other dimension, is era-free.
| Raw RACE2 code (2009-2012) | Reads as _RACE code | Database label | Display label |
|---|---|---|---|
| 3 | 4 | asian | Asian, non-Hispanic |
| 4 | 5 | nhpi | Native Hawaiian/Pacific Islander |
| 5 | 3 | aian | American Indian/Alaska Native |
A replication that reads RACE2 straight onto the _RACE scale relabels Asian, Native Hawaiian/Pacific Islander and American Indian/Alaska Native respondents as each other for every 2009-2012 row.
Codes not listed above become null (the row is kept; the respondent drops out of that dimension’s breakdowns): race 9, education 9, income 77/99, and any other out-of-range code. Income is era-switched on the row’s own year: through 2020 the question is INCOME2 and code 8 means 75k_plus; from 2021 it is INCOME3 and code 8 means 75k_100k, with codes 9-11 covering the finer top buckets. The two code-8 meanings are stored as distinct labels and never unioned, so filtering on 75k_plus implicitly selects only 2009-2020 respondents and the fine buckets select only 2021+ respondents.
| Our item | BRFSS variable | Type | Valid codes | Endorsed codes | Category (the last two are 10-item only) |
|---|---|---|---|---|---|
ace_depressed | ACEDEPRS | binary (1 = Yes, 2 = No) | 1, 2 | 1 | Household Mental Illness |
ace_alcoholic | ACEDRINK | binary (1 = Yes, 2 = No) | 1, 2 | 1 | Household Substance Abuse |
ace_drugs | ACEDRUGS | binary (1 = Yes, 2 = No) | 1, 2 | 1 | Household Substance Abuse |
ace_prison | ACEPRISN | binary (1 = Yes, 2 = No) | 1, 2 | 1 | Household Member Incarcerated |
ace_divorce | ACEDIVRC | binary (1 = Yes, 2 = No) | 1, 2 | 1 | Parental Separation/Divorce |
ace_punch | ACEPUNCH | frequency (1 = Never, 2 = Once, 3 = More than once) | 1, 2, 3 | 2 or 3 | Witnessed Intimate Partner Violence |
ace_hurt | ACEHURT1, ACEHURT | frequency (1 = Never, 2 = Once, 3 = More than once) | 1, 2, 3 | 2 or 3 | Physical Abuse |
ace_swear | ACESWEAR | frequency (1 = Never, 2 = Once, 3 = More than once) | 1, 2, 3 | 2 or 3 | Emotional/Verbal Abuse |
ace_touch | ACETOUCH | frequency (1 = Never, 2 = Once, 3 = More than once) | 1, 2, 3 | 2 or 3 | Sexual Abuse |
ace_touched | ACETTHEM | frequency (1 = Never, 2 = Once, 3 = More than once) | 1, 2, 3 | 2 or 3 | Sexual Abuse |
ace_sex | ACEHVSEX | frequency (1 = Never, 2 = Once, 3 = More than once) | 1, 2, 3 | 2 or 3 | Sexual Abuse |
ace_safe | ACEADSAF | reverse protective (1 = Never ... 5 = All of the time) | 1-5 | 1 or 2 (neglect present) | Emotional Neglect |
ace_needs | ACEADNED | reverse protective (1 = Never ... 5 = All of the time) | 1-5 | 1 or 2 (neglect present) | Physical Neglect |
ACEPUNCH (adults in the home hitting each other) is its own category, witnessed intimate partner violence, as in CDC’s published 8-category scoring. It is not part of physical abuse, which is ACEHURT/ACEHURT1 alone. Versions of this dashboard before November 2026 folded the two together (see the audit section). The expanded 10-item score adds the two neglect categories on their restricted 2021+ basis; see the scoring section and the limitations register.Every outcome is recoded to case / non-case / excluded (null). Excluded respondents leave both the numerator and the denominator of that outcome’s statistic; they are never counted as “no”. Each rule below is machine-checked against the recode functions in CI.
| Outcome | BRFSS variables | Rule |
|---|---|---|
| Depression | ADDEPEV3, ADDEPEV2, ADDEPEV | 1 = case; 2 = non-case; 7, 9, blank = excluded (null). |
| Frequent Mental Distress | MENTHLTH | Days recode first: 88 = 0 days; 1-30 kept; 77, 99, blank = excluded. Case iff recoded days >= 14. |
| Fair or Poor General Health | GENHLTH | 1-5 valid; 4 (Fair) or 5 (Poor) = case; 1-3 = non-case; 7, 9, blank = excluded. |
| Frequent Physical Distress | PHYSHLTH | Days recode first: 88 = 0 days; 1-30 kept; 77, 99, blank = excluded. Case iff recoded days >= 14. |
| Diabetes | DIABETE4, DIABETE3, DIABETE2 | 1 = case; 2 (yes, only during pregnancy), 3 (no), 4 (pre-diabetes/borderline) = non-case; 7, 9, blank = excluded. |
| Heart Disease | _MICHD, CVDINFR4, CVDCRHD4 | Reported MI or CHD. CDC's calculated _MICHD (2019+) wins where present: 1 = case, 2 = non-case. For 2009-2012, where CDC did not compute _MICHD, its own definition is applied to its two inputs: CVDINFR4 (heart attack) or CVDCRHD4 (angina/CHD) = 1 -> case; both = 2 -> non-case; anything else excluded. The derivation agrees with _MICHD on every row where both exist. |
| Stroke | CVDSTRK3 | 1 = case; 2 = non-case; 7, 9, blank = excluded (null). |
| Asthma | ASTHMA3, ASTHMA2 | Lifetime asthma. 1 = case; 2 = non-case; 7, 9, blank = excluded (null). |
| COPD | CHCCOPD3, CHCCOPD2, CHCCOPD1, CHCCOPD | 1 = case; 2 = non-case; 7, 9, blank = excluded (null). |
| Kidney Disease | CHCKDNY2, CHCKIDNY | 1 = case; 2 = non-case; 7, 9, blank = excluded (null). |
| Arthritis | HAVARTH5, HAVARTH4, HAVARTH3, HAVARTH2 | 1 = case; 2 = non-case; 7, 9, blank = excluded (null). |
| Skin Cancer | CHCSCNC1, CHCSCNCR | 1 = case; 2 = non-case; 7, 9, blank = excluded (null). Note: from 2022 this item asks only about skin cancer that is not melanoma, so it is not comparable across 2022. |
| Other Cancer | CHCOCNC1, CHCOCNCR | 1 = case; 2 = non-case; 7, 9, blank = excluded (null). Note: from 2022 this item names melanoma explicitly, previously counted under "skin cancer", so it is not comparable across 2022. |
| Current Smoking | SMOKE100, SMOKDAY2 | smoking_status 2 (never smoked 100 cigarettes) = non-case; smoking_status 1 and smoking_current 1 (every day) or 2 (some days) = case; smoking_status 1 and smoking_current 3 (not at all) = non-case; every other combination = excluded. |
| Obesity | _BMI5CAT, _BMI4CAT | Calculated BMI category, era-aware. 2011+ (_BMI5CAT): 1-4 valid, 4 (BMI >= 30) = case. 2009-2010 (_BMI4CAT): only three levels, 3 (BMI >= 30) = case; reading it on the _BMI5CAT scale would misfile every obese respondent in those years. |
| Heavy Drinking | _RFDRHV9, _RFDRHV8, _RFDRHV7, _RFDRHV6, _RFDRHV5, _RFDRHV4, _RFDRHV3 | Calculated risk flag with inverted coding: 1 = No (non-case); 2 = Yes (case); 9, blank = excluded. CDC's drink-count thresholds behind this flag changed across its renames (_RFDRHV3 through _RFDRHV9) even though the response codes never did, so the definition is not constant across years. |
| Binge Drinking | _RFBING6, _RFBING5, _RFBING4 | Calculated risk flag with inverted coding: 1 = No (non-case); 2 = Yes (case); 9, blank = excluded. As with heavy drinking, the underlying definition shifted across CDC's renames (_RFBING4 through _RFBING6). |
| No Health Insurance | _HLTHPLN, HLTHPLN1, HLTHPLAN, PRIMINS2, PRIMINS1, PRIMINSR | Era-aware. Through 20227, 9, blank = excluded. 2023+ have no yes/no item, only the PRIMINS source-of-coverage scale: 1-10 name a source (non-case), 88 = none (case), 77/99 excluded. The collapse reproduces CDC's own calculated _HLTHPLN exactly where both exist. |
| Couldn't Afford Care | MEDCOST1, MEDCOST | Needed to see a doctor but could not because of cost. 1 = case; 2 = non-case; 7, 9, blank = excluded. |
The 10 ACE indicator columns referenced throughout are ace_emotional_abuse, ace_physical_abuse, ace_sexual_abuse, ace_emotional_neglect, ace_physical_neglect, ace_witnessed_violence, ace_household_depression, ace_incarceration, ace_substance_abuse, ace_divorce.
The 11 scored items collapse into the 8 categories CDC scores in its published BRFSS analyses (Merrick et al., JAMA Pediatrics 2018; Swedo et al., MMWR 2023), under three rules:
Category composition: Sexual Abuse = ace_touch + ace_touched + ace_sex; Physical Abuse = ace_hurt; Witnessed Intimate Partner Violence = ace_punch; Household Substance Abuse = ace_alcoholic + ace_drugs; Emotional/Verbal Abuse = ace_swear; Household Mental Illness = ace_depressed; Household Member Incarcerated = ace_prison; Parental Separation/Divorce = ace_divorce.
The two 2021+ neglect items add two categories on top of the eight: Emotional Neglect = ace_safe; Physical Neglect = ace_needs. The expanded score is complete-case over all 13 items (0-10, mean only, no bands) and is scored separately, so the ACE-8 score never moves. Its basis is strictly smaller: the neglect items were fielded 2021-2024 by 29 of the 49 ACE jurisdictions, so expanded-score and neglect-indicator numbers are not comparable to the pooled metrics (see the limitations register). One computed contrast, live from the production scorers: a respondent answering No to all 11 pooled items who was never made to feel safe scores ACE-8 = 0 but ACE-10 = 1.
Only the input vectors are authored; every flag and score below is computed by the production scoring functions as this page renders.
| Example | Sexual Abuse | Physical Abuse | Witnessed Intimate Partner Violence | Household Substance Abuse | Emotional/Verbal Abuse | Household Mental Illness | Household Member Incarcerated | Parental Separation/Divorce | Score |
|---|---|---|---|---|---|---|---|---|---|
| All items answered No/Never | No | No | No | No | No | No | No | No | 0 |
| Household depression, substance use, sworn at more than once | No | No | No | Yes | Yes | Yes | No | No | 3 |
| Touched once (code 2) | Yes | No | No | No | No | No | No | No | 1 |
| Hit by an adult once, saw adults hit each other more than once | No | Yes | Yes | No | No | No | No | No | 2 |
| Parents never married (ACEDIVRC code 8) | No | No | No | No | No | No | No | null | null |
| Refused the incarceration item (code 7) | No | No | No | No | No | No | null | No | null |
| Physical-abuse item never asked (blank) | No | null | No | No | No | No | No | No | null |
Let w be the survey weight: each respondent’s final weight from the file their state-year was read from (see the pipeline), unmodified except that a state-year read from two questionnaire-version files has each version’s weight multiplied by that version’s share of the state-year’s respondents (P_k = n_k / Σn), pooled over every year and state in scope with no renormalization. Every statistic is a ratio of two weighted sums from one scan, published as round(numerator / denominator, digits) unless suppressed. The table names the exact SQL aggregate aliases; the worked examples below show the statement that computes them and the live values.
| Statistic | Numerator (Σw over ...) | Denominator (Σw over ...) | Suppression count | Digits |
|---|---|---|---|---|
| Average ACE score | score_ws | score_w | score_n | 3 |
| Average expanded ACE score (10 items) | score10_ws | score10_w | score10_n | 3 |
| Percent of adults with 0 ACEs | w_eq0 | score_w | score_n | 4 |
| Percent of adults with 1+ ACEs | w_ge1 | score_w | score_n | 4 |
| Percent of adults with 2+ ACEs | w_ge2 | score_w | score_n | 4 |
| Percent of adults with 3+ ACEs | w_ge3 | score_w | score_n | 4 |
| Percent of adults with 4+ ACEs | w_ge4 | score_w | score_n | 4 |
| Emotional/Verbal Abuse | ace_emotional_abuse_s | ace_emotional_abuse_w | ace_emotional_abuse_n | 4 |
| Physical Abuse | ace_physical_abuse_s | ace_physical_abuse_w | ace_physical_abuse_n | 4 |
| Sexual Abuse | ace_sexual_abuse_s | ace_sexual_abuse_w | ace_sexual_abuse_n | 4 |
| Emotional Neglect | ace_emotional_neglect_s | ace_emotional_neglect_w | ace_emotional_neglect_n | 4 |
| Physical Neglect | ace_physical_neglect_s | ace_physical_neglect_w | ace_physical_neglect_n | 4 |
| Witnessed Intimate Partner Violence | ace_witnessed_violence_s | ace_witnessed_violence_w | ace_witnessed_violence_n | 4 |
| Household Mental Illness | ace_household_depression_s | ace_household_depression_w | ace_household_depression_n | 4 |
| Household Member Incarcerated | ace_incarceration_s | ace_incarceration_w | ace_incarceration_n | 4 |
| Household Substance Abuse | ace_substance_abuse_s | ace_substance_abuse_w | ace_substance_abuse_n | 4 |
| Parental Separation/Divorce | ace_divorce_s | ace_divorce_w | ace_divorce_n | 4 |
| ACE module completion | score_w | asked_w | asked_n | 4 |
Aggregate glossary (aliases as they appear in the SQL):
score_n, score_w, score_wsscore_ws / score_w.w_eq0, w_ge1 ... w_ge4score = 0 and score >= 1..4. The score bands are cumulative and share the scored-base denominator: “score 0” and “1 or more” sum to 1, but the 1+/2+/3+/4+ bands are nested, not a partition.<indicator>_n, _w, _sscore10_n, score10_w, score10_wsasked_n, asked_wscore_w / asked_w: the share of the asked population that produced a complete score.An ACE-indicator population narrows the scan itself, adding WHERE <flag> IS TRUE. “Any ACE score” adds no WHERE clause at all.
A score-group population is the one case that is neither, because the same band is doing two jobs. Its own map metric is the share of the scored base in that band, so WHERE ace_score >= 4 would pin it at a trivial 100% in every state. Everything else on screen is a rate within the band. So the band is applied as a FILTER conjunct rather than a WHERE: the score family (the mean and the cumulative bands) keeps scanning the unnarrowed scored base, while every indicator prevalence, Compare y variable and co-occurrence arm carries AND ace_score >= 4 on both its numerator and its denominator. A replication that row-filters to score >= 4 before computing indicator prevalence will match this view; one that also recomputes the “percent with 4 or more” off that filtered set will not, and should read it off the full scored base instead. The exact statement for the current scope, bands included, is in the worked example below.
ace_module_asked, only offered for the unnarrowed “Any ACE score” population (an ACE population would condition on having answered the category whose nonresponse is being measured).Explore publishes crude estimates. Compare publishes age-adjusted estimates by default, with crude one switch away (adj=crude), because age moves both of the things Compare sets side by side: older adults report fewer ACEs and have more long-term conditions, and jurisdictions differ in how old their adults are (limitation 5 below). The method is direct standardisation:
_AGE_G).The standard is the 2000 U.S. projected population (Klein and Schoenborn, Healthy People Statistical Notes no. 20, NCHS 2001, Table 2), the standard CDC uses for age-adjusted BRFSS prevalence. Its published Distribution #9 merges ages 45-64; the two ten-year counts below are the same table’s rows and sum to that group.
| Age group | Standard population (thousands) | Weight |
|---|---|---|
| 18-24 | 26,258 | 12.9% |
| 25-34 | 37,233 | 18.3% |
| 35-44 | 44,659 | 21.9% |
| 45-54 | 37,030 | 18.2% |
| 55-64 | 23,961 | 11.8% |
| 65+ | 34,710 | 17.0% |
What a replication must copy:
ACE accumulation split by y. For each cumulative band, 1+ through 4+, the card publishes Σw(score at or above the band) / Σw(score non-null) twice: once among respondents with the y variable, once among those without it. “Without” is a valid y response that is not positive (depression IS FALSE; for Any outcome it is the No outcome definition, and the reverse). Respondents with no complete score or no valid y are on neither side, and each side’s four bands share one denominator and one n, so a side suppresses all four rows together.
Two adjustments keep the rows from being true by definition. When y is itself an ACE the score counts (every indicator but the two neglect items), the bands threshold ace_score - <y flag>::int, the count of the other ACEs, on both sides: otherwise everyone with y would read 100% at 1+. And a band the population already decides is not shown, because it is the same on both sides by construction: 1+ under an ACE population the score counts, every band up to k under “an ACE score of k or more”, and every band under “an ACE score of 0”. When y is module completion the whole card is skipped: completing the module is what produces a score, so the side without completion is always empty.
The number the card displays is neither side. Its value column is headed “Prevalence gap (%)” and holds with − without in percentage points: a difference of two proportions, so it carries no denominator of its own. Three properties a replication must copy exactly:
17.6, meaning 17.6 percentage points, not 17.6%.The full chain for one value, in order:
n < 30 or the weighted denominator is not positive, the value is nulled. The count n is kept, so the UI can distinguish suppressed (n > 0, rendered “--”, interpret with caution) from no data (n = 0, rendered “N/A”). The gate reads the unweighted count; there is no relative-standard-error rule.Math.round, avoiding toFixed float drift).For replication: match the rounded API value, not the display string; your unrounded estimate should agree with our unrounded quotient to well under 5e-5 before rounding. The boundary behavior below is computed by calling the production makeCell() as this page renders:
| Case | num | den | n | Cell value | Status | Rendered |
|---|---|---|---|---|---|---|
| n one below the threshold | 60 | 100 | 29 | null | suppressed | -- |
| n exactly at the threshold | 60 | 100 | 30 | 0.6 | value | 60.0% |
| large cell | 60 | 100 | 5000 | 0.6 | value | 60.0% |
| no data at all | 0 | 0 | 0 | null | nodata | N/A |
| count without weight (defensive) | 0 | 0 | 50 | null | suppressed | -- |
An age-adjusted value passes the same gate and one more. It is an average of six age-group ratios on fixed weights, so a cell with plenty of respondents overall can still rest on a handful in one age group that the standard counts heavily. Two extra conditions apply, and failing either renders “--” with the cell’s real n:
With no demographic filter every jurisdiction passes. The gate bites on narrow filters, where a state’s age groups thin out. Computed by calling the production suppressedValue() as this page renders, for a cell of 400 respondents:
| Case | n | Effective n | Value | Rendered |
|---|---|---|---|---|
| effective n one below the threshold | 400 | 29 | null | -- |
| effective n exactly at the threshold | 400 | 30 | 0.6 | 60.0% |
| an age group in scope has no respondents (reported as 0) | 400 | 0 | null | -- |
Both maps are cartograms: one equal-size tile per jurisdiction, laid out in an approximate geography, so tile area carries no meaning and no state is visually larger than another. The color is the encoding. This section states the rule for each map, because a color is a published statistic like any other, and on the Compare map it is the only thing a classed tile shows.
Every state’s value for the selected metric is classed together. The domain is the observed [minimum, maximum] across the states currently on the map, cut by scaleQuantize into as many equal-width classes as the ramp has stops (3). Each cut is then snapped to what the tiles print: it moves to the half-step just above the last value a tile can print at or below it, and every state is classed by its printed value, so two tiles that read the same always share a color. If every state prints the same value there is nothing to cut, and a single stop carries the whole map, which is why the count above is 3 for the scope you are looking at. The table below is not a description of that arithmetic; it is the scale’s own cut points, read back out of the object the tiles are filled from. Three consequences a reader must not miss:
Live for the current scope (metric Percent of adults with 4+ ACEs), classed over 49 jurisdictions:
| Class | Fill | Hex | Tiles reading | Values from | up to |
|---|---|---|---|---|---|
| 1 | #E0F3DB | 9.5% to 14.2% | 9.53% | 14.25% | |
| 2 | #A8DDB5 | 14.3% to 19.0% | 14.25% | 19.05% | |
| 3 | #43A2CA | 19.1% to 23.8% | 19.05% | 23.77% (inclusive) |
The respondents display maps score_n itself: the unweighted count of respondents with a complete ACE score in the scope. No weight touches it, and it is never suppressed, because a count is exact at any size. Counts are skewed, so it is not classed like the statistics above (in this scope the largest classable count is 47.0 times the smallest): equal-width classes would spend most of the ramp on a few big states. Instead it cuts log10 of the count into equal intervals with the same three stops, so each step up is the same multiple. Each cut is rounded to two significant figures and the rounded value is the threshold drawn (if rounding would collapse a class, the cut falls back to the next whole respondent, which classes every count exactly as the unrounded cut would). The legend note under that map prints these cuts.
States under n = 30 stay out of the domain and take the no-data gray, and their tile reads < 30 rather than the exact count, because it is too small for any of the estimates above. In this scope that is 0 of 49 jurisdictions. Live:
| Class | Fill | Hex | Respondents from | up to |
|---|---|---|---|---|
| 1 | #E0F3DB | 972 | 3,500 | |
| 2 | #A8DDB5 | 3,500 | 13,000 | |
| 3 | #43A2CA | 13,000 | 45,661 (inclusive) |
The bivariate map does not class against the data range. It classes each state against the national value of each axis: the same two numbers the scatterplot draws as its crosshair, so a tile’s color and its dot’s quadrant can never disagree. A state is “high” on an axis when its value is greater than or equal to the national value: a state exactly on the line counts as high.
Live thresholds for the current pair. x = Percent of adults with 4+ ACEs 18.97%, y = Depression 38.87%:
| Class | Fill | Hex | Rule |
|---|---|---|---|
| x-high / y-low | #225EA8 | x >= national x AND y < national y | |
| y-high / x-low | #E22B0F | y >= national y AND x < national x | |
| Both low | #DEB8E5 | x < national x AND y < national y | |
| Both high | #40004B | x >= national x AND y >= national y |
A tile with no class is filled with the no-data gray on both maps, and keeps a text marker so suppression is never encoded in color alone. The two maps reach that state by different rules:
-- below n = 30, N/A at n = 0. A jurisdiction with no ACE module data returns no row at all and so reads N/A. The respondents display is the exception: its value is the count, so a tile under the threshold is gray and reads < 30, and only n = 0 reads N/A.-- only when both x and y were measured (n > 0 on each) but at least one is below the threshold; if either side measured nothing at all, the pair reads N/A, because “low sample size” would be the wrong caution there. So a Compare tile can read N/A for a state whose x value publishes perfectly well on the Explore map. The same pair rule governs each co-occurrence row.The Compare scatterplot plots one dot per jurisdiction at (x, y), with the national values drawn as a crosshair: the same two thresholds the bivariate map splits on. Its axes are scaled to round ticks (the smallest 1 / 2.5 / 5 × 10ⁿ step covering the data in about four intervals, with the domain floored and ceiled to that step and the national values forced inside it), so the axis bounds are display choices and not data limits.
It also draws a line of best fit: ordinary least squares over the plotted dots. Two properties to be explicit about, since the page publishes no other fitted quantity:
Everything below runs the production statements against the live database as this page renders, shows the raw intermediate aggregates, and re-derives the published value step by step. The intermediates obey the same publication rule as the values: weighted sums appear only for cells of at least 30 respondents, and a suppressed or empty cell shows its unweighted n and the decision but withholds the sums, because for a tiny cell the weighted numerator and denominator would be a single respondent’s own survey weight. Per-respondent weights never appear (this page’s one deliberate extension of the API’s “ratios and counts only” rule stops exactly there).
Current scope: adults with an ACE score of 4 or more, metric Percent of adults with 4+ ACEs. Open it on the dashboard: Explore / Compare.
One scan computes every aggregate for the scope (national total, every state, and the national demographic rows; gset is the GROUPING bitmask that routes them). This is the exact statement and bindings the dashboard executes:
SELECT state_fips,
sex::text AS sex,
age_group::text AS age_group,
race::text AS race,
education::text AS education,
income::text AS income,
GROUPING(state_fips, sex, age_group, race, education, income)::int AS gset,
COUNT(*) FILTER (WHERE ace_module_asked)::int AS asked_n,
SUM(weight) FILTER (WHERE ace_module_asked)::float8 AS asked_w,
COUNT(*) FILTER (WHERE ace_score IS NOT NULL)::int AS score_n,
SUM(weight) FILTER (WHERE ace_score IS NOT NULL)::float8 AS score_w,
SUM(weight * ace_score) FILTER (WHERE ace_score IS NOT NULL)::float8 AS score_ws,
SUM(weight) FILTER (WHERE ace_score = 0)::float8 AS w_eq0,
SUM(weight) FILTER (WHERE ace_score >= 1)::float8 AS w_ge1,
SUM(weight) FILTER (WHERE ace_score >= 2)::float8 AS w_ge2,
SUM(weight) FILTER (WHERE ace_score >= 3)::float8 AS w_ge3,
SUM(weight) FILTER (WHERE ace_score >= 4)::float8 AS w_ge4,
COUNT(*) FILTER (WHERE ace_score_10 IS NOT NULL)::int AS score10_n,
SUM(weight) FILTER (WHERE ace_score_10 IS NOT NULL)::float8 AS score10_w,
SUM(weight * ace_score_10) FILTER (WHERE ace_score_10 IS NOT NULL)::float8 AS score10_ws,
COUNT(*) FILTER (WHERE ace_emotional_abuse IS NOT NULL AND ace_score >= 4)::int AS ace_emotional_abuse_n,
SUM(weight) FILTER (WHERE ace_emotional_abuse IS NOT NULL AND ace_score >= 4)::float8 AS ace_emotional_abuse_w,
SUM(weight) FILTER (WHERE ace_emotional_abuse AND ace_score >= 4)::float8 AS ace_emotional_abuse_s,
COUNT(*) FILTER (WHERE ace_physical_abuse IS NOT NULL AND ace_score >= 4)::int AS ace_physical_abuse_n,
SUM(weight) FILTER (WHERE ace_physical_abuse IS NOT NULL AND ace_score >= 4)::float8 AS ace_physical_abuse_w,
SUM(weight) FILTER (WHERE ace_physical_abuse AND ace_score >= 4)::float8 AS ace_physical_abuse_s,
COUNT(*) FILTER (WHERE ace_sexual_abuse IS NOT NULL AND ace_score >= 4)::int AS ace_sexual_abuse_n,
SUM(weight) FILTER (WHERE ace_sexual_abuse IS NOT NULL AND ace_score >= 4)::float8 AS ace_sexual_abuse_w,
SUM(weight) FILTER (WHERE ace_sexual_abuse AND ace_score >= 4)::float8 AS ace_sexual_abuse_s,
COUNT(*) FILTER (WHERE ace_emotional_neglect IS NOT NULL AND ace_score >= 4)::int AS ace_emotional_neglect_n,
SUM(weight) FILTER (WHERE ace_emotional_neglect IS NOT NULL AND ace_score >= 4)::float8 AS ace_emotional_neglect_w,
SUM(weight) FILTER (WHERE ace_emotional_neglect AND ace_score >= 4)::float8 AS ace_emotional_neglect_s,
COUNT(*) FILTER (WHERE ace_physical_neglect IS NOT NULL AND ace_score >= 4)::int AS ace_physical_neglect_n,
SUM(weight) FILTER (WHERE ace_physical_neglect IS NOT NULL AND ace_score >= 4)::float8 AS ace_physical_neglect_w,
SUM(weight) FILTER (WHERE ace_physical_neglect AND ace_score >= 4)::float8 AS ace_physical_neglect_s,
COUNT(*) FILTER (WHERE ace_witnessed_violence IS NOT NULL AND ace_score >= 4)::int AS ace_witnessed_violence_n,
SUM(weight) FILTER (WHERE ace_witnessed_violence IS NOT NULL AND ace_score >= 4)::float8 AS ace_witnessed_violence_w,
SUM(weight) FILTER (WHERE ace_witnessed_violence AND ace_score >= 4)::float8 AS ace_witnessed_violence_s,
COUNT(*) FILTER (WHERE ace_household_depression IS NOT NULL AND ace_score >= 4)::int AS ace_household_depression_n,
SUM(weight) FILTER (WHERE ace_household_depression IS NOT NULL AND ace_score >= 4)::float8 AS ace_household_depression_w,
SUM(weight) FILTER (WHERE ace_household_depression AND ace_score >= 4)::float8 AS ace_household_depression_s,
COUNT(*) FILTER (WHERE ace_incarceration IS NOT NULL AND ace_score >= 4)::int AS ace_incarceration_n,
SUM(weight) FILTER (WHERE ace_incarceration IS NOT NULL AND ace_score >= 4)::float8 AS ace_incarceration_w,
SUM(weight) FILTER (WHERE ace_incarceration AND ace_score >= 4)::float8 AS ace_incarceration_s,
COUNT(*) FILTER (WHERE ace_substance_abuse IS NOT NULL AND ace_score >= 4)::int AS ace_substance_abuse_n,
SUM(weight) FILTER (WHERE ace_substance_abuse IS NOT NULL AND ace_score >= 4)::float8 AS ace_substance_abuse_w,
SUM(weight) FILTER (WHERE ace_substance_abuse AND ace_score >= 4)::float8 AS ace_substance_abuse_s,
COUNT(*) FILTER (WHERE ace_divorce IS NOT NULL AND ace_score >= 4)::int AS ace_divorce_n,
SUM(weight) FILTER (WHERE ace_divorce IS NOT NULL AND ace_score >= 4)::float8 AS ace_divorce_w,
SUM(weight) FILTER (WHERE ace_divorce AND ace_score >= 4)::float8 AS ace_divorce_s
FROM respondents
GROUP BY GROUPING SETS ((state_fips), (sex), (age_group), (race), (education), (income), ())No bound parameters; this scan is unfiltered.
| Step | Quantity | Value |
|---|---|---|
| 1 | Unweighted count score_n | 673,232 |
| 2 | Weighted numerator w_ge4 | 78488509.25830142 |
| 3 | Weighted denominator score_w | 445428544.7320121 |
| 4 | Quotient (unrounded) | 0.176208979390 |
| 5 | Suppression check | publish (n = 673,232 >= 30) |
| 6 | Rounded to 4 decimals | 0.1762 |
| 7 | As displayed: Map tile and demographic bar rows (unit lives in the legend / column header) | 17.6 |
| 8 | As displayed: Hover probe and state card (unit inline) | 17.6% |
Self-check: this ledger’s result equals the production API value for the same scope. Recomputed and compared as the page rendered.
Suppression fires on the unweighted count, so small cells exist in every seed. This one is live from Puerto Rico’s default-scope scan: Income = $150-200K, average ACE score. Your own run WILL produce a value here; we deliberately publish neither the value nor its weighted sums, since at small n those sums approach an individual respondent’s own survey weight. The ledger shows the n and the decision, which is everything a replication needs to confirm the rule fired.
| Step | Quantity | Value |
|---|---|---|
| 1 | Unweighted count score_n | 16 |
| 2 | Weighted numerator score_ws | withheld (below the publication threshold, same rule as the value) |
| 3 | Weighted denominator score_w | withheld (below the publication threshold, same rule as the value) |
| 4 | Quotient (unrounded) | withheld (below the publication threshold, same rule as the value) |
| 5 | Suppression check | suppress (n = 16 < 30) |
| 6 | Rounded to 3 decimals | null |
| 7 | As displayed: Map tile and demographic bar rows (unit lives in the legend / column header) | -- |
| 8 | As displayed: Hover probe and state card (unit inline) | -- |
Self-check: this ledger’s result equals the production API value for the same scope. Recomputed and compared as the page rendered.
The Compare view computes both axes in one per-state statement; x and y have independent denominators and suppression counts. National ledgers for Percent of adults with 4+ ACEs (x) versus Depression (y):
These are age-adjusted estimates, Compare’s default. The statement’s inner query (strata) is the crude scan with the age group added to every grouping set; the outer query averages each ratio over the age groups on the standard population listed in its VALUES clause. Counts and denominators come back as plain sums, so they are the crude ones; each numerator comes back as the adjusted rate times that denominator, so the same quotient applies. Add adj=crude to this page’s address to see the crude statement instead.
WITH strata AS (
SELECT state_fips,
GROUPING(state_fips)::int AS gset,
std_age,
SUM(weight) FILTER (WHERE ace_score >= 4)::float8 AS x_num,
SUM(weight) FILTER (WHERE ace_score IS NOT NULL)::float8 AS x_den,
COUNT(*) FILTER (WHERE ace_score IS NOT NULL)::int AS x_n,
SUM(weight) FILTER (WHERE depression IS TRUE AND ace_score >= 4)::float8 AS y_num,
SUM(weight) FILTER (WHERE depression IS NOT NULL AND ace_score >= 4)::float8 AS y_den,
COUNT(*) FILTER (WHERE depression IS NOT NULL AND ace_score >= 4)::int AS y_n
FROM (SELECT *, age_group::text AS std_age FROM respondents) AS respondents
GROUP BY GROUPING SETS ((state_fips, std_age), (std_age))
)
SELECT state_fips, gset,
SUM(x_n)::int AS x_n,
SUM(x_den)::float8 AS x_den,
(CASE WHEN COUNT(*) FILTER (WHERE x_den > 0) = 6
THEN POWER(SUM(std.pop) FILTER (WHERE x_den > 0), 2) / SUM(POWER(std.pop, 2) / NULLIF(x_n, 0))
ELSE 0 END)::float8 AS x_n_eff,
(SUM(x_den) * SUM(std.pop * COALESCE(x_num, 0) / NULLIF(x_den, 0))
/ NULLIF(SUM(std.pop) FILTER (WHERE x_den > 0), 0))::float8 AS x_num,
SUM(y_n)::int AS y_n,
SUM(y_den)::float8 AS y_den,
(CASE WHEN COUNT(*) FILTER (WHERE y_den > 0) = 6
THEN POWER(SUM(std.pop) FILTER (WHERE y_den > 0), 2) / SUM(POWER(std.pop, 2) / NULLIF(y_n, 0))
ELSE 0 END)::float8 AS y_n_eff,
(SUM(y_den) * SUM(std.pop * COALESCE(y_num, 0) / NULLIF(y_den, 0))
/ NULLIF(SUM(std.pop) FILTER (WHERE y_den > 0), 0))::float8 AS y_num
FROM strata
JOIN (VALUES ('18_24', 26258), ('25_34', 37233), ('35_44', 44659), ('45_54', 37030), ('55_64', 23961), ('65_plus', 34710)) AS std(age, pop) ON std.age = strata.std_age
GROUP BY state_fips, gsetNo bound parameters; this scan is unfiltered.
| Step | Quantity | Value |
|---|---|---|
| 1 | Unweighted count x_n | 673,232 |
| 2 | Age-standardised numerator x_num (adjusted rate × the denominator below) | 84490127.21653637 |
| 3 | Weighted denominator x_den | 445428544.7320446 |
| 4 | Quotient (unrounded): the adjusted rate | 0.189682785748 |
| 5 | Suppression check | publish (n = 673,232 and effective n = 457,905, both >= 30) |
| 6 | Rounded to 4 decimals | 0.1897 |
| 7 | As displayed: Compare hover probe (a classed bivariate tile prints no number; see the encoding section) | 19.0% |
Self-check: this ledger’s result equals the production API value for the same scope. Recomputed and compared as the page rendered.
| Step | Quantity | Value |
|---|---|---|
| 1 | Unweighted count y_n | 91,763 |
| 2 | Age-standardised numerator y_num (adjusted rate × the denominator below) | 28498322.75065141 |
| 3 | Weighted denominator y_den | 73312332.17942132 |
| 4 | Quotient (unrounded): the adjusted rate | 0.388724814823 |
| 5 | Suppression check | publish (n = 91,763 and effective n = 85,116, both >= 30) |
| 6 | Rounded to 4 decimals | 0.3887 |
| 7 | As displayed: Compare hover probe (a classed bivariate tile prints no number; see the encoding section) | 38.9% |
Self-check: this ledger’s result equals the production API value for the same scope. Recomputed and compared as the page rendered.
The population decides every band in this scope (adults with an ACE score of 4 or more), so the card blanks all four rows and there is no ledger to show. See the co-occurrence formulas above.
P_k = n_k / (n_1 + n_2), CDC’s rule for combining versions._LLCPWT or _FINALWT for a main file; a version or landline file carries only its own).ACEDEPRS, ACEDRINK, ACEDRUGS, ACEPRISN, ACEDIVRC, ACEPUNCH, ACEHURT1, ACESWEAR, ACETOUCH, ACETTHEM, ACEHVSEX).Do not expect standard errors to match anything: we publish none. The design variables (
_STSTR,_PSU) are not extracted, so nothing on the dashboard carries design-based variance; then < 30suppression rule is the only reliability guard. Weighted point estimates are the comparison target.
Skip the 32 downloads by using the committed prisma/data/brfss-ace.csv.gz (verify its SHA-256 against the provenance banner). Its header, rendered from the transform that reads it:
year,state,sex,age_group,race,education,income,ace_depressed,ace_alcoholic,ace_drugs,ace_prison,ace_divorce,ace_punch,ace_hurt,ace_swear,ace_touch,ace_touched,ace_sex,ace_safe,ace_needs,general_health,mental_health_days,physical_health_days,depression,smoking_status,smoking_current,bmi_category,heavy_drinker,binge_drinker,physical_activity,health_insurance,cost_barrier,diabetes,heart_disease,heart_attack,angina_chd,stroke,asthma,copd,kidney_disease,arthritis,skin_cancer,other_cancer,weightCells are raw BRFSS codes as extracted (blank = never asked), each state-year already taken from its one source file (steps 2-4). The weight cell is that file’s own weight, already multiplied by the version share for the two-version state-years; the file has no source column, so use coverage.csv’s to see which file and weight a state-year carries. Steps 5-7 still apply.
age=25_34 and so on), for every Explore metric. The link above carries this page’s current scope, so re-scope the page and download again to get a different population or filter set.weight_withheld flag but no weight, since at that size the pooled weight approaches a single respondent’s own. The counts are never withheld.R (one year, 2023, one indicator; pool years by concatenating before the ratio). The file names, state codes and weights are generated from the same registries the extractor runs on, so they are that year’s actual sources:
library(haven)
library(dplyr)
ace_vars <- c("ACEDEPRS","ACEDRINK","ACEDRUGS","ACEPRISN","ACEDIVRC",
"ACEPUNCH","ACEHURT1","ACESWEAR","ACETOUCH","ACETTHEM",
"ACEHVSEX","ACEADSAF","ACEADNED")
# One year (2023). Each state-year comes from ONE file, weighted by that
# file's own final weight: the main file, except for the split-sample states,
# whose answers are in a questionnaire-version file. Repeat per year with that
# year's files (the source table) and pool (no weight renormalization).
part <- function(file, weight, keep) {
read_xpt(file) %>%
filter(keep(`_STATE`)) %>%
select(`_STATE`, any_of(ace_vars), w = all_of(weight))
}
d <- bind_rows(
part("LLCP2023.XPT", "_LLCPWT", function(s) !(s %in% c(24, 39))),
part("LLCP23V1.XPT", "_LCPWTV1", function(s) s %in% c(39)), # OH
part("LLCP23V3.XPT", "_LCPWTV3", function(s) s %in% c(24)) # MD
)
# Asked population: any ACE item non-missing (7/9 refusals are NOT missing).
asked <- d %>% filter(if_any(any_of(ace_vars), ~ !is.na(.x)))
# One indicator, e.g. emotional abuse (ACESWEAR, frequency item):
emo <- asked %>%
mutate(flag = case_when(ACESWEAR %in% c(2, 3) ~ TRUE,
ACESWEAR == 1 ~ FALSE,
TRUE ~ NA)) %>%
filter(!is.na(flag))
emo %>% summarise(prevalence = sum(w[flag]) / sum(w))SAS skeleton:
/* Same shape in SAS: one year, each state-year from ONE file with that file's
own weight, then a weighted ratio. No PROC SURVEYFREQ variance will match
ours, because we publish none. */
data emo;
set llcp2023 (in=f0) llcp23v1 (in=f1) llcp23v3 (in=f2);
if f0 then do; if _STATE in (24, 39) then delete; w = _LLCPWT; end;
if f1 then do; if _STATE not in (39) then delete; w = _LCPWTV1; end; /* OH */
if f2 then do; if _STATE not in (24) then delete; w = _LCPWTV3; end; /* MD */
if n(of ACEDEPRS ACEDRINK ACEDRUGS ACEPRISN ACEDIVRC ACEPUNCH ACEHURT1
ACESWEAR ACETOUCH ACETTHEM ACEHVSEX ACEADSAF ACEADNED) = 0 then delete;
if ACESWEAR in (2, 3) then flag = 1;
else if ACESWEAR = 1 then flag = 0;
else delete;
run;
proc means data=emo mean;
var flag;
weight w; /* weighted mean of flag = the prevalence */
run;A sanity check, not a validation: given the enumerated design differences (year windows, state sets), agreement within a few points is the expected outcome, and exact agreement would itself be suspicious. Every “ours” value is computed live from the current seed (national, all respondents, no filters); published values were verified against the corrected primary sources on the retrieval date shown. Neither source age-adjusts: both report crude weighted estimates (re-read for this on 2026-11-09), as we do here, so no row compares an adjusted figure with a crude one.
| Statistic | Ours (live) | Published | Source | Published scope | Expected difference, and why |
|---|---|---|---|---|---|
| Percent of adults with 1+ ACEs | 64.4% | 63.9% | Swedo et al., MMWR 2023 (doi:10.15585/mmwr.mm7226a2; retrieved 2026-11-09) | 50 states + DC, one survey year per jurisdiction (2011-2020, most 2019-2020), 8 ACE categories from 11 items, complete case, N = 264,882. | Close agreement expected. Swedo takes one year per jurisdiction across 50 states + DC; we pool each participating state's years with a smaller state set. We score the same 8 categories from the same 11 items, but pool 2009-2012 with 2019-2024, with most of the weight in the later years. The physical-abuse item reads about 9 points lower pre-2013 (a break in series; see the limitations register), which drags pooled score-based estimates slightly below a 2019-2024-only figure. |
| Percent of adults with 4+ ACEs | 17.6% | 17.3% | Swedo et al., MMWR 2023 (doi:10.15585/mmwr.mm7226a2; retrieved 2026-11-09) | 50 states + DC, one survey year per jurisdiction (2011-2020, most 2019-2020), 8 ACE categories from 11 items, complete case, N = 264,882. | Close agreement expected. Our window runs through 2024, when several items read higher than in Swedo's mostly 2019-2020 years, while our pre-2013 years pull the other way. We score the same 8 categories from the same 11 items, but pool 2009-2012 with 2019-2024, with most of the weight in the later years. The physical-abuse item reads about 9 points lower pre-2013 (a break in series; see the limitations register), which drags pooled score-based estimates slightly below a 2019-2024-only figure. |
| Percent of adults with 1+ ACEs | 64.4% | 61.55% | Merrick et al., JAMA Pediatrics 2018 (doi:10.1001/jamapediatrics.2018.2537; retrieved 2026-07-30) | 23 states, 2011-2014 (some states multiple years), 8 ACE categories, N = 214,157. | Ours should read HIGHER: Merrick's window is 2011-2014, and our 2019-2024 years read higher than our 2009-2012 ones. We score the same 8 categories from the same 11 items, but pool 2009-2012 with 2019-2024, with most of the weight in the later years. The physical-abuse item reads about 9 points lower pre-2013 (a break in series; see the limitations register), which drags pooled score-based estimates slightly below a 2019-2024-only figure. |
| Average ACE score | 1.7 | 1.57 | Merrick et al., JAMA Pediatrics 2018 (doi:10.1001/jamapediatrics.2018.2537; retrieved 2026-07-30) | 23 states, 2011-2014 (some states multiple years), 8 ACE categories, N = 214,157. | Ours should read HIGHER: Merrick's window is 2011-2014, and our 2019-2024 years read higher than our 2009-2012 ones. We score the same 8 categories from the same 11 items, but pool 2009-2012 with 2019-2024, with most of the weight in the later years. The physical-abuse item reads about 9 points lower pre-2013 (a break in series; see the limitations register), which drags pooled score-based estimates slightly below a 2019-2024-only figure. |
| Emotional/Verbal Abuse | 36.0% | 34.0% | Swedo et al., MMWR 2023 (doi:10.15585/mmwr.mm7226a2; retrieved 2026-11-09) | 50 states + DC, one survey year per jurisdiction (2011-2020, most 2019-2020), 8 ACE categories from 11 items, complete case, N = 264,882. | Near-identical definitions (the single ACESWEAR item), so this row should agree within a couple of points; the difference is year window and state mix. Ours should read somewhat HIGHER: our window runs through 2024, and the item reads higher in 2021-2024 than in Swedo's mostly 2019-2020 years. |
| Physical Abuse | 24.6% | 23.3% | Swedo et al., MMWR 2023 (doi:10.15585/mmwr.mm7226a2; retrieved 2026-11-09) | 50 states + DC, one survey year per jurisdiction (2011-2020, most 2019-2020), 8 ACE categories from 11 items, complete case, N = 264,882. | Same single item (ACEHURT/ACEHURT1), so the rows should agree within a couple of points. Ours should read slightly HIGHER: the item reads higher in 2021-2024 than in Swedo's mostly 2019-2020 years, partly offset by the item's lower-reading pre-2013 era (the break in series in the limitations register). |
| Witnessed Intimate Partner Violence | 17.6% | 17.2% | Swedo et al., MMWR 2023 (doi:10.15585/mmwr.mm7226a2; retrieved 2026-11-09) | 50 states + DC, one survey year per jurisdiction (2011-2020, most 2019-2020), 8 ACE categories from 11 items, complete case, N = 264,882. | Same single item (ACEPUNCH), worded identically across every year we pool, so this row should agree within a point or two; the difference is year window and state mix. |
Full citations: Swedo EA, Aslam MV, Dahlberg LL, Holditch Niolon P, Guinn AS, Simon TR, Mercy JA. Prevalence of Adverse Childhood Experiences Among U.S. Adults, Behavioral Risk Factor Surveillance System, 2011-2020. MMWR Morb Mortal Wkly Rep 2023;72(26):707-715. Merrick MT, Ford DC, Ports KA, Guinn AS. Prevalence of Adverse Childhood Experiences From the 2011-2014 Behavioral Risk Factor Surveillance System in 23 States. JAMA Pediatr 2018;172(11):1038-1044.
No standard errors, confidence intervals, or design effects appear anywhere; the design variables (_STSTR, _PSU) are never extracted. Every number is a weighted point estimate presented as exact, and the n < 30 suppression rule is the only reliability guard. Do not run significance tests against these values; return to the raw files for design-based variance.
Each state contributes every year it fielded the module (1 to 7 years across the 49 participating jurisdictions; the full state-year grid, with the file each state-year was read from, is in coverage.csv). Each file’s weight is calibrated to the whole state’s adults, whichever file a state-year comes from; the respondents who reached the module carry most of that total but not all (interviews that ended before it are excluded), and the state-years are pooled without renormalization, so state comparisons partially reflect when each state ran the module, and weighted totals are not population counts.
| Jurisdiction | Years in the data |
|---|---|
| Alabama | 2019, 2020, 2021 |
| Arizona | 2020, 2022 from version 1, 2024 from version 2 |
| Arkansas | 2009, 2021, 2022 |
| California | 2011 from landline versions 1+2 (rescaled), 2020 from version 2 |
| Delaware | 2019, 2023 |
| District of Columbia | 2010, 2020 |
| Florida | 2019, 2020, 2022, 2023, 2024 |
| Georgia | 2020, 2023, 2024 |
| Hawaii | 2010, 2020, 2024 |
| Idaho | 2020 |
| Indiana | 2019 |
| Iowa | 2012, 2019, 2020, 2021, 2022, 2024 from version 1 |
| Kansas | 2019 from version 2, 2020 from version 2, 2021 from version 1 |
| Kentucky | 2020 |
| Louisiana | 2009 |
| Maine | 2010 from version 2, 2011 from landline version 1, 2021 from version 1, 2024 from version 1 |
| Maryland | 2020 from version 3, 2023 from version 3 |
| Massachusetts | 2020 from version 1 |
| Michigan | 2019 |
| Minnesota | 2011 |
| Mississippi | 2019, 2020, 2021 |
| Missouri | 2019, 2020, 2023 |
| Montana | 2011, 2020 |
| Nebraska | 2010 from version 3, 2011 from landline versions 1+2 (rescaled) |
| Nevada | 2010, 2011 from landline file, 2020, 2021, 2022, 2023, 2024 |
| New Hampshire | 2021 |
| New Jersey | 2020 from version 2, 2021 from version 2, 2022 from version 2, 2023 |
| New Mexico | 2009 from version 1, 2019 |
| New York | 2019 from version 3, 2021 from version 1 |
| North Carolina | 2012 |
| North Dakota | 2019, 2020, 2021, 2022, 2024 |
| Ohio | 2010 from version 2, 2019 from version 1, 2021 from version 1, 2022 from version 1, 2023 from version 1, 2024 from version 1 |
| Oklahoma | 2012 from version 2, 2019 from version 2, 2020 from version 2, 2022 from version 2, 2024 from version 2 |
| Oregon | 2011 from landline file, 2021, 2022, 2023 |
| Pennsylvania | 2010 from version 1, 2019 |
| Rhode Island | 2019, 2020, 2023 |
| South Carolina | 2019, 2020, 2021 |
| South Dakota | 2020, 2022 |
| Tennessee | 2009 from version 1, 2012, 2019, 2023 |
| Texas | 2020 |
| Utah | 2010 from version 3, 2020 |
| Vermont | 2010, 2011 |
| Virginia | 2019, 2020, 2021, 2022, 2023, 2024 |
| Washington | 2009 from version 1, 2010 from version 1, 2011 |
| West Virginia | 2019 |
| Wisconsin | 2010, 2011, 2012, 2019, 2020, 2021 |
| Wyoming | 2020 |
| Puerto Rico | 2024 |
| Virgin Islands | 2024 |
The score is null unless all 11 items are valid, so score-based metrics (average, the bands) cover a narrower and potentially non-random subset than the indicator metrics, each of which uses its own valid-response base. Module completion quantifies exactly this gap, per state, on the dashboard.
The CDC renamed the physical-abuse item between eras (ACEHURT in 2009-2012, ACEHURT1 from 2019), and the two eras do not read alike: endorsement is about 9 percentage points lower pre-2013 even within the 16 jurisdictions present in both eras (16.1% vs 25.3% unweighted, 2009-2012 vs 2019-2024; every one of the 16 jumps 7-13 points). ACEPUNCH (witnessed intimate partner violence), the adjacent question on the same scale, barely moves (+0.8 points), and no other ACE item rises more than 4.6 (parental divorce, about half the jump), so this is specific to the one renamed item, not a cohort or mode story. Nor is it the 2011 landline-only rows: without them the gap is 9.5 points. Physical abuse is scored from this item alone, so the indicator carries the full jump. These figures were measured on 2026-09-22, after the split-sample state-years were added, and re-derived unchanged on 2026-11-09; the 2026-07-30 audit, with eight states then in both eras, found 15.2% vs 23.9% on a sample of the raw files with 2019-2021 as the later era. CDC’s national codebook margins show the same pattern (17.9% endorsed in 2011 vs 24.5% in 2019, while ACEPUNCH sits at 17.0% in both).
The cause is a confirmed rewording, verified against the archived CDC questionnaires for 2009-2012 and 2019-2021. The early item reads: “Before age 18, how often did a parent or adult in your home ever hit, beat, kick, or physically hurt you in any way? Do not include spanking. Would you say--”. The 2019+ item reads: “Not including spanking, (before age 18), how often did a parent or adult in your home ever hit, beat, kick, or physically hurt you in any way? Was it--”. The spanking exclusion moved from a standalone sentence heard immediately before answering to a clause at the front of a long sentence, and the age frame became a parenthetical (optional for the interviewer to read). The direction of the jump is consistent with the exclusion losing salience, though no published split-ballot experiment quantifies this change; the module preamble, item order, response scale, and surrounding items are verbatim identical across eras, ruling the alternatives out. CDC’s own pooled publications (including Swedo et al. 2023) mix the two versions without a comparability note.
Weighted effect of pooling the eras here: mean ACE score 1.746 for 2019-2024 alone against 1.704 pooled, physical-abuse prevalence 26.6% against 24.6%. (The audit of 2026-07-30, before the split-sample state-years were added and on the old 7-category score, measured 1.634 to 1.605 and 32.0% to 30.8%.) Score-based and physical-abuse estimates blend two versions of this item; era-restricted replications will not match pooled values exactly.
Age sits on both sides of this dashboard. Reported ACEs fall with age (the mean ACE score is 2.12 among adults 18-24 and 1.06 among adults 65 and over), while most long-term conditions rise with it. Jurisdictions differ in age mix, and so do the survey years, so a crude gap between two states or two periods is partly a gap in who was young and who was old. Of two states with identical rates at every age, the older one reads lower on ACE measures and higher on long-term conditions.
Every number on Explore is crude: a weighted proportion or mean, not standardised to a common age distribution. That is the right figure for how common something is in a state, and the wrong one for ranking states. To compare states on Explore, filter to one age group or read the age breakdown; each holds age roughly constant.
Compare is age-adjusted by default (direct standardisation to the 2000 U.S. standard population; see the formulas), because there age moves both axes at once and both sides of the co-occurrence card: adults with a condition of older age are older on average than adults without it, and older adults report fewer ACEs, which narrows a crude gap for those conditions and widens it for behaviours of younger age. Its switch to crude shows the figures as surveyed. Three consequences to keep in mind:
The two published sources in the cross-checks above report crude estimates, and those rows read Explore’s crude scan, so they are like for like.
| What we do | Why | What a replication must do |
|---|---|---|
| Suppression at unweighted n < 30, applied after aggregation. | Small-cell estimates are unreliable; a single fixed rule is auditable. | Suppressed is not empty: the n is published so you can tell a withheld value (n > 0) from no data (n = 0). |
| Income eras are never unioned: 75k_plus exists only through 2020, the finer 75k+ buckets only from 2021. | INCOME2 code 8 and INCOME3 code 8 mean different things. | Filtering on 75k_plus implicitly selects 2009-2020 respondents; the fine buckets select 2021+. |
| 2022 moved melanoma out of the skin-cancer item (CHCSCNC1) and into other cancer (CHCOCNC1), so the two items measure slightly different things either side of that year. | A CDC questionnaire change: from 2022 the skin item asks about skin cancer that is not melanoma, and the other-cancer item names melanoma explicitly. | Do not expect to find this by splitting the pooled series at 2022. Our post-2022 respondents are older, and because skin-cancer prevalence rises steeply with age that composition shift lifts the crude skin-cancer rate by roughly as much as the reclassification lowers it, leaving the crude series looking almost flat while the reclassification is plainly visible within age groups. Compare within age group, and within states present on both sides, or simply treat the two eras as different measures. |
| Heart disease for 2009-2012 is OUR derivation: CDC's calculated _MICHD exists only from 2019, so its own definition (MI or CHD) is applied to its two inputs, CVDINFR4 and CVDCRHD4. | The inputs exist in every year; the calculated variable does not. | The derivation agrees with _MICHD on all 553,160 rows where both exist (measured on the extract of 2026-09-22), but it is our computation and a replication must apply the same rule (either input yes = case; both no = non-case; else excluded). |
| 2023-2024 have no yes/no insurance question; no-insurance is collapsed from the 13-value PRIMINS source-of-coverage item (codes 1-10 = insured, 88 = none). | CDC dropped the yes/no item after 2022. | The collapse reproduces CDC's own calculated _HLTHPLN exactly where both exist; replicate the collapse, not a yes/no read of PRIMINS. |
| The heavy-drinking and binge-drinking definitions changed thresholds across CDC's renames (_RFDRHV3 through _RFDRHV9; _RFBING4 through _RFBING6) even though the response codes match. | CDC revised the drink-count cutoffs behind the calculated flags over the years. | Treat these two series as definition-drifting across years; per-year comparisons are safe, pooled levels blend definitions. |
| Some outcomes were optional modules or absent in early years: depression is absent entirely in 2009 and optional in 2010 (a valid answer from 41% of that year's ACE respondents); arthritis was optional in 2010 (7% coverage); COPD, kidney disease, and both cancer items were not asked before 2011. | BRFSS module participation varied by state and year. | The coverage matrix above shows the exact percentages; low-coverage year cells change which states contribute to that outcome's pooled estimate. |
| Territories are included: District of Columbia, Puerto Rico, and Virgin Islands are in the data alongside the states (Guam is seeded but has no ACE data). | They fielded the module; excluding them would be a silent editorial choice. | Our national total is not a 50-state total. See coverage.csv for who contributed. |
| 41 state-years come from a questionnaire-version or landline file instead of CDC's main annual file, including every year of California, Kansas, Maine, Maryland, Massachusetts, Nebraska, New York, Ohio, and Oklahoma. Those states asked the ACE module on only some versions of their questionnaire (a split sample), or in 2011 on the landline survey only, so their answers come from the respondents given those versions alone, each weighted by its own file's weight. | CDC's own procedure: it blanks a split-sample module's answers in the main file and publishes them per version, with a weight that projects the subsample onto the state's whole adult population. Reading main files only would drop those state-years, and whole states, for no reason but file layout. | Read each one from the file(s) the pipeline's source table names, with that file's weight, and never also from the main file (Oklahoma 2012's answers are in both). A subsample is a fraction of the state's respondents, so these state-years carry more sampling error than the state's size suggests. coverage.csv gives each state-year's source file, weight variable, and row count. |
| Every 2011 split-sample row (California, Maine, Nebraska, Nevada, and Oregon) is a landline respondent: CDC's 2011 questionnaire versions, like its LAND2011 file, cover the landline survey only. | That is how CDC published those states' 2011 module; their cell-phone samples were not asked it. CDC still weights the landline respondents to the whole state's adults, cell-only adults included. | These state-years differ in survey mode from every other 2011-onward state-year. A replication that wants a dual-frame basis throughout must drop them (coverage.csv source beginning “landline”). |
| California 2011 has no ACE-8 score and no incarceration indicator: neither of its questionnaire versions asked ACEPRISN. | A gap in the questionnaire, not nonresponse. Scoring is complete-case over all 11 items, so no California 2011 respondent can be scored, while its other six categories still count toward their own indicators. | Expect about 9,500 California 2011 respondents in the other indicator prevalences, and none in any score-based metric, in incarceration, or in the module-completion base (n_asked 0 in coverage.csv). About 1,600 more of its rows have no usable answer for any category, nearly all coded 9 on every item, apparently California's code for respondents the module never reached. The asked-population rule keeps them because 9 is not blank. With no valid ACE answer they enter no indicator, score or completion figure, but their core answers still count in California's Compare values for health outcomes, education and income under "Any ACE score", which divides by every row with a valid answer, and their weight is in the state-year's totals in coverage.csv. The same rule keeps smaller groups of whole-module refusers in other state-years. |
| Age uses the 6-band _AGE_G collapse. | The dashboard's demographic cards were designed around six bands. | Rebuild age groups from _AGE_G, not the 5-year bands, or the cells will not match. |
| ACEDIVRC code 8 (parents never married) is invalid, not a No. | Matches the legacy app and Swedo et al.'s published handling. | Treating 8 as No inflates the divorce denominator and deflates the whole-score missingness; copy our rule exactly. |
| Frequency items count code 2 (Once) as endorsed. | Standard BRFSS ACE practice; a threshold choice all the same. | Endorse at >= 2, not > 2. |
| Null demographics are dropped from breakdowns, never shown as an Unknown row. | The dashboard's cards enumerate known categories only. | Demographic rows do not sum to the total. |
| The two neglect indicators and the expanded 10-item score live on a restricted basis: the reverse-coded neglect items (ACEADSAF/ACEADNED) were fielded 2021-2024 by 29 of the 49 ACE jurisdictions. The pooled ACE-8 score never touches them. | BRFSS added the items in 2021 and only some states ran them; scoring them separately keeps ACE-8 comparable across all years. | Endorse neglect at codes 1-2 of the reverse 1-5 scale (CDC's cut; 3 is neither pole). Never compare an expanded-score or neglect number against a pooled metric. Note that the state and year restrictions are ONE restriction, not two: every jurisdiction that ran the ACE module at all in 2021-2024 also ran the neglect items, in every year it participated, so the 29 are exactly the jurisdictions present in those years. Restricting by state and restricting by year select the same rows. |
| The neglect items are held to a far stricter threshold than the other eleven, and the gap is not a finding about the population. | CDC's own coding, followed here. MMWR Suppl 2024;73(4) Table 1 codes neglect as exposed at 'never or rarely' while coding abuse as exposed at 'rarely' and above, in one table on one scale for one set of respondents, footnoting that the neglect cut aligns with previously published neglect measures. | The six frequency items endorse at "Once" (a single lifetime occurrence) and the five binary items at "ever", while the two neglect items endorse only at the bottom two of a five-point scale asking for how much of childhood a protective adult was present. So emotional/verbal abuse means sworn at once and emotional neglect means a near-total absence of a protective adult. Do not read the difference in magnitude as neglect being rarer than abuse. Equalising the basis does not close it either: on the shared 13-item base emotional neglect reads 6.6% against emotional abuse's 36.3%, both measured on that same base rather than on the 7.3% and 36.0% the bars publish. For scale, moving the neglect cut to codes 1-3 would give 13.4% and 7.2% and lift the ACE-10 mean from 1.907 to 1.993 (measured on 2026-11-09 from the extract of 2026-09-22), but no published analysis uses that cut. |
| The "Any ACE score" population applies no filter at all, so every indicator's denominator is wider than the scored base and the two score-group populations together cover fewer respondents than their own parent. | Restricting indicator prevalences to a complete 11-item score would be listwise deletion: refusing any one item nulls the score while leaving the other categories perfectly valid, and dropping those respondents biases every prevalence downward. | Roughly 76,000 respondents with no valid ace_score sit inside at least one indicator denominator (emotional abuse divides by about 732k against the scored base's 673k); about 9,500 of them are California 2011 respondents, who cannot be scored at all. Each indicator's denominator is its own valid responders, never ace_score IS NOT NULL. A score-group population, by contrast, IS complete-case, because its band excludes nulls either way. |
| Five outcomes carry a shorter series than the rest: depression starts in 2010, and COPD, kidney disease, skin cancer and other cancer start in 2011. | Those items were not fielded (or not under a resolvable variable) in the earliest ACE years; the pipeline nulls them rather than inventing a value. | Each divides by its own valid responders like every other measure, so the numbers are right, but they rest on 48 of the 49 jurisdictions rather than all 49. The missing one is Louisiana, which ran the ACE module in 2009 only: that is before any of the five begins, so its absence follows from the year ranges alone and needs no further explanation. Expect about 670k valid responses for each of the four that start in 2011, against about 757k for an outcome with a full series such as diabetes. Note separately that 2010 depression was optional and reaches 41% of that year's rows, so a short series is not always a complete one. |
| Refusers (codes 7/9) are in the asked base but excluded from every indicator's valid base. | Refusal is nonresponse, not a No; module completion exists to measure it. | Each indicator has its own denominator; never reuse one common denominator. |
| Seed drops rows only for unknown state FIPS or missing/non-positive weight. | Everything else nulls a field and keeps the row. | Reconcile row counts against the provenance banner's loaded/skipped figures. |
| Compare's no-outcome requires only one valid outcome response with none positive. | Requiring all 19 valid would empty the composite in sparse years. | A respondent with one valid No and 18 nulls counts as no outcome; composites mix each outcome's coverage window. |
Every data payload (and this page) is keyed by an opaque version, currently 9: the id of the latest seed run. A reseed (new data, or a transform change that bumps TRANSFORM_VERSION) mints a new id, so a given versioned URL is immutable and two people looking at the same version are looking at identical numbers. The provenance banner’s SHA-256 and transform version pin what this version was built from.
The authoritative change record for the methodology is the git history of the extraction, transform and scoring modules (scripts/process-brfss.ts, src/lib/brfss/variable-mappings.ts, src/lib/brfss/split-sample.ts, src/lib/brfss/transform.ts, src/lib/brfss/scoring.ts, src/lib/queries/sql.ts). Every registry and formula rendered on this page is imported from that same code, so a rename or a changed rule reaches this page by construction rather than by anyone remembering to edit it.
Being precise about this matters more here than anywhere else on the page, because it is what a reader is entitled to assume when they take a number on trust:
npm test), which covers the pure modules behind those functions: scoring, recodes, suppression, formatting, classing, the URL codec, the CSV builders.*.dbtest.ts and run via npm run test:db. CI has no database and does not run them. They are a release gate, not a per-commit one, so a data-dependent claim on this page can in principle go stale between reseeds; the render-time self-checks above are what stand behind the numbers in the meantime._MICHD agreement count) need raw CDC item codes the database does not keep. Each names the extract it was measured on, and the test suite pins a live neighbour where one exists, so a reseed that moves it flags the dated figure for re-measurement.