Synopsis

Data Processing

Data is in comma separeated CSV file, file can be download from this link, the file is compressed in bzip2 format, uncompress before read into R.

loading data

dat<-read.csv("repdata%2Fdata%2FStormData.csv", stringsAsFactors = F)
# summarize by year
dat$date<-strptime(dat$BGN_DATE, "%m/%d/%Y %H:%M:%S")
dat$year<-dat$date$year+1900
dat$date<-as.character(dat$date)  # this column will not be use again actually
total_Obj<-dim(dat)[1]
quantile(dat$year)
##   0%  25%  50%  75% 100% 
## 1950 1995 2002 2007 2011
# remove lower 25%
dat<-dat[dat$year>=1995,]
total_obj<-dim(dat)[1]

National Weather Service indicates the data is collected since 1950, until 2011, there are 902297 events in data set, however, most data are collected after year 2002, we will skip lower 25% of data in favor of complete yearly observation. The subset of data is 681500 events, from 1995 until 2011.

Damaged properties and crop values

dataset has 2 column for each damage type, one column store the number, another column store exponent, like “m” for million, “H” for handred. we first need to convert the exponent to number.

PROPDMGEXP and CROPDMGEXP explaination

How To Handle Exponent Value of PROPDMGEXP and CROPDMGEXP guide has comperhansive study of how to handle each exponent, below is descipition

  • H,h,K,k,M,m,B,b,+,-,?,0,1,2,3,4,5,6,7,8, and blank-character

  • H,h = hundreds = 100

  • K,k = kilos = thousands = 1,000

  • M,m = millions = 1,000,000

  • B,b = billions = 1,000,000,000

  • (+) = 1

  • (-) = 0

  • (?) = 0

  • black/empty character = 0

  • numeric 0..8 = 10
    conclusion for all numeric, exp 0, 1, 2, 3, 4, 5, 6, 7, 8, they are multiplier of 10.

convert exponent

we will create a function take exponent charactor and create multiplication factor, use this factor multiply with damage value.

# function take two vector and multiply
expval<-function(v,e) {
  if ( length(v) != length(e)) {
    message("2 vectors not at same length")
    return()
  }
  # the order doesnt matter, all gsub will run anyway,
  # only order matters is number be first, so that 10 will not be replace again
  e <- sub("^[0|1|2|3|4|5|6|7|8]$", "10", e)
  e <- sub("^$", "0", e)
  e <- sub("^[-|?]$", "0", e)
  e <- sub("^\\+$", "1", e)
  e <- sub("^[h|H]$", "100", e)
  e <- sub("^[k|K]$", "1000", e)
  e <- sub("^[m|M]$", "1000000", e)
  e <- sub("^[b|B]$", "1000000000", e)
  e <- as.numeric(e)
  return (v * e)
}

we will create two new column for dataset, propval for property damange value, cropval fro crop damage value

# calculate property and crop danmage
dat$propval <- expval(dat$PROPDMG, dat$PROPDMGEXP)
dat$cropval <- expval(dat$CROPDMG, dat$CROPDMGEXP)

Event types

the detail description of dataset can be found in National Weather Service Storm Data Documentation. extract “Storm Data Event” and save to text file.

evtcat <- read.csv("evtcat.txt", header = F)
eventcat<-sort(toupper((evtcat[,1])))
rm(evtcat)

According to 2.1.1 Storm Data Event Table, there are 48 types of event, but there are 799 event names reported. In order to produce meaningful result, we first need to clean up the event name of each event. The plan as following

first, supporting functions

# function that match orignal event name with pattern, if found assign offical name to event_type column
# ep is vector of patterns that will apply to orignal names
# ec is vector of list of offical names, pair will patterns
match_event <- function(ep,em) {
  for ( i in 1:length(ep)) {
    #print(paste("replacing ",ep[i],"with",em[i], sep = " "))
    events[grep(ep[i],events$evtype),] %<>% mutate(event_type = em[i])
    events<<-events
  }
}
  1. create a events data frame by copy EVTYPE from data set, do simple clean up, convert to upper case, remove surrounding spaces.
    events had 3 columns, first column is orignal name copied from dataset,
    second is event name that is manipulated after matched with patterns, third column is offical event name.
    The third column “event_cat” start with all NA.
# subset event from dataset
evts<-toupper(trimws(as.vector(dat$EVTYPE)))
events<-cbind(evts, evts,rep(NA,length(evts)))
colnames(events)<-c("evtype","event_type","event_cat")
events<-tbl_df(events)
rm(evts)
  1. Create two vectors, one is pattern that will search orignals names, another is offical name that is the name of matching event. we can start with empty vector but will start from with THUNDERSTORM for demostrattion.
event_patterns <- c("^TSTM$")
event_matches <- c("THUNDERSTORM")
  1. call match function on each event pattern and event match pair
match_event(event_patterns, event_matches)
  1. assign name of event_cat if the matches offical name. we can directly change event_type column, but have additional result column will be easier to produce comparsion report used during clean up.
# assign offical name if cleaned up event_name is offical name
for ( e in eventcat) {
  events[events$event_type==e, "event_cat"]<-e
}
  1. filter rows which office name is unassigned(NA), sort those rows by number, create new pattern for top event and matching offical event name to event_patterns and event_matches, run step 4 and 5, after run step 4 and 5, this step will should smaller unassigned.

repeat step 4 to 6, until top unassigned event is insignificate.

events %>% filter(is.na(event_cat)) %>% group_by(event_type) %>% summarise(cnt=n()) %>% arrange(desc(cnt))
## # A tibble: 662 x 2
##              event_type    cnt
##                   <chr>  <int>
##  1            TSTM WIND 128929
##  2   THUNDERSTORM WINDS  10041
##  3     MARINE TSTM WIND   6175
##  4 URBAN/SML STREAM FLD   3392
##  5     WILD/FOREST FIRE   1446
##  6   WINTER WEATHER/MIX   1104
##  7       TSTM WIND/HAIL   1028
##  8           HIGH WINDS    776
##  9         EXTREME COLD    634
## 10            LANDSLIDE    599
## # ... with 652 more rows

list of patterns after over 10 rounds of matching, the number of of event is low enough, how ever we need to consider smaller number of event but having bigger impact.

options(width=80)
# pattern of evtype
event_patterns <- c(
  "^(TSTM|TSTM WIND|THUNDERSTORM WINDS)$",
  "^MARINE TSTM WIND$",
  "^(URBAN/SML STREAM FLD|URBAN FLOOD|RIVER FLOOD(ING)?|FLOOD/FLASH FLOOD)$",
  "^(HIGH WINDS|WIND)", # high winds or start with wind
  "^WILD/FOREST FIRE$",
  "^WINTER WEATHER/MIX$",
  "^(TSTM WIND/HAIL|HAILSTORM)$",
  "^EXTREME COLD$",
  "^SNOW$",
  "^FOG$",
  "^RIP CURRENTS$",
  "^STORM SURGE$",
  "^(FREEZING RAIN|GLAZE)$",
  "^HEAVY SURF/HIGH SURF$",
  "^EXTREME WINDCHILL$",
  "^STRONG WINDS$",
  "^(HURRICANE|TYPHOON)",     # named hurricane
  "^ASTRONOMICAL (LOW|HIGH) TIDE$",
  "^COLD$",
  "^(FREEZE|DAMAGING FREEZE)$",
  "^HEAVY RAIN",
  "^COASTAL FLOODING$",
  "^FLASH FLOODING$",
  "^SEVERE THUNDERSTORM$",
  "^(HEAT WAVE|UNSEASONABLY WARM AND DRY|UNSEASONABLY WARM)$",
  "^EXTREME HEAT$"
  )
# replaced with, elementes must match with associated pattern as pair
event_matches <- c(
  "THUNDERSTORM WIND",
  "MARINE THUNDERSTORM WIND",
  "FLOOD",
  "HIGH WIND",
  "WILDFIRE",
  "WINTER WEATHER",
  "HAIL",
  "EXTREME COLD/WIND CHILL",
  "HEAVY SNOW",
  "DENSE FOG",
  "RIP CURRENT",
  "STORM SURGE/TIDE",
  "SLEET",
  "HIGH SURF",
  "EXTREME COLD/WIND CHILL",
  "STRONG WIND",
  "HURRICANE (TYPHOON)",
  "ASTRONOMICAL LOW TIDE",
  "COLD/WIND CHILL",
  "FROST/FREEZE",
  "HEAVY RAIN",
  "COASTAL FLOOD",
  "FLASH FLOOD",
  "THUNDERSTORM WIND",
  "HEAT",
  "EXCESSIVE HEAT"
  )
# step 4
match_event(event_patterns, event_matches)
# step 5
for ( e in eventcat) {
  events[events$event_type==e, "event_cat"]<-e
}
# add result back to data set
dat$event_cat <- events$event_cat

After finish will “count”, and adding event_cat back to dataset, run more verification, sort by fataility, injure, and damage value. create more pattern/matches, and clean up again step 4 to 6. this will take another 5 to 10 tries.

# step 6
dat %>% 
  filter(is.na(event_cat))  %>% 
  group_by(EVTYPE) %>% 
  summarize( 
    cnt = n(), 
    total_fat = sum(FATALITIES), 
    total_inj = sum(INJURIES),
    total_propval =  round(sum(propval)/1000000,2),
    total_cropval =  round(sum(cropval)/1000000,2)
  ) %>% 
  arrange(desc(total_fat))
## # A tibble: 646 x 6
##                     EVTYPE   cnt total_fat total_inj total_propval
##                      <chr> <int>     <dbl>     <dbl>         <dbl>
##  1               LANDSLIDE   599        38        52        324.60
##  2           COLD AND SNOW     1        14         0          0.00
##  3              ROUGH SEAS     3         8         5          0.00
##  4           MARINE MISHAP     2         7         5          0.00
##  5              HEAVY SURF    82         6        40          1.34
##  6            COLD WEATHER     4         5         0          0.00
##  7               ICY ROADS    28         5        31          0.34
##  8 RIP CURRENTS/HEAVY SURF     2         5         0          0.00
##  9       HEAT WAVE DROUGHT     1         4        15          0.20
## 10    Hypothermia/Exposure     3         4         0          0.00
## # ... with 636 more rows, and 1 more variables: total_cropval <dbl>
# unassigned rows
dat %>% group_by(is.na(event_cat)) %>% summarize(
  cnt=n(),
  total_fat = sum(FATALITIES), 
  total_inj = sum(INJURIES),
  total_propval =  round(sum(propval)/1000000,2),
  total_cropval =  round(sum(cropval)/1000000,2)
  )
## # A tibble: 2 x 6
##   `is.na(event_cat)`    cnt total_fat total_inj total_propval
##                <lgl>  <int>     <dbl>     <dbl>         <dbl>
## 1              FALSE 677551     10029     61821     376052.73
## 2               TRUE   3949       194       634        506.92
## # ... with 1 more variables: total_cropval <dbl>

This is final result, the summary shows that after clean up, the number of un-catagorized, total injure, total property damange value, total crop damage val are all between 1 to 2%.

Note the landside cause total 38 death, which is high but there’s no catelog to match to, landside could cause by rain or snow, we leave it as is.

At this point, we are ready to process data.

summarize data, sorting the top events.

  1. take orignal dataset, group by offical event names, in each group, summarize the number of fatality/injuries, for damage type event, summarize the value, then sort the result, lastly pick top 20 result. the reason I pick 20 is to keep “other” low enough.

  2. create a total count/value for later percentage calculation.

  3. find the events that are outside of top 20, assign the event name as “OTHER”, their value is either number of occurence, or sum of value for damage type.

  4. add the row of others to result data frame

  5. create data frame for treemap display, the lable is combination of event name and percentage.

Summarize Fatality and Injuries

# top fatality
top_fat<-dat %>% 
  group_by(event_cat) %>%
  summarize(total= sum(FATALITIES)) %>% 
  arrange(desc(total)) %>% top_n(20)

total_cnt<-sum(dat$FATALITIES)

other_cnt<-dat %>% 
  filter(!event_cat %in% top_fat$event_cat) %>% 
  group_by(event_cat) %>% 
  summarise(total=sum(FATALITIES)) %>% 
  select(total) %>% 
  sum()
top_fat[nrow(top_fat)+1,] <- list("OTHERS",other_cnt)
top_fat$pct<-round(top_fat$total/total_cnt*100,2)
top_fat_tm<-data.frame(event_cat=paste(top_fat$event_cat,"(",top_fat$pct,"%)", sep=""), total=top_fat$total)
# top injure
top_inj<-dat %>% 
  group_by(event_cat) %>%
  summarize(total= sum(INJURIES)) %>% 
  arrange(desc(total)) %>% top_n(20)

total_cnt<-sum(dat$INJURIES)

other_cnt<-dat %>% 
  filter(!event_cat %in% top_inj$event_cat) %>% 
  group_by(event_cat) %>% 
  summarise(total=sum(INJURIES)) %>% 
  select(total) %>% 
  sum()
top_inj[nrow(top_inj)+1,] <- list("OTHERS",other_cnt)
top_inj$pct<-round(top_inj$total/total_cnt*100,2)
top_inj_tm<-data.frame(event_cat=paste(top_inj$event_cat,"(",top_inj$pct,"%)", sep=""), total=top_inj$total)

Summarize property and crop damage

# top property damange
top_prop<-dat %>% 
  group_by(event_cat) %>%
  summarize(total= round(sum(propval)/1000000)) %>% 
  arrange(desc(total)) %>% top_n(20)

total_cnt<-round(sum(dat$propval)/1000000)

other_cnt<-dat %>% 
  filter(!event_cat %in% top_prop$event_cat) %>% 
  group_by(event_cat) %>% 
  summarise(total=round(sum(propval)/1000000)) %>% 
  select(total) %>% 
  sum()
top_prop[nrow(top_prop)+1,] <- list("OTHERS",other_cnt)
top_prop$pct<-round(top_prop$total/total_cnt*100,2)
top_prop_tm<-data.frame(event_cat=paste(top_prop$event_cat,"(",top_prop$pct,"%)", sep=""), total=top_prop$total)

# top crop damage
top_crop<-dat %>% 
  group_by(event_cat) %>%
  summarize(total= round(sum(cropval)/1000000)) %>% 
  arrange(desc(total)) %>% top_n(20)

total_cnt<-round(sum(dat$cropval)/1000000)

other_cnt<-dat %>% 
  filter(!event_cat %in% top_crop$event_cat) %>% 
  group_by(event_cat) %>% 
  summarise(total=round(sum(cropval)/1000000)) %>% 
  select(total) %>% 
  sum()
top_crop[nrow(top_crop)+1,] <- list("OTHERS",other_cnt)
top_crop$pct<-round(top_crop$total/total_cnt*100,2)
top_crop_tm<-data.frame(event_cat=paste(top_crop$event_cat,"(",top_crop$pct,"%)", sep=""), total=top_crop$total)

Top Event by State

Each state have different top event, we will create top most event in terms of casuing fatality, injures, perproty damage, and crop damage.

  1. get list of state code and state name, for user friendly display

  2. group dataset into state_name, event_cat, in that order, summarize either by count of value, arrange result n=in descending order, filter by state_name, reduce value to million if necessary.

  3. merge four data frame to one.

  4. assign column names with clear meaning

# read state name 
state<-read.csv("state.txt",sep = "\t", stringsAsFactors = F)
# create new column in data set for state name
dat$state_name<-state$name[match(dat$STATE, state$code)]
# top property
state_prop <- dat %>% 
  group_by(state_name,event_cat) %>%  
  summarise(total_prop=sum(propval)) %>%
  arrange(desc(total_prop)) %>% 
  filter(row_number(state_name) < 2) %>% 
  mutate(total_prop=round(total_prop/1000000))
# top crop
state_crop <- dat %>% 
  group_by(state_name,event_cat) %>%  
  summarise(total_crop=sum(cropval)) %>%
  arrange(desc(total_crop)) %>% 
  filter(row_number(state_name) < 2) %>% 
  mutate(total_crop=round(total_crop/1000000))
# top fatality
state_fat <- dat %>% 
  group_by(state_name,event_cat) %>% 
  summarise(total_fat=sum(FATALITIES)) %>%
  arrange(desc(total_fat)) %>%
  filter(row_number(state_name) <2)
# top injure
state_inj<-dat %>% 
  group_by(state_name,event_cat) %>% 
  summarise(total_inj=sum(INJURIES)) %>% 
  arrange(desc(total_inj)) %>%
  filter(row_number(state_name) <2)
# merge 4 data frame into one as top event
state_tops<-merge(state_fat, state_inj, by="state_name")
state_tops<-merge(state_tops, state_prop, by="state_name")
state_tops<-merge(state_tops, state_crop, by="state_name")
# assign user friendly header
colnames(state_tops)<-c("State",
                        "Event Caused Most Fatality", "Fatality Count", 
                        "Event Caused most Injure", "Injure Count",
                        "Event caused most Property Damage","Damage Value (Million)",
                        "Event Caused Most Crop Damage","Damage Value (Million)"
                        )

Result

The most harmful to population health.

Natural events that cause most fatality and injures are considered most harmful, in United States excesive heat caused most fatality.

grid.newpage()
pushViewport(viewport(layout=grid.layout(2,1)))
vp_fat<-viewport(layout.pos.col=1, layout.pos.row=1)
treemap(top_fat_tm, index=c("event_cat","total"), vSize="total", vColor="total", type="value", title="top fatality events", vp=vp_fat)
vp_inj<-viewport(layout.pos.col=1, layout.pos.row=2)
treemap(top_inj_tm, index=c("event_cat","total"), vSize="total", vColor="total", type="value", title="top injure event", vp=vp_inj)

What event cause most proprety damage and crop damage

grid.newpage()
pushViewport(viewport(layout=grid.layout(2,1)))
vp_prop<-viewport(layout.pos.col=1, layout.pos.row=1)
treemap(top_prop_tm, index=c("event_cat","total"), vSize="total", vColor="total", type="value", title="top property damage events", vp=vp_prop)
vp_crop<-viewport(layout.pos.col=1, layout.pos.row=2)
treemap(top_crop_tm, index=c("event_cat","total"), vSize="total", vColor="total", type="value", title="top crop damage events", vp=vp_crop)

sepreated by state, what is the most impactful event

xtab<-xtable(state_tops)
print(xtab, type="html")
State Event Caused Most Fatality Fatality Count Event Caused most Injure Injure Count Event caused most Property Damage Damage Value (Million) Event Caused Most Crop Damage Damage Value (Million)
1 ALABAMA TORNADO 342.00 TORNADO 3446.00 TORNADO 5039.00 HEAT 400.00
2 ALASKA AVALANCHE 33.00 ICE STORM 34.00 FLOOD 167.00 HIGH WIND 0.00
3 ARIZONA FLASH FLOOD 61.00 DUST STORM 177.00 HAIL 2829.00 TROPICAL STORM 200.00
4 ARKANSAS TORNADO 100.00 TORNADO 1419.00 TORNADO 1560.00 FLOOD 141.00
5 CALIFORNIA EXCESSIVE HEAT 110.00 WILDFIRE 978.00 FLOOD 116867.00 EXTREME COLD/WIND CHILL 731.00
6 COLORADO AVALANCHE 48.00 LIGHTNING 239.00 HAIL 1369.00 HAIL 112.00
7 CONNECTICUT HIGH WIND 10.00 LIGHTNING 51.00 TROPICAL STORM 60.00 HAIL 0.00
8 DELAWARE EXCESSIVE HEAT 7.00 HIGH SURF 66.00 COASTAL FLOOD 40.00 DROUGHT 29.00
9 FLORIDA RIP CURRENT 263.00 HURRICANE (TYPHOON) 812.00 HURRICANE (TYPHOON) 31794.00 HURRICANE (TYPHOON) 1448.00
10 GEORGIA TORNADO 87.00 TORNADO 1483.00 TORNADO 976.00 DROUGHT 717.00
11 GUAM RIP CURRENT 38.00 HURRICANE (TYPHOON) 339.00 HURRICANE (TYPHOON) 864.00 HURRICANE (TYPHOON) 106.00
12 HAWAII HIGH SURF 28.00 HIGH SURF 32.00 FLASH FLOOD 157.00 HIGH WIND 3.00
13 IDAHO AVALANCHE 16.00 THUNDERSTORM WIND 94.00 FLOOD 114.00 HAIL 6.00
14 ILLINOIS HEAT 653.00 TORNADO 546.00 FLASH FLOOD 794.00 DROUGHT 285.00
15 INDIANA TORNADO 34.00 TORNADO 581.00 FLOOD 838.00 FLOOD 697.00
16 IOWA TORNADO 20.00 TORNADO 441.00 FLOOD 1355.00 DROUGHT 2010.00
17 KANSAS TORNADO 37.00 TORNADO 454.00 TORNADO 739.00 HAIL 240.00
18 KENTUCKY FLASH FLOOD 39.00 TORNADO 473.00 HAIL 610.00 DROUGHT 226.00
19 LOUISIANA EXCESSIVE HEAT 58.00 TORNADO 507.00 STORM SURGE/TIDE 31828.00 DROUGHT 587.00
20 MAINE LIGHTNING 5.00 LIGHTNING 65.00 ICE STORM 318.00 HAIL 0.00
21 MARYLAND EXCESSIVE HEAT 88.00 EXCESSIVE HEAT 461.00 TROPICAL STORM 539.00 DROUGHT 100.00
22 MASSACHUSETTS TORNADO 9.00 TORNADO 424.00 TORNADO 460.00 THUNDERSTORM WIND 1.00
23 MICHIGAN THUNDERSTORM WIND 27.00 HEAT 315.00 THUNDERSTORM WIND 360.00 DROUGHT 150.00
24 MINNESOTA EXCESSIVE HEAT 13.00 TORNADO 275.00 FLOOD 1288.00 FLOOD 105.00
25 MISSISSIPPI TORNADO 64.00 TORNADO 901.00 HURRICANE (TYPHOON) 14178.00 HURRICANE (TYPHOON) 1515.00
26 MISSOURI TORNADO 233.00 EXCESSIVE HEAT 3525.00 TORNADO 3644.00 FLOOD 596.00
27 MONTANA LIGHTNING 9.00 WILDFIRE 33.00 HAIL 93.00 HAIL 33.00
28 NEBRASKA WINTER STORM 11.00 TORNADO 129.00 HAIL 908.00 DROUGHT 720.00
29 NEVADA HEAT 53.00 FLOOD 51.00 FLOOD 678.00 FLOOD 6.00
30 NEW HAMPSHIRE FLASH FLOOD 4.00 LIGHTNING 79.00 ICE STORM 65.00 FLOOD 0.00
31 NEW JERSEY EXCESSIVE HEAT 39.00 EXCESSIVE HEAT 300.00 FLOOD 2112.00 DROUGHT 80.00
32 NEW MEXICO FLASH FLOOD 16.00 TORNADO 50.00 WILDFIRE 1549.00 DROUGHT 14.00
33 NEW YORK EXCESSIVE HEAT 93.00 THUNDERSTORM WIND 251.00 FLASH FLOOD 1755.00 HAIL 82.00
34 NORTH CAROLINA TORNADO 45.00 TORNADO 758.00 HURRICANE (TYPHOON) 5519.00 HURRICANE (TYPHOON) 1457.00
35 NORTH DAKOTA BLIZZARD 8.00 BLIZZARD 97.00 FLOOD 3907.00 THUNDERSTORM WIND 194.00
36 OHIO FLASH FLOOD 33.00 TORNADO 285.00 FLASH FLOOD 1230.00 DROUGHT 200.00
37 OKLAHOMA TORNADO 79.00 TORNADO 1680.00 TORNADO 1752.00 DROUGHT 1097.00
38 OREGON HIGH WIND 19.00 HIGH WIND 44.00 FLOOD 716.00 HAIL 37.00
39 PENNSYLVANIA EXCESSIVE HEAT 360.00 EXCESSIVE HEAT 357.00 FLASH FLOOD 1407.00 DROUGHT 539.00
40 PUERTO RICO FLASH FLOOD 34.00 HEAVY RAIN 10.00 HURRICANE (TYPHOON) 1824.00 HURRICANE (TYPHOON) 451.00
41 RHODE ISLAND HIGH SURF 3.00 LIGHTNING 17.00 FLOOD 93.00 BLIZZARD 0.00
42 SOUTH CAROLINA EXCESSIVE HEAT 29.00 TORNADO 263.00 ICE STORM 148.00 HURRICANE (TYPHOON) 20.00
43 SOUTH DAKOTA ICE STORM 8.00 TORNADO 220.00 HAIL 85.00 HAIL 63.00
44 TENNESSEE TORNADO 187.00 TORNADO 2159.00 FLOOD 4245.00 THUNDERSTORM WIND 9.00
45 TEXAS EXCESSIVE HEAT 269.00 FLOOD 6339.00 TROPICAL STORM 5491.00 DROUGHT 6373.00
46 UTAH AVALANCHE 44.00 WINTER STORM 415.00 FLOOD 332.00 HIGH WIND 2.00
47 VERMONT FLOOD 4.00 THUNDERSTORM WIND 17.00 FLOOD 1076.00 FLASH FLOOD 15.00
48 VIRGIN ISLANDS HIGH SURF 3.00 LIGHTNING 1.00 HURRICANE (TYPHOON) 28.00 DROUGHT 0.00
49 VIRGINIA FLASH FLOOD 29.00 TORNADO 454.00 HURRICANE (TYPHOON) 635.00 DROUGHT 297.00
50 WASHINGTON AVALANCHE 34.00 HIGH WIND 43.00 FLOOD 212.00 FROST/FREEZE 205.00
51 WEST VIRGINIA FLASH FLOOD 24.00 LIGHTNING 45.00 FLASH FLOOD 483.00 DROUGHT 20.00
52 WISCONSIN EXCESSIVE HEAT 94.00 TORNADO 209.00 HAIL 961.00 FLOOD 466.00
53 WYOMING AVALANCHE 23.00 WINTER STORM 119.00 HAIL 111.00 HAIL 2.00