Our analysis relies on combining public health surveillance data with external information about trends in sports gambling.

Data Sources and Scope

Our project utilizes two main sources spanning the period 2017 through 2024:

  • Primary Source (Health Outcome / Demographic Data): The Behavioral Risk Factor Surveillance System (BRFSS). This is an annual, state-based, nationwide telephone survey conducted by the CDC, providing detailed self-reported health and behavioral data. We analyzed 2.75 million completed interviews across all available years. We chose this period as it spans the period before the 2018 Supreme Court ruling (PASPA repeal), which allowed many states to legalize sports betting.

  • Secondary Sources (Sports Gambling Policy and Market Activity Data): We used data scraped from Legal Sports Report for market handle and manually compiled state legalization dates from the American Gaming Association.

Data Cleaning and Processing

Due to variations in the BRFSS survey over the years, we standardized the data. This process was handled by a dedicated source/ code folder, with the following functions ensuring data quality and analytical readiness:

  • Variable Standardization standardize_brfss_variable.R: This function renames variables that have more than one version of the same variable (e.g. HLTHPL1 and HLTHPL2). Seeing that the variables differed in name only (the responses were coded in the same way), this was handled by renaming different versions to the single standardized name. (e.g. hlthpl_standard).
standardize_brfss_variable = function(raw_data){
  
  column_names = colnames(raw_data)
  
  raw_data = 
    raw_data |> 
    rename_with(.fn = ~ "hlthpl_standard", .cols = starts_with("hlthpl", ignore.case = FALSE)) |> 
    rename_with(.fn = ~ "rfdrh_standard", .cols = starts_with("rfdrhv", ignore.case = FALSE)) |> 
    rename_with(.fn = ~ "rfbing_standard", .cols = starts_with("rfbing", ignore.case = FALSE)) |> 
    rename_with(.fn = ~ "income_standard", .cols = starts_with("income", ignore.case = FALSE)) |> 
    rename_with(.fn = ~ "medcost_standard", .cols = starts_with("medcost", ignore.case = FALSE))|> 
    rename_with(.fn = ~ "addepe_standard", .cols = starts_with("addepe", ignore.case = FALSE))
  
  
  
    
  if (!("sdlonely" %in% column_names)) {
    raw_data = raw_data |> mutate(sdlonely = NA_integer_)
  }
  
  if (!("lsatisfy" %in% column_names)) {
    raw_data = raw_data |> mutate(lsatisfy = NA_integer_)
  }
  
  if (!("emtsuprt" %in% column_names)) {
    raw_data = raw_data |> mutate(emtsuprt = NA_integer_)
  }
  
  if (!("sdhemply" %in% column_names)) {
    raw_data = raw_data |> mutate(sdhemply = NA_integer_)
  }
  
  if (!("sdhbills" %in% column_names)) {
    raw_data = raw_data |> mutate(sdhbills = NA_integer_)
  }
  
  if (!("sdhutils" %in% column_names)) {
    raw_data = raw_data |> mutate(sdhutils = NA_integer_)
  }
  
  if ("sex1" %in% column_names) {
    raw_data = raw_data |> mutate(sex = sex1)
  }
  
  if (!("urbstat" %in% column_names)) {
    raw_data = raw_data |> mutate(urbstat = NA_integer_)
  }

  raw_data
}
  • Filtering filter_brfss_data.R: This function keeps the key variables for our study (unique survey identifiers, demographic/predictor variables, health/financial outcomes variables). It also filters for completed interviews (dispcode = 1100) and converts the date of the interview to a Date type variable.
filter_brfss_data = function(brfss_data_raw, data_year = 2024){
  
  column_names = colnames(brfss_data_raw)
  
  brfss_data_clean = 
    brfss_data_raw |> 
    select(qstver, dispcode, state, seqno, iyear, imonth, iday, 
           sex, marital, educag, employ1, children, income_standard, urbstat, imprace, ageg5yr, hlthpl_standard, 
           genhlth, rfhlth, physhlth, phys14d, menthlth, ment14d, poorhlth, medcost_standard, totinda, michd, addepe_standard, 
           decide, diffalon, lsatisfy, emtsuprt, sdlonely, sdhemply, sdhbills, sdhutils, rfbing_standard, rfdrh_standard
    ) |> 
    mutate(
      date = as.Date(paste(iyear, imonth, iday, sep = "-"))
    ) |> 
    filter(
      dispcode == 1100, 
      year(date) == data_year
      ) # only selecting completed interviews in the right year
  
  brfss_data_clean
}
  • Loading load_clean_brfss_data.R: This function is used to load the cleaned data set into R by recoding variables (e.g. 1 ~ "Male"), and connects the date of each interview to the status of legalization in that state. This sb_legal treatment variable is added by merging with state_legalization_dates.csv.
load_clean_brfss = function(filepath){
  
  #get date when sports betting became legal by state
  sb_legal_dates = 
    read_csv(here::here("data", "legal_sports_report","state_legalization_dates.csv")) |> 
    select(first_start, abbr, fips)
  
  cleaned_df = 
    read_csv(filepath) |> 
    mutate(
      
      id = paste0(state, seqno), # concatenating state and seqno to get a unique row id for each interview
      
      sex = case_match(sex, 1 ~ "Male", 2 ~ "Female", .default = NA) |> as.factor(),
      
      marital_status =
        case_match(
          marital,
          1 ~ "Married",
          2 ~ "Divorced",
          3 ~ "Widowed",
          4 ~ "Separated",
          5 ~ "Never Married",
          6 ~ "Member of an unmarried couple (Partner)", 
          .default = NA) |> as.factor(),
      
      education_status =
        case_match(
          educag,
          1 ~ "Did not graduate High School", 
          2 ~ "Graduated High School",           
          3 ~ "Attended College or Technical School",
          4 ~ "Graduated from College or Technical School",
          .default = NA) |> as.factor(),
      
      employment_status =
        case_match(
          employ1,
          1 ~ "Employed for wages",
          2 ~ "Self-employed",
          3 ~ "Out of work (<1 year)",
          4 ~ "Out of work (>1 year)",
          5 ~ "Homemaker",
          6 ~ "Student",
          7 ~ "Retired",
          8 ~ "Unable to work (Disabled)",
          .default = NA) |> as.factor(),
      
      children_in_household = case_match(children, 88 ~ 0, 99 ~ NA, .default = children),
      
      income_level =
        case_match(
          income_standard,
          1 ~ "Less than $10,000",
          2 ~ "$10,000 to < $15,000",
          3 ~ "$15,000 to < $20,000",
          4 ~ "$20,000 to < $25,000",
          5 ~ "$25,000 to < $35,000",
          6 ~ "$35,000 to < $50,000",
          7 ~ "$50,000 to < $75,000",
          c(8, 9, 10, 11) ~ "$75,000 or more",
          .default = NA 
        ) |> as.factor(),
      
      insurance_coverage =
        case_match(
          hlthpl_standard,
          1 ~ "Have some form of insurance",
          2 ~ "Do not have some form of health insurance",
          9 ~ NA,
          .default = NA) |> as.factor(),
      
      race =
        case_match(
          imprace,
          1 ~ "White, Non-Hispanic",
          2 ~ "Black, Non-Hispanic",
          3 ~ "Asian, Non-Hispanic",
          4 ~ "American Indian, Alaska Native, Non-Hispanic",
          5 ~ "Hispanic",
          6 ~ "Other/Multiracial, Non-Hispanic",
          .default = NA) |> as.factor(),
      
      age_group_5yr =
        case_match(
          ageg5yr,
          1 ~ "18-24",
          2 ~ "25-29",
          3 ~ "30-34",
          4 ~ "35-39",
          5 ~ "40-44",
          6 ~ "45-49",
          7 ~ "50-54",
          8 ~ "55-59",
          9 ~ "60-64",
          10 ~ "65-69",
          11 ~ "70-74",
          12 ~ "75-79",
          13 ~ "80 or older",
          .default = NA) |> as.factor(),
      
      urban_status =
        case_match(
          urbstat,
          1 ~ "Urban counties",
          2 ~ "Rural counties",
          .default = NA) |> as.factor(),
      
      general_health =
        case_match(
          genhlth,
          1 ~ "Excellent",
          2 ~ "Very Good",
          3 ~ "Good",
          4 ~ "Fair",
          5 ~ "Poor",
          .default = NA) |> as.factor(),
      
      general_health_refactored =
        case_match(
          rfhlth,
          1 ~ "Good or Better Health",
          2 ~ "Fair or Poor Health",
          .default = NA) |> as.factor(),
      
      michd = case_match(michd, 1 ~ "Yes", 2 ~ "No", .default = NA) |> as.factor(),
      
      physical_health = case_match(physhlth, 88 ~ 0, 77 ~ NA, 99 ~ NA, .default = physhlth),
      physical_health_not_good_days = case_match(phys14d, 1 ~ "0", 2 ~ "1-13", 3 ~ "14+", 9 ~ NA, .default = NA) |> as.factor(),
      leisure_physical_activity_last_30_days = case_match(totinda, 1 ~ "Yes", 2 ~ "No", 9 ~ NA, .default = NA) |> as.factor(),
      
      mental_health = case_match(menthlth, 88 ~ 0, 77 ~ NA, 99 ~ NA, .default = menthlth),
      mental_health_not_good_days = case_match(ment14d, 1 ~ "0", 2 ~ "1-13", 3 ~ "14+", 9 ~ NA, .default = NA) |> as.factor(),
      
      depressive_disorder = case_match(addepe_standard, 1 ~ "Yes", 2 ~ "No", .default = NA) |> as.factor(),
      
      poor_health = case_match(poorhlth, 88 ~ 0, 77 ~ NA, 99 ~ NA, .default = poorhlth),
      
      binge_drink = case_match(rfbing_standard, 1 ~ "No", 2 ~ "Yes", 9 ~ NA, .default = NA) |> as.factor(),
      heavy_drink = case_match(rfdrh_standard, 1 ~ "No", 2 ~ "Yes", 9 ~ NA, .default = NA) |> as.factor(),
      
      medical_cost_barrier = case_match(medcost_standard, 1 ~ "Yes", 2 ~ "No", 7 ~ NA, 9 ~ NA, .default = NA) |> as.factor(),
      
      difficulty_self_care = case_match(diffalon, 1 ~ "Yes", 2 ~ "No", .default = NA) |> as.factor(),
    
      life_satisfaction =
        case_match(
          lsatisfy,
          1 ~ "Very satisfied",
          2 ~ "Satisfied",
          3 ~ "Dissatisfied",
          4 ~ "Very dissatisfied",
          .default = NA_character_
        ) |> as.factor(),
      
      emotional_support = 
        case_match(
          emtsuprt,
          1 ~ "Always",
          2 ~ "Usually",
          3 ~ "Sometimes",
          4 ~ "Rarely",
          5 ~ "Never",
          .default = NA_character_
        ) |> as.factor(),
      
      loneliness =
        case_match(
          sdlonely,
          1 ~ "Always",
          2 ~ "Usually",
          3 ~ "Sometimes",
          4 ~ "Rarely",
          5 ~ "Never",
          .default = NA_character_
        ) |> as.factor(),
      
      lost_reduced_employment = case_match(sdhemply, 1 ~ "Yes", 2 ~ "No", .default = NA) |> as.factor(),
      
      financial_strain_bills = case_match(sdhbills, 1 ~ "Yes", 2 ~ "No", .default = NA) |> as.factor(),
      financial_strain_utilities = case_match(sdhbills, 1 ~ "Yes", 2 ~ "No", .default = NA) |> as.factor(),
      
      # Adding binary versions of outcomes for prop tests and regression
      any_physical_health_not_good_days = 
        case_match(
          physical_health_not_good_days,
          "0" ~ FALSE,
          "1-13" ~ TRUE,
          "14+" ~ TRUE
        ),
      any_mental_health_not_good_days = 
        case_match(
          mental_health_not_good_days,
          "0" ~ FALSE,
          "1-13" ~ TRUE,
          "14+" ~ TRUE
        ),
      has_depressive_disorder = 
        case_match(
          depressive_disorder,
          "No" ~ FALSE, 
          "Yes" ~ TRUE
        ),
      has_binge_drink = 
        case_match(
          binge_drink,
          "No" ~ FALSE, 
          "Yes" ~ TRUE
        )
    ) |>
    
    #add in whether sports betting was legal at the time of the interview
    #NOTE: legalization dates are set to the first of the month so we will check that the interview was the following month (not day) by temporarily creating a new column month_of_interview
    merge(sb_legal_dates, by.x = "state", by.y = "fips", all = TRUE) |> 
    mutate(
      month_of_interview = floor_date(date, unit = "month"),
      sb_legal = (as.numeric(month_of_interview > first_start))
    ) |> 
    # dropping any overwritten variables
    select( 
        #Survey Identifiers
        id, date, qstver, 
        # Demographic/Predictor Variables
        state, urban_status, age_group_5yr, sex, marital_status, education_status, employment_status, children_in_household, income_level, race, insurance_coverage, 
        # Health/Financial Outcomes Variables
        medical_cost_barrier, general_health, general_health_refactored, michd, 
        physical_health, physical_health_not_good_days, leisure_physical_activity_last_30_days,
        mental_health, mental_health_not_good_days, poor_health, depressive_disorder, difficulty_self_care,
        life_satisfaction, emotional_support, loneliness,
        binge_drink, heavy_drink,
        lost_reduced_employment, financial_strain_bills, financial_strain_utilities,
        any_physical_health_not_good_days, any_mental_health_not_good_days, 
        has_depressive_disorder, has_binge_drink,
        #Sports Betting Legal
        sb_legal
      ) 
  
  
  cleaned_df
}

Analysis Data Dictionary

Our analysis focuses on the following treatment variable (exposure), outcome variables (adverse health indicator), and demographic variables.

Treatment Variable (Exposure)

  • sb_legal: A binary flag indicating whether the interview took place after sports betting was legalized in that state (\(\text{1}\)) or before (\(\text{0}\)).

Outcome Variables (Adverse Health)

We primarily use binary (Yes/No) measures to capture the prevalence of these adverse health outcomes in the population:

  • At least 1 poor mental health day:
    • Survey Question: “Now thinking about your mental health, which includes stress, depression, and problems with emotions, for how many days during the past 30 days was your mental health not good?”
    • If the respondent reported 1+ to this question, any_mental_health_not_good_days is TRUE.
  • At least 1 poor physical health day:
    • Survey Question: “Now thinking about your physical health, which includes physical illness and injury, for how many days during the past 30 days was your physical health not good?”
    • If the respondent reported 1+ to this question, any_physical_health_not_good_days is TRUE.
  • Depression:
    • Survey Question: “Has a doctor or other health professional ever told you that you had a depressive disorder, including depression, major depression, dysthymia, or minor depression?”
    • If the respondent reported “Yes” to this question, has_depressive_disorder is TRUE.
  • Binge Drinking:
    • Survey Question: “Considering all alcoholic beverages that you drink, on average, how many times per month do you have 5 (for men) or 4 (for women) or more drinks on one occasion?”
    • If the respondent reported “Yes” to this question, has_binge_drink is TRUE.

Demographic Variables

To control for social and economic factors influencing health, we include individual-level demographic predictors (e.g., sex, age group, income level, education, and employment status) in our regression models. These are important in our regression models.