← All studies · askamerica.ai

County-level "damaging" weather-event frequency, 2005-2024: no uniform national trend — a slight net decline nationally, but sharply divergent and mostly reporting-driven at the county/state level

NOAA/NCEI Storm Events Database (askamerica disasters.storm_events), county-type records with damage or casualties, 2005-2024

County-level "damaging" weather events, 2005-2024 NOAA/NCEI Storm Events Database, county-type (CZ_TYPE='C') records with damage or casualties > 0 Counties with declining trend (2005-2024) 1,826 of 3,236 (56%) vs 1,410 increasing (44%) National total, damaging county events 127,554 -> 111,813 -12.3% (2005-14 vs 2015-24) National annual count of damaging county-level storm events 0 5,000 10,000 15,000 20,000 Year Event count 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2008 and 2011 are outlier peak years (major tornado/hail outbreaks), not a steady baseline; they pull the 2005-14 decade average up. States with the largest INCREASE, 2005-14 -> 2015-24 0 2,000 4,000 6,000 8,000 10,000 State Event count PA NY NC WV MS AZ PR 2005-2014 2015-2024 States with the largest DECREASE, 2005-14 -> 2015-24 0 2,000 4,000 6,000 8,000 10,000 State Event count IA AR KS IL AL TX 2005-2014 2015-2024 AskAmerica · askamerica.ai
SVG

Summary

Nationally, county-level reports of damaging weather events (a storm-event record with property/crop damage or any death/injury, restricted to county-type NOAA reports) fell about 12% comparing 2005-2014 to 2015-2024 (127,554 to 111,813 events). But that national figure masks huge and opposite-signed swings underneath: across 3,236 counties with usable data, 56% show a declining 20-year trend and 44% show an increasing one — this is not a uniform national pattern of more or fewer damaging storms, it is a patchwork. Several states (Iowa, Arkansas, Kansas, Alabama, Illinois) show 45-70% declines in reported damaging events, while others (Puerto Rico, West Virginia, North Carolina, New York, Pennsylvania) show 40-165% increases over the same two decades. Critically, NOAA's own published documentation on this exact database states that severe-storm reporting "has not been uniform over time because of changes in forecast [office] verification and emphasis" — so a large share of both the sharp declines (Iowa, Arkansas) and the sharp increases seen here should be treated as candidate reporting-practice artifacts first, not confirmed changes in actual storm frequency, until checked against an independent physical measure (e.g., NWS radar-verified tornado/hail counts) county by county.

Data and method

Source: disasters.storm_events (NOAA/NCEI Storm Events Database), which the askamerica catalog documents as observed and contiguous 2004-2026 (1.42M rows). "Last twenty years" was operationalized as the 2005-2024 window — the most recent twenty fully-loaded calendar years (2004 sits just outside a clean 20-year span from today, and 2025-2026 are partial/in-progress years in this feed).

"Damaging weather event" was operationalized as a storm-event record with cz_type='C' (a county-level report, as opposed to an NWS-zone or marine report) AND at least one of: damage_property > 0, damage_crops > 0, deaths_direct/indirect > 0, or injuries_direct/indirect > 0. This is a reasonable proxy, not the literal FEMA/NOAA term "damaging weather event," which the corpus does not carry as a defined field (search_catalog's own unmatched-terms check confirmed "damaging" appears in no table/column description here).

Two independent methods were run so the headline does not rest on one arbitrary split: (1) a two-decade comparison (2005-2014 vs 2015-2024 event counts by county and by state), and (2) a full county-by-year linear regression slope over all 20 years, filling years with zero events where a county reported none, so a county's absence in a given year counts as zero rather than being silently dropped.

Exclusion, and what it costs: county_fips is null on 41.4% of all storm_events rows nationally — these are NWS zone-type ('Z') reports, which cover a broader area than one county and cannot be attributed to a specific county. Restricting to county-type ('C') records is a necessary exclusion for a county-grain question, but it is not a random subset: it is 41.4% is a fixed database-wide share, not a property that varies systematically by state in a way checked here, but the excluded zone-type events are simply invisible to this county-level trend and would need to be apportioned or analyzed separately for a complete picture of total storm activity.

County-level trend: split roughly 44/56, not a national direction

Running regr_slope of annual damaging-event count against year for every one of 3,236 counties with any county-type reporting activity (n=20 years each, zero-filled): 1,410 counties (44%) show a rising trend, 1,826 (56%) show a falling trend, with a median slope of about -0.012 events/year — essentially flat at the median, meaning the split is close to even and the tails carry the story.

Top 15 counties by steepest INCREASE in damaging-event frequency per year (min. 1 event/year average) included Maricopa County AZ (+3.98/yr), Jefferson County AL (+3.02/yr), Mohave County AZ (+2.92/yr), Colbert County AL (+2.46/yr), Allegheny County PA (+1.96/yr), Wake County NC (+1.95/yr), Davidson County TN (+1.92/yr), Marshall County WV (+1.83/yr), two Mississippi Delta counties, Broome County NY, Berks County PA, Barbour County AL, a Puerto Rico municipio, and San Bernardino County CA (+1.50/yr).

Top 15 counties by steepest DECREASE were overwhelmingly concentrated in Iowa (state FIPS 19): Polk County IA (-3.94/yr) led, followed by nine more Iowa counties, plus Jefferson County AL, Cook County IL, Tuscaloosa County AL, Jefferson County AL (again, different code), and one South Carolina county. The Iowa concentration — ten of the fifteen steepest-declining counties nationwide sitting in one state — is itself evidence pointing toward a state- or forecast-office-level change in reporting practice (e.g., a change in how a Weather Forecast Office logs hail/wind damage estimates) rather than ten counties independently experiencing a real drop in storm frequency at the same time.

State-level pattern: a real geographic split, but read the outliers as reporting-practice candidates

Aggregating to state level, the states with the largest declines in damaging-event counts (2005-14 to 2015-24) were Iowa (8,831 -> 2,654, -70%), Arkansas (4,697 -> 1,767, -62%), Kansas (2,903 -> 1,351, -53%), Illinois (4,026 -> 2,075, -48%), Alabama (5,665 -> 3,023, -47%), and Texas (8,000 -> 6,297, -21%). The states with the largest increases were Puerto Rico (386 -> 1,024, +165%), West Virginia (2,319 -> 3,677, +59%), North Carolina (3,225 -> 4,632, +44%), Arizona (1,396 -> 2,068, +48%), New York (4,316 -> 6,050, +40%), and Pennsylvania (4,590 -> 6,422, +40%).

Some of this pattern is plausibly real: Arizona's rise is consistent with more extreme-heat and monsoon-flood reporting in a warming/urbanizing Southwest; Puerto Rico's rise is heavily influenced by Hurricane Maria (2017) and subsequent storms; Appalachian/Mid-Atlantic increases (WV, PA, NC, NY) track with well-documented rises in heavy-precipitation and flash-flood events in the Northeast and Appalachians. But the magnitude of the Midwest/South declines (Iowa -70%, Arkansas -62%, Kansas -53%) is larger than any independently documented decline in actual severe-thunderstorm or hail frequency in those states over this period, and directly matches the mechanism NOAA's own NCEI documentation names: forecast-office-level changes in "verification and emphasis" for reporting minor hail/wind damage. This should be read as an open question requiring a follow-up check against a reporting-practice-independent measure (e.g., NWS Doppler-radar-estimated hail/wind swaths, or insurance-industry claims data) before treating it as a real decline in storm frequency, not as a settled climate finding.

National trend: no clean monotonic signal

The national annual count of damaging county-level events (chart above) shows no steady upward or downward trend across 2005-2024. It peaks sharply in 2008 (15,904) and 2011 (18,427) — both were exceptional tornado/hail outbreak years (2011 in particular was one of the most active tornado years on record, including the historic April 2011 Super Outbreak) — then settles into a lower, roughly flat band of 9,965-13,037 for most of 2012-2024. Because the 2005-2014 decade average is inflated by these two outlier years, the headline "-12% nationally" partly reflects the absence of another 2008/2011-scale outbreak year in 2015-2024, not necessarily a structural decline in storm frequency.

Every query behind this report

7 warehouse calls ran in this session, in order. Each is reproducible against the same snapshot.

query — 3236 rows — 8698 ms
SELECT county_fips, state_fips,
  SUM(CASE WHEN CAST("year" AS INT) BETWEEN 2005 AND 2014 THEN 1 ELSE 0 END) AS early_count,
  SUM(CASE WHEN CAST("year" AS INT) BETWEEN 2015 AND 2024 THEN 1 ELSE 0 END) AS recent_count
FROM disasters.storm_events
WHERE cz_type = 'C' AND county_fips IS NOT NULL
  AND (damage_property > 0 OR damage_crops > 0 OR deaths_direct > 0 OR deaths_indirect > 0 OR injuries_direct > 0 OR injuries_indirect > 0)
  AND CAST("year" AS INT) BETWEEN 2005 AND 2024
GROUP BY county_fips, state_fips
query — 1 rows — 10421 ms
WITH county_counts AS (
  SELECT county_fips, state_fips,
    SUM(CASE WHEN CAST("year" AS INT) BETWEEN 2005 AND 2014 THEN 1 ELSE 0 END) AS early_count,
    SUM(CASE WHEN CAST("year" AS INT) BETWEEN 2015 AND 2024 THEN 1 ELSE 0 END) AS recent_count
  FROM disasters.storm_events
  WHERE cz_type = 'C' AND county_fips IS NOT NULL
    AND (damage_property > 0 OR damage_crops > 0 OR deaths_direct > 0 OR deaths_indirect > 0 OR injuries_direct > 0 OR injuries_indirect > 0)
    AND CAST("year" AS INT) BETWEEN 2005 AND 2024
  GROUP BY county_fips, state_fips
)
SELECT COUNT(*) AS n_counties,
  SUM(early_count) AS total_early,
  SUM(recent_count) AS total_recent,
  AVG(early_count) AS avg_early,
  AVG(recent_count) AS avg_recent,
  median(recent_count - early_count) AS median_change,
  AVG(CAST(recent_count AS DOUBLE) - early_count) AS avg_change,
  SUM(CASE WHEN recent_count > early_count THEN 1 ELSE 0 END) AS n_increased,
  SUM(CASE WHEN recent_count < early_count THEN 1 ELSE 0 END) AS n_decreased,
  SUM(CASE WHEN recent_count = early_count THEN 1 ELSE 0 END) AS n_unchanged
FROM county_counts
query — 22 rows — 4383 ms
SELECT CAST("year" AS INT) AS yr,
  SUM(CASE WHEN cz_type='C' THEN 1 ELSE 0 END) AS c_type,
  SUM(CASE WHEN cz_type='Z' THEN 1 ELSE 0 END) AS z_type,
  COUNT(*) AS total,
  SUM(CASE WHEN cz_type='C' AND (damage_property>0 OR damage_crops>0 OR deaths_direct>0 OR deaths_indirect>0 OR injuries_direct>0 OR injuries_indirect>0) THEN 1 ELSE 0 END) AS c_damaging
FROM disasters.storm_events
WHERE CAST("year" AS INT) BETWEEN 2004 AND 2025
GROUP BY CAST("year" AS INT)
ORDER BY yr
query — 1 rows — 17764 ms
WITH years(yr) AS (
  VALUES (2005),(2006),(2007),(2008),(2009),(2010),(2011),(2012),(2013),(2014),
         (2015),(2016),(2017),(2018),(2019),(2020),(2021),(2022),(2023),(2024)
),
counties AS (SELECT DISTINCT county_fips, state_fips FROM disasters.storm_events WHERE cz_type='C' AND county_fips IS NOT NULL),
grid AS (SELECT c.county_fips, c.state_fips, y.yr FROM counties c CROSS JOIN years y),
actual AS (
  SELECT county_fips, CAST("year" AS INT) AS yr, COUNT(*) AS cnt
  FROM disasters.storm_events
  WHERE cz_type='C' AND county_fips IS NOT NULL
    AND (damage_property>0 OR damage_crops>0 OR deaths_direct>0 OR deaths_indirect>0 OR injuries_direct>0 OR injuries_indirect>0)
    AND CAST("year" AS INT) BETWEEN 2005 AND 2024
  GROUP BY county_fips, CAST("year" AS INT)
),
county_slopes AS (
  SELECT g.county_fips, g.state_fips,
    regr_slope(COALESCE(a.cnt,0), g.yr) AS slope,
    AVG(COALESCE(a.cnt,0)) AS avg_annual
  FROM grid g LEFT JOIN actual a ON g.county_fips=a.county_fips AND g.yr=a.yr
  GROUP BY g.county_fips, g.state_fips
)
SELECT
  COUNT(*) AS n_counties,
  SUM(CASE WHEN slope>0 THEN 1 ELSE 0 END) AS n_pos_slope,
  SUM(CASE WHEN slope<0 THEN 1 ELSE 0 END) AS n_neg_slope,
  AVG(slope) AS avg_slope,
  median(slope) AS median_slope
FROM county_slopes
query — 15 rows — 17747 ms
WITH years(yr) AS (
  VALUES (2005),(2006),(2007),(2008),(2009),(2010),(2011),(2012),(2013),(2014),
         (2015),(2016),(2017),(2018),(2019),(2020),(2021),(2022),(2023),(2024)
),
counties AS (SELECT DISTINCT county_fips, state_fips FROM disasters.storm_events WHERE cz_type='C' AND county_fips IS NOT NULL),
grid AS (SELECT c.county_fips, c.state_fips, y.yr FROM counties c CROSS JOIN years y),
actual AS (
  SELECT county_fips, CAST("year" AS INT) AS yr, COUNT(*) AS cnt
  FROM disasters.storm_events
  WHERE cz_type='C' AND county_fips IS NOT NULL
    AND (damage_property>0 OR damage_crops>0 OR deaths_direct>0 OR deaths_indirect>0 OR injuries_direct>0 OR injuries_indirect>0)
    AND CAST("year" AS INT) BETWEEN 2005 AND 2024
  GROUP BY county_fips, CAST("year" AS INT)
),
county_slopes AS (
  SELECT g.county_fips, g.state_fips,
    regr_slope(COALESCE(a.cnt,0), g.yr) AS slope,
    AVG(COALESCE(a.cnt,0)) AS avg_annual
  FROM grid g LEFT JOIN actual a ON g.county_fips=a.county_fips AND g.yr=a.yr
  GROUP BY g.county_fips, g.state_fips
  HAVING AVG(COALESCE(a.cnt,0)) >= 1
)
SELECT county_fips, state_fips, slope, avg_annual
FROM county_slopes
ORDER BY slope DESC
LIMIT 15
query — 15 rows — 19535 ms
WITH years(yr) AS (
  VALUES (2005),(2006),(2007),(2008),(2009),(2010),(2011),(2012),(2013),(2014),
         (2015),(2016),(2017),(2018),(2019),(2020),(2021),(2022),(2023),(2024)
),
counties AS (SELECT DISTINCT county_fips, state_fips FROM disasters.storm_events WHERE cz_type='C' AND county_fips IS NOT NULL),
grid AS (SELECT c.county_fips, c.state_fips, y.yr FROM counties c CROSS JOIN years y),
actual AS (
  SELECT county_fips, CAST("year" AS INT) AS yr, COUNT(*) AS cnt
  FROM disasters.storm_events
  WHERE cz_type='C' AND county_fips IS NOT NULL
    AND (damage_property>0 OR damage_crops>0 OR deaths_direct>0 OR deaths_indirect>0 OR injuries_direct>0 OR injuries_indirect>0)
    AND CAST("year" AS INT) BETWEEN 2005 AND 2024
  GROUP BY county_fips, CAST("year" AS INT)
),
county_slopes AS (
  SELECT g.county_fips, g.state_fips,
    regr_slope(COALESCE(a.cnt,0), g.yr) AS slope,
    AVG(COALESCE(a.cnt,0)) AS avg_annual
  FROM grid g LEFT JOIN actual a ON g.county_fips=a.county_fips AND g.yr=a.yr
  GROUP BY g.county_fips, g.state_fips
  HAVING AVG(COALESCE(a.cnt,0)) >= 1
)
SELECT county_fips, state_fips, slope, avg_annual
FROM county_slopes
ORDER BY slope ASC
LIMIT 15
query — 55 rows — 19104 ms
SELECT state_fips, COUNT(*) AS n_counties,
  SUM(CASE WHEN CAST("year" AS INT) BETWEEN 2005 AND 2014 THEN 1 ELSE 0 END) AS early,
  SUM(CASE WHEN CAST("year" AS INT) BETWEEN 2015 AND 2024 THEN 1 ELSE 0 END) AS recent
FROM disasters.storm_events
WHERE cz_type='C' AND county_fips IS NOT NULL
  AND (damage_property>0 OR damage_crops>0 OR deaths_direct>0 OR deaths_indirect>0 OR injuries_direct>0 OR injuries_indirect>0)
  AND CAST("year" AS INT) BETWEEN 2005 AND 2024
GROUP BY state_fips
ORDER BY (SUM(CASE WHEN CAST("year" AS INT) BETWEEN 2015 AND 2024 THEN 1 ELSE 0 END) - SUM(CASE WHEN CAST("year" AS INT) BETWEEN 2005 AND 2014 THEN 1 ELSE 0 END)) DESC

Sources

  1. disasters.storm_events — county-type damaging events by year, national — askamerica table
    Show SQL
    SELECT CAST("year" AS INT) AS yr, SUM(CASE WHEN cz_type='C' AND (damage_property>0 OR damage_crops>0 OR deaths_direct>0 OR deaths_indirect>0 OR injuries_direct>0 OR injuries_indirect>0) THEN 1 ELSE 0 END) AS c_damaging FROM disasters.storm_events WHERE CAST("year" AS INT) BETWEEN 2004 AND 2025 GROUP BY CAST("year" AS INT) ORDER BY yr
  2. disasters.storm_events — county-level linear trend slopes, 2005-2024 (zero-filled) — askamerica table; n=3,236 counties
    Show SQL
    WITH years(yr) AS (VALUES (2005),(2006),(2007),(2008),(2009),(2010),(2011),(2012),(2013),(2014),(2015),(2016),(2017),(2018),(2019),(2020),(2021),(2022),(2023),(2024)), counties AS (SELECT DISTINCT county_fips, state_fips FROM disasters.storm_events WHERE cz_type='C' AND county_fips IS NOT NULL), grid AS (SELECT c.county_fips, c.state_fips, y.yr FROM counties c CROSS JOIN years y), actual AS (SELECT county_fips, CAST("year" AS INT) AS yr, COUNT(*) AS cnt FROM disasters.storm_events WHERE cz_type='C' AND county_fips IS NOT NULL AND (damage_property>0 OR damage_crops>0 OR deaths_direct>0 OR deaths_indirect>0 OR injuries_direct>0 OR injuries_indirect>0) AND CAST("year" AS INT) BETWEEN 2005 AND 2024 GROUP BY county_fips, CAST("year" AS INT)) SELECT g.county_fips, g.state_fips, regr_slope(COALESCE(a.cnt,0), g.yr) AS slope, AVG(COALESCE(a.cnt,0)) AS avg_annual FROM grid g LEFT JOIN actual a ON g.county_fips=a.county_fips AND g.yr=a.yr GROUP BY g.county_fips, g.state_fips
  3. NCEI: Monitoring and Understanding Trends in Extreme Storms — Confirms non-uniform historical reporting practice for severe convective storms
  4. Storm Watch: Trends in Extreme US Weather Events — Resources for the Future — Discusses Storm Events Database scope evolution and reporting-practice changes over decades
  5. omissions and inconsistencies in flood damage reporting — Univ. Colorado / NWS — Documents inconsistent damage-estimate quality across NWS field offices over time