Executive summary

Why Pennsylvania

We are taking a deeper dive into changes in Pennsylvania’s BBCE asset test policies since its $5,000 asset test implementation and elimination are the cleanest of the states with BBCE + asset limits. For the most part, I compare Pennsylvania to states with BBCE but who have never implemented as asset test, of which there are 38 + DC.

Results

Implementation of a $5,000 asset test in Pennsylvania was associated with a roughly 16% decrease in SNAP beneficiaries in the period when the asset test was active (6/1/2012 - 5/1/2015). The elimination of the test in 2015 was not associated with a change in the number of SNAP beneficiaries. (pooled diff-in-diff)

The event study for the asset test implementation exhibits no significant pre-trend in the periods immediately prior and shows a significant decrease in SNAP beneficiaries for most periods post-implementation, where the window I look at is 24 months on either side of the event. The event study for the elimination shows increased enrollment after the elimination of the asset test but with a significant pre-trend. The effect does rise above a linear pre-trend, though. (event studies)

Specifications for the pooled DiD and event studies include state and time fixed effects with no other controls and standard errors clustered at the level of the state. The regression specifications are described below.

BBCE timeline

Dates and comparisons to other states

Dates

10/2008: Enacted BBCE for SNAP. Income limit set to 130 FPL, 200 FPL for households with at least one senior or disabled member.

08/2009: Income limit raised to 160 FPL. Still 200 for households with at least one senior or disabled member.

06/2012*: Asset limit of $5,500 implemented, excluding part of the value of at least one (but not all) vehicles.

05/2015*: Asset limit eliminated.

*our events of interest

The raw data

Pennsylvania follows the general trend among states with asset test.

plot_data <- subset(snap_data, state %in% c('AL','AK','ID','PA','MI','NE','TX') &
                               date >= as.Date('1900-01-01'))

ggplot(plot_data[plot_data$date != as.Date('1989-06-01'),], aes(x = date, y = people_count/1000, group = state, color = state)) +
    geom_line() +
    geom_point() +
    scale_y_log10() +
    labs(title = 'date-over-date level change for asset-test states (levels)',
         y = 'SNAP recipients (thousands)')
## Warning: Removed 6 rows containing missing values or values outside the scale range
## (`geom_point()`).

In % change

Here’s a look at how PA compares to non-asset test states w.r.t. percent change in SNAP recipients across 6-month time periods. Data is noisy but PA again generally follows trends in other BBCE states with no asset tests.

# Function to compare policy change states to non-changing states

log_plots <- function(states){
    
    plot_data_logs <- snap_data %>%
        group_by(state) %>%
        arrange(date) %>%
        mutate(bene_change_people = people_count / lag(people_count) - 1) %>%
        ungroup() %>%
        subset(., state %in% states)
    
    plot_data_logs <- rbind(plot_data_logs[,c('state','date','bene_change_people')], 
                            # snap_data[snap_data$state == 'OH',c('state','date','bene_change_people')]) %>%
                            snap_change_BBCE_noasset[,c('state','date','bene_change_people')]) %>%
        subset(date >= as.Date('2001-01-01') &
                   date < as.Date('2020-01-01'))#start_date)
    
    plot_data_logs$state <- factor(plot_data_logs$state, levels = state_order)
    
    plot_data_logs$state[is.na(plot_data_logs$state)] <- c('other states')
    
    plot <- ggplot(plot_data_logs, aes(x = date, y = bene_change_people, group = state, color = state)) +
        geom_line() +
        geom_point() +
        scale_color_manual(values = state_palette) +
        theme_minimal() +
        labs(x = "date", y = "% change in # SNAP recipients", color = "State Code", title = paste0("date-over-date change, ",states))
    
    return(plot)
    
}

plot <- log_plots('PA')

plot + 
    geom_vline(xintercept = as.Date('2008-10-01'), color = 'orange3', alpha = 0.7) +
    annotate("text", x = as.Date('2008-10-01'), y = 0.25, label = "PA BBCE", 
             vjust = 1.5, hjust = 1, angle = 90, color = 'grey42') +
    # geom_vline(xintercept = as.Date('2009-08-01'), color = 'green3', alpha = 0.7) +
    geom_vline(xintercept = as.Date('2012-06-01'), color = 'red3', alpha = 0.7) + 
    annotate("text", x = as.Date('2012-06-01'), y = 0.25, label = "Asset limit (PA)", 
             vjust = 1.5, hjust = 1, angle = 90, color = 'grey42') +
    geom_vline(xintercept = as.Date('2015-05-01'), color = 'green3', alpha = 0.7) +
    annotate("text", x = as.Date('2015-05-01'), y = 0.25, label = "Eliminated (PA)", 
             vjust = 1.5, hjust = 1, angle = 90, color = 'grey42') +
    labs(title = 'Date-over-date change, PA vs. other BBCE (no asset limit) states')

DiD and event studies

Pooled diff-in-diffs

Below are the results of two groups of pooled diff-in-diffs: one where the event is the implementation of the $5,000 asset test in 6/1/2012, and another where the event is the elimination of the same asset test in 5/1/2015. All event studies include state and time fixed effects with no other controls, standard errors clustered at the level of the state.

For the implementation event study, I only include post-periods between the implementation (6/1/2012) and the elimination (5/1/2015) of the asset test.

Pooled diff-in-diff (1): log(number of beneficiaries)

\[\log(\text{SNAP benes #}) = \beta_0 + \beta_1AssetTest_s \times \textbf{1}_{t \geq 0}+\alpha_s + \gamma_{kt} + \epsilon_{kit}\]

Pooled diff-in-diff (2): rate of change in beneficiaries \[\text{Change in SNAP benes #} = \omega_0 + \omega_1AssetTest_s \times \textbf{1}_{t \geq 0}+\alpha_s + \gamma_{kt} + \epsilon_{kit}\] Compared to states that have no asset tests, Pennsylvania sees a significant decrease in enrollment (\(\beta_1 = -0.155, p < 0.01\)) after the implementation of the asset test in 2012. There is no a significant change in the number of beneficiaries after its repeal in 2015.

Implementation of asset test

PA_asset_start <- as.Date('2012-06-01')
PA_asset_end <- as.Date('2015-05-01')

# $5,000 asset test implementation

PA_experiment <- snap_data[snap_data$state %in% bbce_states,] %>%
    rbind(.,snap_data[snap_data$state ==  'PA',]) %>%
    mutate('t_months' = round(as.numeric(difftime(date, PA_asset_start, units = 'days') / 365 * 12)))

PA_experiment <- PA_experiment[PA_experiment$date < PA_asset_end,]

PA_experiment$treated <- ifelse(PA_experiment$state == 'PA',1,0)
PA_experiment$post <- ifelse(PA_experiment$t_months>0,1,0)

asset_felm1 <- felm(log(people_count) ~ treated:post | state + t_months|0|state,data = PA_experiment)
asset_felm2 <- felm(bene_change_people ~ treated:post | state + t_months|0|state,data = PA_experiment)

stargazer(asset_felm1, 
          asset_felm2,
          type = 'text',
          keep.stat = c('adj.rsq'))
## 
## =================================================
##                      Dependent variable:         
##              ------------------------------------
##              log(people_count) bene_change_people
##                     (1)               (2)        
## -------------------------------------------------
## treated:post     -0.155***          0.013***     
##                   (0.037)           (0.003)      
##                                                  
## -------------------------------------------------
## Adjusted R2        0.977             0.068       
## =================================================
## Note:                 *p<0.1; **p<0.05; ***p<0.01

Elimination of asset test

# $5,000 asset test eliminated

PA_experiment <- snap_data[snap_data$state %in% bbce_states,] %>%
    rbind(.,snap_data[snap_data$state ==  'PA',]) %>%
    mutate('t_months' = round(as.numeric(difftime(date, PA_asset_end, units = 'days') / 365 * 12)))

PA_experiment$treated <- ifelse(PA_experiment$state == 'PA',1,0)
PA_experiment$post <- ifelse(PA_experiment$t_months>0,1,0)

asset_felm1 <- felm(log(people_count) ~ treated:post | state + t_months|0|state,data = PA_experiment)
asset_felm2 <- felm(bene_change_people ~ treated:post | state + t_months|0|state,data = PA_experiment)

stargazer(asset_felm1,
          asset_felm2,
          type = 'text',
          keep.stat = c('adj.rsq'))
## 
## =================================================
##                      Dependent variable:         
##              ------------------------------------
##              log(people_count) bene_change_people
##                     (1)               (2)        
## -------------------------------------------------
## treated:post       0.011            0.020***     
##                   (0.039)           (0.004)      
##                                                  
## -------------------------------------------------
## Adjusted R2        0.975             0.084       
## =================================================
## Note:                 *p<0.1; **p<0.05; ***p<0.01

Event studies

Same experiment as above but as event studies. I’ve drawn in pre-trend lines using the four periods leading up to the policy change, though the regression itself is no an explicit honest DiD.

Specification: \[\log(\text{SNAP benes #}) = \beta_0 + \sum_{\tau \neq -1}\beta_tAssetTest_s \times \textbf{1}_{\tau = t}+\alpha_s + \gamma_{kt} + \epsilon_{kit}\]

Implementation of asset test

Where event is implementation of the asset limit (6/1/2012). Looking at a 2-year window on either side of the event.

# $5,000 asset test implementation
PA_experiment$t_months <- round(as.numeric(difftime(PA_experiment$date, PA_asset_start, units = 'days') / 365 * 12)) %>%
    factor(.,levels = c(-5, sort(as.numeric(setdiff(unique(.), -5)))))

PA_experiment <- subset(PA_experiment, !is.na(people_count))

asset_feols1 <- feols(log(people_count) ~  i(t_months,treated,-5) | state + t_months,cluster = ~state, data = PA_experiment)
# asset_feols1$coefficients

# Ensure 't_months' is a factor and set the baseline
# PA_experiment  <- within(PA_experiment, t_months <- relevel(t_months, ref = "-5"))
# PA_experiment$t_months <- factor(PA_experiment$t_months, levels = c(-5, sort(as.numeric(setdiff(unique(PA_experiment$t_months), -5)))))
# asset_felm1 <- felm(log(people_count) ~  treated:t_months | state + t_months|0|state,data = PA_experiment)
# asset_felm2 <- felm(bene_change_people ~ treated:t_months | state + t_months|0|state,data = PA_experiment)


coefficients <- coef(asset_feols1)
standard_errors <- asset_feols1$se
results_df1 <- data.frame(Coefficient = coefficients, Standard_Error = standard_errors) %>%
    mutate('Time_Relative_to_Event' = as.numeric(gsub(".*?(-?\\d+).*", "\\1", rownames(.)))) %>%
    rbind(c(0,0,-5))

pre_trend <- lm(Coefficient ~ Time_Relative_to_Event, data = results_df1[results_df1$Time_Relative_to_Event > -28 & results_df1$Time_Relative_to_Event < 0,])
pre_trend_line <- data.frame('Time_Relative_to_Event' = seq(-23,25,1),
                             'Coefficient' = pre_trend$coefficients[1] + seq(-23,25,1) * pre_trend$coefficients[2])

ggplot(results_df1[as.numeric(results_df1$Time_Relative_to_Event) >= -25 & as.numeric(results_df1$Time_Relative_to_Event) <= 25,], aes(x = PA_asset_start %m+% months(as.numeric(Time_Relative_to_Event)), y = Coefficient)) +
    geom_point(color = 'dodgerblue4') +
    geom_errorbar(aes(ymin = Coefficient - 1.96 * Standard_Error, ymax = Coefficient + 1.96 * Standard_Error), width = 0.2, color = 'dodgerblue2') +
    geom_line(aes(x = PA_asset_start %m+% months(as.numeric(Time_Relative_to_Event)), y = Coefficient), data = pre_trend_line, color = 'grey30', linetype = 'dotted') +
    annotate("text", x = as.Date('2013-01-01'), y = 0, label = "pre-trend", 
             vjust = 2, hjust = 1, angle = -10, color = 'grey42') +
    labs(x = "Date", y = "Coefficient estimate", title = "Number of SNAP beneficiaries (log)") +
    theme_minimal() +
    geom_vline(xintercept = PA_asset_start,
               color = 'grey', linetype = 'dashed') +
    annotate("text", x = PA_asset_start, y = -0.025, label = "Implementation", 
             vjust = -0.5, hjust = 1, angle = 90, color = 'grey42') +
    geom_hline(yintercept = 0,
               color = 'grey') +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

# ggplot(results_df1, aes(x = as.numeric(Time_Relative_to_Event), y = Coefficient)) +
#     geom_point(color = 'dodgerblue4') +
#     geom_errorbar(aes(ymin = Coefficient - 1.96 * Standard_Error, ymax = Coefficient + 1.96 * Standard_Error), width = 0.2, color = 'dodgerblue2') +
#     geom_vline(xintercept = 0,
#                color = 'grey', linetype = 'dashed') +
#     geom_hline(yintercept = 0,
#                color = 'grey') +
#     labs(x = "Date", y = "Coefficient estimate", title = "Number of SNAP beneficiaries (log)") +
#     theme_minimal() +
#     theme(axis.text.x = element_text(angle = 45, hjust = 1))

Elimination of asset test

Where event is elimination of the asset limit (5/1/2015)

# $5,000 asset test eliminated

PA_experiment$t_months <- round(as.numeric(difftime(PA_experiment$date, PA_asset_end, units = 'days') / 365 * 12)) %>%
    factor(.,levels = c(-4, sort(as.numeric(setdiff(unique(.), -4)))))

PA_experiment <- subset(PA_experiment, !is.na(people_count))

asset_feols2 <- feols(log(people_count) ~  i(t_months,treated,-4) | state + t_months,cluster = ~state, data = PA_experiment)
# asset_feols2$coefficients

# Ensure 't_months' is a factor and set the baseline
# PA_experiment  <- within(PA_experiment, t_months <- relevel(t_months, ref = "-5"))
# PA_experiment$t_months <- factor(PA_experiment$t_months, levels = c(-5, sort(as.numeric(setdiff(unique(PA_experiment$t_months), -5)))))
# asset_felm1 <- felm(log(people_count) ~  treated:t_months | state + t_months|0|state,data = PA_experiment)
# asset_felm2 <- felm(bene_change_people ~ treated:t_months | state + t_months|0|state,data = PA_experiment)


coefficients <- coef(asset_feols2)
standard_errors <- asset_feols2$se
results_df2 <- data.frame(Coefficient = coefficients, Standard_Error = standard_errors) %>%
    mutate('Time_Relative_to_Event' = as.numeric(gsub(".*?(-?\\d+).*", "\\1", rownames(.)))) %>%
    rbind(c(0,0,-4))

pre_trend <- lm(Coefficient ~ Time_Relative_to_Event, data = results_df2[results_df2$Time_Relative_to_Event > -28 & results_df2$Time_Relative_to_Event < 0,])
pre_trend_line <- data.frame('Time_Relative_to_Event' = seq(-22,22,1),
                             'Coefficient' = pre_trend$coefficients[1] + seq(-22,22,1) * pre_trend$coefficients[2])

ggplot(results_df2[as.numeric(results_df2$Time_Relative_to_Event) >= -25 & as.numeric(results_df2$Time_Relative_to_Event) <= 25,], aes(x = PA_asset_end %m+% months(as.numeric(Time_Relative_to_Event)), y = Coefficient)) +
    geom_point(color = 'dodgerblue4') +
    geom_errorbar(aes(ymin = Coefficient - 1.96 * Standard_Error, ymax = Coefficient + 1.96 * Standard_Error), width = 0.2, color = 'dodgerblue2') +
    geom_line(aes(x = PA_asset_end %m+% months(as.numeric(Time_Relative_to_Event)), y = Coefficient), data = pre_trend_line, color = 'grey30', linetype = 'dotted') +
    annotate("text", x = as.Date('2017-01-01'), y = 0.05, label = "pre-trend", 
             vjust = -1.5, hjust = 1, angle = 20, color = 'grey42') +
    geom_vline(xintercept = PA_asset_end,
               color = 'grey', linetype = 'dashed') +
    annotate("text", x = PA_asset_end, y = 0.095, label = "Elimination", 
             vjust = -0.5, hjust = 1, angle = 90, color = 'grey42') +
    geom_hline(yintercept = 0,
               color = 'grey') +
    labs(x = "Month relative to elimination", y = "Coefficient estimate", title = "Number of SNAP beneficiaries (log)") +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

All periods

A broad look at all periods for which there is USDA data.

ggplot(results_df2, aes(x = PA_asset_end %m+% months(as.numeric(Time_Relative_to_Event)), y = Coefficient)) +
    geom_point(color = 'dodgerblue4') +
    geom_errorbar(aes(ymin = Coefficient - 1.96 * Standard_Error, ymax = Coefficient + 1.96 * Standard_Error), width = 0.2, color = 'dodgerblue2') +
    geom_vline(xintercept = as.Date('2008-10-01'), color = 'orange3', alpha = 0.7) +
    annotate("text", x = as.Date('2008-10-01'), y = 0.4, label = "PA BBCE", 
             vjust = -0.5, hjust = 1, angle = 90, color = 'grey42') +
    geom_vline(xintercept = PA_asset_start,
               color = 'green4', linetype = 'dashed') +
    annotate("text", x = PA_asset_start, y = 0.4, label = "Implementation", 
             vjust = -0.5, hjust = 1, angle = 90, color = 'grey42') +
    geom_vline(xintercept = PA_asset_end,
               color = 'red4', linetype = 'dashed') +
    annotate("text", x = PA_asset_end, y = 0.4, label = "Elimination", 
             vjust = -0.5, hjust = 1, angle = 90, color = 'grey42') +
    geom_hline(yintercept = 0,
               color = 'grey') +
    labs(x = "Month relative to elimination", y = "Coefficient estimate", title = "Number of SNAP beneficiaries (log)") +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))