The primary goal of this report is to use publicly-available data to better inform Promise Zone SNAP policy. Drawing on data from the Census Bureau and USDA, this report: 1) gives an overview of current SNAP conditions in the Promise Zone, 2) highlights changes in Promise Zone SNAP access over the last decade, and 3) provides actionable suggestions for improving access.
Three criteria for SNAP access are considered in this report: 1) SNAP enrollment, 2) the number of stores that accept SNAP vouchers, and 3) the types and locations of those stores. Additional metrics were calculated based on those data. These include the ratio of SNAP stores to SNAP enrollees per tract, the average SNAP income cutoff per tract, and the ratio of the median income per tract to the average SNAP cutoff per tract. For an explanation of how these were calculated and the underlying code, see the “Methodology” section at the end of this report.
SNAP access in the Promise Zone has declined dramatically over the last ten years. Stores accepting SNAP in the Promise Zone are poorly located relative to where SNAP enrollment is highest. Of the stores in the Promise Zone that accept SNAP, half are convenience stores and are therefore poorly-positioned to offer quality food options.
In order to fix these issues, this report recommends: 1) targeted SNAP enrollment outreach to residents in and around Powelton, 2) efforts to increase the number of stores in Mantua and Powelton that accept SNAP vouchers, and 3) efforts to boost the number of large grocery stores and supermarkets in the Promise Zone, ideally in Mantua.
This section outlines the current state of SNAP enrollment and access in the Promise Zone. The first map indicates the percent SNAP enrollment per tract. The second map and accompaying table indicate the locations and types of currently-active sites accepting SNAP vouchers in the Promise Zone. The final chart illustrates the types of stores accepting SNAP vouchers in the Promise Zone.
phl_demos <- get_acs(geography = "tract",
year = 2020, #Most recent available year
variables = c("B11001_001E", #Total number of households
"B22001_002E", #Number of hholds that received foodstamps/SNAP in last 12 months
"B19013_001E", #Median household income in last 12 months
"B25010_001E" #Avg household size
),
geometry = T, #we want this as a sf
state = "PA",
county = "Philadelphia",
output = "wide") |>
rename(tot_hh = B11001_001E,
snap_enroll = B22001_002E,
med_hh_inc = B19013_001E,
avg_hh_size = B25010_001E)
phl_demos <- phl_demos |>
mutate(perc_snap = snap_enroll / tot_hh * 100) |>
mutate(avg_snap_thresh = (12*(1396 + (492*(avg_hh_size-1))))) |>
mutate(med_hh_inc_as_perc_snap_thresh = med_hh_inc / avg_snap_thresh)|>
st_transform(crs = st_crs("EPSG:4326"))
#clean historic sites
historic_snap_sites$street_address <-paste(historic_snap_sites$Street.Number, historic_snap_sites$Street.Name, sep=" ")
historic_snap_sites = historic_snap_sites |>
mutate(end_year = year(mdy(End.Date)))
historic_snap_sites$end_year[is.na(historic_snap_sites$end_year)] <- "active"
#clean active sites
active_phl_sites <- historic_snap_sites |>
filter(end_year == "active")
#I'm using st_join() to join SNAP sites to their tract IDs. This works as long as the sites don't fall on a tract
#border, which is possible.
active_phl_sites = st_as_sf(active_phl_sites,
coords = c("Longitude", "Latitude"),
crs = st_crs("EPSG:4326"))
active_phl_sites = st_join(active_phl_sites, phl_tracts)
active_phl_sites_by_tract <- active_phl_sites |>
group_by(GEOID10) |>
tally()
active_phl_sites_by_tract$GEOID10 <- as.character(active_phl_sites_by_tract$GEOID10)
active_phl_sites_by_tract = st_transform(active_phl_sites_by_tract, st_crs("EPSG:4326"))
active_phl_sites_by_tract <- st_join(phl_demos, active_phl_sites_by_tract)
active_phl_sites_by_tract$n[is.na(active_phl_sites_by_tract$n)] = 0
active_phl_sites_by_tract <- active_phl_sites_by_tract |>
mutate(snap_per_hh = n / snap_enroll)
#Define logicals
#Defining a logical variable for tracts where the median household income is less than the average snap threshold for the tract
active_phl_sites_by_tract$below_snap_cut = case_when(
active_phl_sites_by_tract$med_hh_inc_as_perc_snap_thresh < 1 ~ "Yes",
active_phl_sites_by_tract$med_hh_inc_as_perc_snap_thresh >= 1 ~ "No"
)
active_phl_sites_by_tract[is.infinite(active_phl_sites_by_tract$snap_per_hh), ] <- NA
#Defining a categorical variable so that a low snap per hh value is anything below half the city-wide median of snap sites per hh per tract
active_phl_sites_by_tract$low_snap_per_hh = case_when(
active_phl_sites_by_tract$snap_per_hh < quantile(na.omit(active_phl_sites_by_tract$snap_per_hh),0.25) ~ "Yes",
active_phl_sites_by_tract$snap_per_hh >= quantile(na.omit(active_phl_sites_by_tract$snap_per_hh),0.25) ~ "No"
)
active_phl_sites_by_tract$snap_expand = case_when(
na.omit(active_phl_sites_by_tract$med_hh_inc) > active_phl_sites_by_tract$avg_snap_thresh ~ 0,
na.omit(active_phl_sites_by_tract$med_hh_inc) <= active_phl_sites_by_tract$avg_snap_thresh ~
(50 - active_phl_sites_by_tract$perc_snap))
active_phl_sites_by_tract$snap_expand[active_phl_sites_by_tract$snap_expand == 0] <- NA
active_phl_sites_by_tract$snap_expand_boolean = case_when(
na.omit(active_phl_sites_by_tract$med_hh_inc) > active_phl_sites_by_tract$avg_snap_thresh ~ "No",
na.omit(active_phl_sites_by_tract$med_hh_inc) <= active_phl_sites_by_tract$avg_snap_thresh ~ "Yes")
#Spatial clean
active_pz_sites = active_phl_sites[pz, ]
active_pz_sites_by_tract = active_phl_sites_by_tract[pz, ]
active_pz_largeorsuper = active_pz_sites |>
filter(Store.Type %in% c("Large Grocery Store", "Supermarket"))
active_pz_largeorsuper_buffer = st_buffer(active_pz_largeorsuper, units::as_units(0.5, "mile")) |> #dist has to be provided in units of CRS
st_transform(crs = st_crs("EPSG:4326"))
active_phl_largeorsuper = active_phl_sites |>
filter(Store.Type %in% c("Large Grocery Store", "Supermarket"))
active_phl_largeorsuper_buffer = st_buffer(active_phl_largeorsuper, units::as_units(0.5, "mile")) |> #dist has to be provided in units of CRS
st_transform(crs = st_crs("EPSG:4326"))
| Street Name | Store Type | Street Address | |
|---|---|---|---|
| 26 | 40th St Grocery | Small Grocery Store | 804 N 40th St |
| 27 | 42nd Street Food Market | Small Grocery Store | 920 N 42nd St |
| 28 | 44 Food Market Inc | Convenience Store | 701 N 44th St |
| 75 | 7-ELEVEN 22479A | Convenience Store | 3401 Lancaster Ave |
| 105 | 7-eleven Store 2408-35020a 35020A | Convenience Store | 3440 Market St |
| 110 | 8 Brother Associated Inc | Medium Grocery Store | 1127 N 40th St |
| 177 | ALDI 54 | Supermarket | 4421 Market St |
| 190 | Alexander Supermarket Inc | Convenience Store | 4035 Lancaster Ave |
| 266 | Boruco Mini Market Inc | Small Grocery Store | 4316 Parrish St |
| 317 | CHESTNUT BP | Convenience Store | 4600 Chestnut St |
| 423 | D8 Brothers Food Market & Deli Inc | Large Grocery Store | 4500 Lancaster Ave |
| 425 | Dana Mandi 0 | Medium Grocery Store | 4211 Chestnut St |
| 448 | Desh Bangla, LLC | Medium Grocery Store | 4319 Chestnut St |
| 471 | Dollar General 23121 | Combination Grocery/Other | 801 N 48th St |
| 527 | Dollar Warehouse | Convenience Store | 4007 Market St |
| 635 | Family Dollar Store 10581 | Combination Grocery/Other | 4061 Lancaster Ave |
| 703 | Giant Heirloom Market 6551 | Supermarket | 3401 Chestnut St |
| 708 | Girard Food Market I Inc | Small Grocery Store | 4200 W Girard Ave |
| 711 | Girard Neighorhood Food Market Inc | Convenience Store | 4058 W Girard Ave |
| 727 | Grab N Go Market | Convenience Store | 4026 Lancaster Ave |
| 796 | J & L Mini Market II | Small Grocery Store | 641 N 39th St |
| 815 | JAQUEZ GROCERY | Convenience Store | 856 N Holly St |
| 848 | Jose Alexander Cruz Inc | Convenience Store | 957 N 43rd St |
| 898 | L and P Fish Market Inc. | Medium Grocery Store | 4064 Lancaster Ave |
| 918 | Les No 1 Market Llc | Convenience Store | 423 N 36th St |
| 1050 | New Family Food Market Inc | Convenience Store | 1043 Belmont Ave |
| 1112 | Parrish Supermarket Inc | Convenience Store | 4529 Parrish St |
| 1173 | R D Mini Market Inc | Small Grocery Store | 340 N 41st St |
| 1193 | Rd Family Market Inc | Convenience Store | 3423 Haverford Ave |
| 1240 | RITE AID 3213 | Combination Grocery/Other | 4641 Chestnut St |
| 1247 | Rite Aid 11124 | Combination Grocery/Other | 4055 Market St |
| 1337 | Sanchez Mini Market | Convenience Store | 4630 Chestnut St |
| 1609 | Wawa Food Market 55 | Convenience Store | 3604 Chestnut St |
| 1620 | Wawa Store 8141 8141 | Convenience Store | 3300 Market St |
It is important to understand the history of SNAP access in the Promise Zone. The number of stores in the Promise Zone accepting SNAP vouchers has declined steadily, down 43.3% from its peak of 60 in 2013. Meanwhile, SNAP enrollment as a percentage of the tract population has dropped approximately 7% from its peak of 37% around 2015 to a current level of about 30%. Note, however, that the dropoff in SNAP sites (43%) has been much larger than the dropoff in SNAP enrollment (7%).
#Here it's possible to use area weighted spatial interpolation to get a good estimate of number of households in th Promise Zone, and the subset of that population that's enrolled in SNAP.
phl_demos_twenty = get_acs(geography = "tract",
year = 2020, #Most recent available year
variables = c("B11001_001E", #Total number of households
"B22001_002E" #Number of hholds that received foodstamps/SNAP in last 12 months
),
geometry = T, #we want this as a sf
state = "PA",
county = "Philadelphia",
output = "wide") |>
rename(tot_hh = B11001_001E,
snap_enroll = B22001_002E) |>
st_transform(crs = st_crs("EPSG:4326"))
#vars15 = load_variables(2015, "acs5")
#vars10 = load_variables(2010, "acs5")
phl_demos_fifteen = get_acs(geography = "tract",
year = 2015, #Most recent available year
variables = c("B11001_001E", #Total number of households
"B22001_002E" #Number of hholds that received foodstamps/SNAP in last 12 months
),
geometry = T, #we want this as a sf
state = "PA",
county = "Philadelphia",
output = "wide") |>
rename(tot_hh = B11001_001E,
snap_enroll = B22001_002E)|>
st_transform(crs = st_crs("EPSG:4326"))
phl_demos_ten = get_acs(geography = "tract",
year = 2010, #Most recent available year
variables = c("B11001_001E", #Total number of households
"B22001_002E" #Number of hholds that received foodstamps/SNAP in last 12 months
),
geometry = T, #we want this as a sf
state = "PA",
county = "Philadelphia",
output = "wide") |>
rename(tot_hh = B11001_001E,
snap_enroll = B22001_002E)|>
st_transform(crs = st_crs("EPSG:4326"))
pz_demos_twenty = st_interpolate_aw(phl_demos_twenty[, c(3,5)], pz, ext = TRUE) |>
mutate(year = 2020)
pz_demos_fifteen = st_interpolate_aw(phl_demos_fifteen[, c(3,5)], pz, ext = TRUE)|>
mutate(year = 2015)
pz_demos_ten = st_interpolate_aw(phl_demos_ten[, c(3,5)], pz, ext = TRUE)|>
mutate(year = 2010)
pz_historic_demos = rbind(pz_demos_twenty, pz_demos_fifteen, pz_demos_ten)
pz_historic_demos$year = as.character(pz_historic_demos$year)
pz_historic_demos = pz_historic_demos |>
mutate(pct_snap_enroll = snap_enroll / tot_hh*100)
pz_historic_demos$active_snap_sites = c(34, 56, 45)
The data available from the American Communities Survey and the USDA can inform more targeted policy to expand SNAP access.
First, ACS data can be used to identify where SNAP enrollment is lower than expected. Comparing the median income per tract to the predicted SNAP cutoff per tract indicates whether SNAP enrollment in that tract could be higher. For tracts where the median income is lower than the SNAP cutoff, at least 50% of the population should be eligible for SNAP. If SNAP enrollment is lower than 50%, then SNAP enrollment can likely be expanded in that tract.
Second, the ratio of SNAP-accepting stores per tract to SNAP-enrolled households per tract indicates whether SNAP supply meets demand. In the map below, tracts in yellow are those where the ratio of SNAP stores to SNAP-enrolled households is in the bottom quartile city-wide, suggesting that supply may be insufficient.
(Both these measures are imperfect. They are meant to give a sense of what tracts most need higher enrollment or better access, and what the approximate magnitude of that need is, but they cannot project an exact target enrollment percentage or ratio of SNAP stores to enrolled households.)
Finally, the locations of the only three large grocery stores or supermarkets are indicated in black, with purple buffers to indicate a walkable range (half a mile). Areas not covered by these buffers would likey benefit from increased access to large, high-quality grocery stores.
These maps below compare the most recently-available SEPTA bus and rail routes to the locations of active SNAP-accepting large grocery stores and supermarkets in and around the Promise Zone.