From b3541298e303bbd03feb00a586f1b9085dfab54b Mon Sep 17 00:00:00 2001 From: Nissim Lebovits <111617674+nlebovits@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:42:54 -0500 Subject: [PATCH] Built site for gh-pages --- .nojekyll | 2 +- assets/permits_animation.gif | Bin 52990 -> 59161 bytes final.html | 786 ++++++++++++++++------------------- index.html | 786 ++++++++++++++++------------------- 4 files changed, 725 insertions(+), 849 deletions(-) diff --git a/.nojekyll b/.nojekyll index f7c8040..4f7ec7b 100644 --- a/.nojekyll +++ b/.nojekyll @@ -1 +1 @@ -334f3c1f \ No newline at end of file +4d8fcb43 \ No newline at end of file diff --git a/assets/permits_animation.gif b/assets/permits_animation.gif index 23c5f411044ca610f3f2dd76e5c5a125f4119a48..58a1d0fd71cd0d9ebc92644cb4cb6ee071be9c31 100644 GIT binary patch literal 59161 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 literal 52990 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 of contents
  • 1 Background
  • 2 Overview
  • -
  • 3 Select and Engineer Features +
  • 3 Feature Selection and Engineering
  • -
  • 4 Build Predictive Models +
  • 4 Model Building
  • -
  • 5 Model Validation
  • +
  • 5 Model Testing
  • 6 Discussion
    • 6.1 Accuracy
    • @@ -9285,8 +9285,8 @@

      -

      3 Select and Engineer Features

      +
      +

      3 Feature Selection and Engineering

      This study leverages open data sources including permit counts, council district boundaries, racial mix, median income, housing cost burden to holistically understand what drives development pressure. Generally, data is collected at the block group or parcel level and aggregated up to the council district to capture both local and more citywide trends.

      @@ -9324,9 +9324,10 @@

      -

      3.1 Permits

      -

      Firstly, 10 years of permit data from 2012 to 2023 from the Philadelphia Department of Licenses and Inspections are critical to the study. This study filters only for new construction permits granted for residential projects. In the future, filtering for full and substantial renovations could add more nuance to what constitutes as development pressure.

      +
      +

      3.1 Construction Permits

      +

      Permit data from 2013 through 2023, collected from the Philadelphia Department of Licenses & Inspections, are the basis of our model. We consider only new construction permits granted for residential projects, but in the future, filtering for data on “full” or “substantial” renovations could add nuance to the compelexities of development pressure. Given the granular spatial scale of our analysis, and the need to aggregate Census data to our unit of analysis, we chose to aggregate these permits data to the block group level.

      +

      Construction Permits per Year Philadelphia, PA

      Show the code @@ -9335,176 +9336,187 @@

      tm_facets(along = "year") + tm_shape(broad_and_market) + tm_lines(col = "darkgrey") + - tm_layout(frame = FALSE), - "New Construction Permits per Year\nPhiladelphia, PA") - -suppressMessages( -tmap_animation(tm, "assets/permits_animation.gif", delay = 50) -)

      + tm_layout(frame = FALSE)) + +suppressMessages( +tmap_animation(tm, "assets/permits_animation.gif", delay = 50) +)
      -

      +

      Philadelphia Building Permits, 2013 - 2023
      -

      The spike in new construction permits in 2021 is reasonably attributed to the expiration of a tax abatement program for developers.

      +
      +
      +Show the code +
      ggplot(building_permits %>% filter(!year %in% c(2024)), aes(x = as.factor(year))) +
      +  geom_bar(fill = palette[1], color = NA, alpha = 0.7) +
      +  labs(title = "Permits per Year",
      +       y = "Count") +
      +  theme_minimal() +
      +  theme(axis.title.x = element_blank(),
      +        aspect.ratio = .75)
      +
      +
      +

      +
      +
      +

      We note a significant uptick in new construction permits as we approach 2021, followed by a sharp decline. It is generally acknowledged that this trend was due to the expiration of a tax abatement program for developers.

      When assessing new construction permit count by Council Districts, a few districts issued the bulk of new permits during that 2021 peak. Hover over the lines to see more about the volume of permits and who granted them.

      Show the code -
      perms_x_dist <- st_join(building_permits, council_dists)
      -
      -perms_x_dist_sum <- perms_x_dist %>%
      -                  st_drop_geometry() %>%
      -                  group_by(DISTRICT, year) %>%
      -                  summarize(permits_count = n())
      -
      -perms_x_dist_mean = perms_x_dist_sum %>%
      -                      group_by(year) %>%
      -                      summarize(permits_count = mean(permits_count)) %>%
      -                      mutate(DISTRICT = "Average")
      -
      -perms_x_dist_sum <- bind_rows(perms_x_dist_sum, perms_x_dist_mean) %>%
      -                        mutate(color = ifelse(DISTRICT != "Average", 0, 1))
      -
      -ggplotly(
      -ggplot(perms_x_dist_sum %>% filter(year > 2013, year < 2024), aes(x = year, y = permits_count, color = as.character(color), group = interaction(DISTRICT, color))) +
      -  geom_line(lwd = 0.7) +
      -  labs(title = "Permits per Year by Council District",
      -       y = "Total Permits") +
      -  # facet_wrap(~DISTRICT) +
      -  theme_minimal() +
      -  theme(axis.title.x = element_blank(),
      -        legend.position = "none") +
      -  scale_color_manual(values = c(palette[5], palette[1]))
      -)
      +
      perms_x_dist <- st_join(building_permits, council_dists)
      +
      +perms_x_dist_sum <- perms_x_dist %>%
      +                  st_drop_geometry() %>%
      +                  group_by(DISTRICT, year) %>%
      +                  summarize(permits_count = n())
      +
      +perms_x_dist_mean = perms_x_dist_sum %>%
      +                      group_by(year) %>%
      +                      summarize(permits_count = mean(permits_count)) %>%
      +                      mutate(DISTRICT = "Average")
      +
      +perms_x_dist_sum <- bind_rows(perms_x_dist_sum, perms_x_dist_mean) %>%
      +                        mutate(color = ifelse(DISTRICT != "Average", 0, 1))
      +
      +ggplotly(
      +ggplot(perms_x_dist_sum %>% filter(year > 2013, year < 2024), aes(x = year, y = permits_count, color = as.character(color), group = interaction(DISTRICT, color))) +
      +  geom_line(lwd = 0.7) +
      +  labs(title = "Permits per Year by Council District",
      +       y = "Total Permits") +
      +  # facet_wrap(~DISTRICT) +
      +  theme_minimal() +
      +  theme(axis.title.x = element_blank(),
      +        legend.position = "none") +
      +  scale_color_manual(values = c(palette[5], palette[1]))
      +)
      -
      - +
      +
      -
      -

      3.2 Feature Engineering by Time and Space

      +
      +

      3.2 Spatio-Temporal Features

      New construction exhibits sizable spatial and temporal autocorrelation. In other words, there is a strong relationship between the number of permits in a given block group and the number of permits in neighboring block groups; as well as between the number of permits issued in a block group in a given year and the number of permits issued in that same block group in the previous year. To account for these relationships, we engineer new features, including both space and time lags. We note that all of these engineered features have strong correlation coefficients with our dependent variable, permits_count, and p-values indicating that these relationships are statistically significant.

      Show the code -
      permits_bg_long <- permits_bg %>%
      -                    filter(!year %in% c(2024)) %>%
      -                    st_drop_geometry() %>%
      -                    pivot_longer(
      -                      cols = c(starts_with("lag"), dist_to_2022),
      -                      names_to = "Variable",
      -                      values_to = "Value"
      -                    )
      -
      -
      -ggscatter(permits_bg_long, x = "permits_count", y = "Value", facet.by = "Variable",
      -   add = "reg.line",
      -   add.params = list(color = palette[3], fill = palette[5]),
      -   conf.int = TRUE
      -   ) + stat_cor(method = "pearson", p.accuracy = 0.001, r.accuracy = 0.01)
      +
      permits_bg_long <- permits_bg %>%
      +                    filter(!year %in% c(2024)) %>%
      +                    st_drop_geometry() %>%
      +                    pivot_longer(
      +                      cols = c(starts_with("lag"), dist_to_2022),
      +                      names_to = "Variable",
      +                      values_to = "Value"
      +                    )
      +
      +
      +ggscatter(permits_bg_long, x = "permits_count", y = "Value", facet.by = "Variable",
      +   add = "reg.line",
      +   add.params = list(color = palette[3], fill = palette[5]),
      +   conf.int = TRUE
      +   ) + stat_cor(method = "pearson", p.accuracy = 0.001, r.accuracy = 0.01)

      -
      -

      3.3 Socioeconomics

      -

      Racial Mix (white vs non-white), median income, and housing cost burden are socioeconomic factors that often play an outsized role in affordability in cities like Philadelphia, with a pervasive and persistent history of housing discrimination and systemic disinvestment. This data is all pulled from the US Census Bureau’s American Community Survey 5-Year survey.

      +
      +

      3.3 Socioeconomic Features

      +

      Socioeconomic factors such as race, income, and housing cost burden play an outsized role in affordability in cities like Philadelphia, which are marred by a pervasive and persistent history housing discrimination and systemic disinvestment in poor and minority neighborhoods. To account for these issues, we incorporate various data from the US Census Bureau’s American Community Survey 5-Year survey. Later, we also consider our model’s generalizability across different racial and economic contexts to ensure that it will not inadvertently reinforce structural inequity.

      Spatially, is clear that non-white communities earn lower median incomes and experience higher rates of extreme rent burden (household spends more than 35% of income on gross rent).

      Show the code -
      med_inc <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      -        tm_polygons(col = "med_inc", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Med. Inc. ($)") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "darkgrey") +
      -  tm_layout(frame = FALSE),
      -  "Median Income")
      -  
      -race <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      -        tm_polygons(col = "percent_nonwhite", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Nonwhite (%)") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "darkgrey") +
      -  tm_layout(frame = FALSE),
      -  "Race")
      -  
      -rent_burd <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      -        tm_polygons(col = "ext_rent_burden", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Rent Burden (%)") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "darkgrey") +
      -  tm_layout(frame = FALSE),
      -  "Extreme Rent Burden")
      -  
      -tmap_arrange(med_inc, race, rent_burd)
      +
      med_inc <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      +        tm_polygons(col = "med_inc", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Med. Inc. ($)") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "darkgrey") +
      +  tm_layout(frame = FALSE),
      +  "Median Income")
      +  
      +race <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      +        tm_polygons(col = "percent_nonwhite", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Nonwhite (%)") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "darkgrey") +
      +  tm_layout(frame = FALSE),
      +  "Race")
      +  
      +rent_burd <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      +        tm_polygons(col = "ext_rent_burden", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Rent Burden (%)") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "darkgrey") +
      +  tm_layout(frame = FALSE),
      +  "Extreme Rent Burden")
      +  
      +tmap_arrange(med_inc, race, rent_burd)

      -

      Considering the strong spatial relationship between socioeconomics and certain areas of Philadelphia, we will be sure to investigate our model’s generalizability against race and income.

      -
      -

      4 Build Predictive Models

      +
      +

      4 Model Building

      “All the complaints about City zoning regulations really boil down to the fact that City Council has suppressed infill housing or restricted multi-family uses, which has served to push average housing costs higher.” - Jon Geeting, Philly 3.0 Engagement Director

      SmartZoning® seeks to predict where permits are most likely to be filed as a measure to predict urban growth. As discussed, predicting growth is fraught because growth is influenced by political forces rather than by plans published by the city’s Planning Commission. Comprehensive plans, typically set on ten-year timelines, tend to become mere suggestions, ultimately subject to the prerogatives of city council members rather than serving as steadfast guides for smart growth. With these dynamics in mind, SmartZoning’s prediction model accounts for socioeconomics, council district, and time-space lag.

      -
      -

      4.1 Tests for Correlation

      -

      The goal is to select variables that most significantly correlate to permit count to include in the predictive model. Correlation is a type of association test. For example, are permit counts more closely associated to population or to median income? Or, do racial mix and rent burden offer redundant insight? These are the types of subtle but important distinctions we aim to seek out.

      +
      +

      4.1 Tests for Correlation and Collinearity

      4.1.1 Correlation Coefficients

      +

      In building our model, we aim to select variables that correlate significantly with permit_count. Using a correlation matrix, we can assess whether our predictors are, in fact, meaningfully associated with our dependent variable. As it turns out, socioeconomic variables are not (we exclude the other variables, which we have previously established to be significant), but we retain them for the sake of later analysis.

      Show the code -
      corr_vars <- c("total_pop",
      -               "med_inc",
      -               "percent_nonwhite",
      -               "percent_renters",
      -               "rent_burden",
      -               "ext_rent_burden")
      -
      -corr_dat <- permits_bg %>% select(all_of(corr_vars), permits_count) %>% select(where(is.numeric)) %>% st_drop_geometry() %>% unique() %>% na.omit()
      -
      -corr <- round(cor(corr_dat), 2)
      -p.mat <- cor_pmat(corr_dat)
      -
      -ggcorrplot(corr, p.mat = p.mat, hc.order = TRUE,
      -    type = "full", insig = "blank", lab = TRUE, colors = c(palette[2], "white", palette[3])) +
      -  annotate(
      -  geom = "rect",
      -  xmin = .5, xmax = 7.5, ymin = 4.5, ymax = 5.5,
      -  fill = "transparent", color = "red", alpha = 0.5
      -)
      +
      corr_vars <- c("total_pop",
      +               "med_inc",
      +               "percent_nonwhite",
      +               "percent_renters",
      +               "rent_burden",
      +               "ext_rent_burden")
      +
      +corr_dat <- permits_bg %>% select(all_of(corr_vars), permits_count) %>% select(where(is.numeric)) %>% st_drop_geometry() %>% unique() %>% na.omit()
      +
      +corr <- round(cor(corr_dat), 2)
      +p.mat <- cor_pmat(corr_dat)
      +
      +ggcorrplot(corr, p.mat = p.mat, hc.order = FALSE,
      +    type = "full", insig = "blank", lab = TRUE, colors = c(palette[2], "white", palette[3])) +
      +  annotate(
      +  geom = "rect",
      +  xmin = .5, xmax = 7.5, ymin = 6.5, ymax = 7.5,
      +  fill = "transparent", color = "red", alpha = 0.5
      +)
      -

      +

      4.1.2 VIF

      -

      To ensure that our predictive model does not have multicollinearity, or multiple values telling the same story about permit counts, we use the VIF test. The table below lists each variables’s VIF score. Variables that have over a 5 are considered to potentially have some multicollinearity, and those over 10 certainly need to be flagged. Generally the council district and zoning overlays such as historic districts may be conflicting.

      -

      Based on VIF, we drop:

      -

      hist_dist_na 33.120644 district8 32.900255 district4 32.164688 district9 30.834357 district5 29.393431 district3 29.092806 district2 28.580678 district1 27.199582 district7 26.741373 hist_dist_historic_street_paving_thematic_district 26.735386 district6 19.912382 overlay_fne 15.601603 overlay_ne 11.179327 overlay_nis 7.717070 overlay_ndo 6.867713 overlay_fdo 6.574022 overlay_edo 5.595256 overlay_vdo 5.400210

      +

      We also aim to minimize or eliminate multicollinearity in our model. For this purpose, we evaluate the variance inflation factor (VIF) of a given predictor. The table below lists the VIF of all of our predictors; we exclude any with a VIF of 5 or more from our final model, including district, which is council district, and several historic district and planning overlays.

      Show the code -
      ols <- lm(permits_count ~ ., data = permits_bg %>% filter(year < 2024) %>% select(-c(mapname, geoid10, year)) %>% st_drop_geometry())
      -vif(ols) %>%
      -  data.frame() %>%
      -  clean_names() %>%
      -  select(-df) %>%
      -  arrange(desc(gvif)) %>%
      -  kablerize()
      +
      ols <- lm(permits_count ~ ., data = permits_bg %>% filter(year < 2024) %>% select(-c(mapname, geoid10, year)) %>% st_drop_geometry())
      +vif(ols) %>%
      +  data.frame() %>%
      +  clean_names() %>%
      +  select(-df) %>%
      +  arrange(desc(gvif)) %>%
      +  kablerize()
      @@ -9954,19 +9966,6 @@

      Show the code -
      ggplot(building_permits %>% filter(!year %in% c(2024)), aes(x = as.factor(year))) +
      -  geom_bar(fill = palette[1], color = NA, alpha = 0.7) +
      -  labs(title = "Permits per Year",
      -       y = "Count") +
      -  theme_minimal() +
      -  theme(axis.title.x = element_blank(),
      -        aspect.ratio = .75)
      -
      -
      -

      -
      -
      -Show the code
      ggplot(permits_bg %>% st_drop_geometry %>% filter(!year %in% c(2024)), aes(x = permits_count)) +
         geom_histogram(fill = palette[1], color = NA, alpha = 0.7) +
         labs(title = "Permits per Block Group per Year",
      @@ -9983,9 +9982,9 @@ 

      -

      4.2 Examine Spatial Patterns

      -

      To to identify spatial clusters, or hotspots, in geographic data, we performed a Local Moran’s I test. It assesses the degree of spatial autocorrelation, which is the extent to which the permit counts in a block group tend to be similar to neighboring block group. We used a p-value of 0.1 as our hotspot threshold.

      +
      +

      4.2 Spatial Patterns

      +

      In addition to correlation between non-spatial variables, our dependent variable, permits_count, displays a high degree of spatial autocorrelation. That is, the number of permits at a given location is closely related to the number of permits at neighboring locations. We’ve accounted for this in our model by factoring in spatial lag, and we explore it here by evaluating the local Moran’s I values, which is the measure of how concentrated high or low values are at a given location. Here, we identify hotspots for new construction in 2023 by looking at statistically signficant concentrations of new building permits.

      Show the code @@ -10010,50 +10009,61 @@

      morans_i <- tmap_theme(tm_shape(lisa) + tm_polygons(col = "ii", border.alpha = 0, style = "jenks", palette = mono_5_green, title = "Moran's I"), - "Local Moran's I") + "Local Moran's I (2023)") p_value <- tmap_theme(tm_shape(lisa) + tm_polygons(col = "p_ii", border.alpha = 0, style = "jenks", palette = mono_5_green, title = "P-Value"), - "Moran's I P-Value") + "Moran's I P-Value (2023)") sig_hotspots <- tmap_theme(tm_shape(lisa) + tm_polygons(col = "hotspot", border.alpha = 0, style = "cat", palette = c(mono_5_green[1], mono_5_green[5]), textNA = "Not a Hotspot", title = "Hotspot?"), - "New Construction Hotspots") + "Construction Hotspots (2023)") tmap_arrange(morans_i, p_value, sig_hotspots, ncol = 3)

      -

      +

      Emergeging hotspots…? If I can get it to work.

      Show the code -
      # stc <- as_spacetime(permits_bg %>% select(permits_count, geoid10, year) %>% na.omit(),
      -#                  .loc_col = "geoid10",
      -#                  .time_col = "year")
      -# 
      -# # conduct EHSA
      -# ehsa <- emerging_hotspot_analysis(
      -#   x = stc,
      -#   .var = "permits_count",
      -#   k = 1,
      -#   nsim = 5
      -# )
      -# 
      -# count(ehsa, classification)
      +
      # # Prepare the data
      +# permits_data <- permits_bg %>%
      +#   select(permits_count, geoid10, year) %>%
      +#   na.omit()
      +# 
      +# # Check for infinite values or other anomalies
      +# if(any(is.infinite(permits_data$permits_count), na.rm = TRUE)) {
      +#   stop("Infinite values found in permits_count")
      +# }
      +# 
      +# # Create spacetime object
      +# stc <- as_spacetime(permits_data,
      +#                     .loc_col = "geoid10",
      +#                     .time_col = "year")
      +# 
      +# # Run emerging hotspot analysis
      +# ehsa <- emerging_hotspot_analysis(
      +#   x = stc,
      +#   .var = "permits_count",
      +#   k = 1,
      +#   nsim = 3
      +# )
      +# 
      +# # Analyze the result
      +# count(ehsa, classification)

      4.3 Compare Models

      -

      Make sure to note that we train, test, and then validate. So these first models are based on 2022 data, and then we run another on 2023 (and then predict 2024 at the end).

      -

      There are various regression models available, each with its assumptions, strengths, and weaknesses. We compared Ordinary Least Square, Poisson, and Random Forest. This comparative study allowed us to consider the model’s accuracy, if it overfit, its generalizability, as well as compuationl efficiency.

      -

      The Poisson model was unviable because it overvalued outliers and therefore is not detailed below.

      +

      To actually build our model, we have a range to choose from. OLS, or least squares regression, is among the most common; here, we use it as the basis for comparison with a random forest model, which is somewhat more sophisticated. We also considered a Poisson model, although found that it drastically overpredicted for outliers, and we therefore discarded it. As a point of comparison, we built both OLS and random forest models, trained them on data from 2013 through 2021, tested them on 2022 data, dn compared the results for accuracy, overfitting, and generalizability.

      4.3.1 OLS

      -

      OLS (Ordinary least squares) is a method to explore relationships between a dependent variable and one or more explanatory variables. It considers the strength and direction of these relationships and the goodness of model fit. Our model incorporates three engineered groups of features: space lag, time lag, and distance to 2022. We include this last variable because of the Philadelphia tax abatement policy that led to a significant increase in residential development in the years immediately before 2022 discussed earlier. We used this as a baseline model to compare to Poisson and Random Forest. Given how tightly aligned the observed and predicted prices are we performed dozens of variable combinations to rule out over fitting. We are confident that our variables are generalizable and do not over-fit.

      +

      OLS (Ordinary least squares) is a method to explore relationships between a dependent variable and one or more explanatory variables. It considers the strength and direction of these relationships and the goodness of model fit. Our model incorporates three engineered groups of features: space lag, time lag, and distance to 2022. We include this last variable because of the Philadelphia tax abatement policy that led to a significant increase in residential development in the years immediately before 2022 discussed earlier. We used this as a baseline model to compare to Poisson and Random Forest.

      +

      Overall, we found that our basic OLS model performed quite well; with a mean absolute error (MAE) of 2.68, it is fairly accurate in prediciting future development. We also note that it overpredicts in most cases which, given our goal of anticipating and preparing for high demand for future development, is preferrable to underpredicting. That said, it still produces a handful of outliers that deviate substantially from the predicted value. As a result, we considered a random forest model to see if it would handle these outliers better.

      Show the code @@ -10072,71 +10082,112 @@

      + +
      Show the code -
      ggplot(ols_preds, aes(x = abs_error)) +
      -  geom_histogram(fill = palette[3], color = NA, alpha = 0.7) +
      -  labs(title = "Distribution of Absolute Error per Block Group",
      -       subtitle = "OLS, 2022") +
      -  theme_minimal()
      +
      ols_preds_map <- tmap_theme(tm_shape(ols_preds) +
      +        tm_polygons(col = "ols_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Predicted Permits: OLS")
      +
      +ols_error_map <- tmap_theme(tm_shape(ols_preds) +
      +        tm_polygons(col = "abs_error", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Absolute Error") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Absolute Error: OLS")
      +
      +tmap_arrange(ols_preds_map, ols_error_map)
      -

      +

      +
      +
      +
      +

      4.3.2 Random Forest

      +

      Random forest models are superior to OLS in their ability to capture non-linear patterns, outliers, and so forth. They also tend to be less sensitive to multicolinearity. Thus, we considered whether a random forest model would improve on some of the weaknesses of the OLS model. We found that this was indeed the case; the random forest model yielded a MAE of 2.91. Furthermore, the range of absolute error in the model was sizably reduced, with outliers exerting less of an impact on the model.

      +
      Show the code -
      ols_mae <- paste0("MAE: ", round(mean(ols_preds$abs_error, na.rm = TRUE), 2))
      +
      suppressMessages(
      +ggplot(rf_test_preds, aes(x = permits_count, y = rf_test_preds)) +
      +  geom_point() +
      +  labs(title = "Predicted vs. Actual Permits: RF",
      +       subtitle = "2022 Data",
      +       x = "Actual Permits",
      +       y = "Predicted Permits") +
      +  geom_abline() +
      +  geom_smooth(method = "lm", se = FALSE, color = palette[3]) +
      +  theme_minimal()
      +)
      +
      +

      +
      -

      Our OLS model exhibits a Mean Absolute Error (MAE) of 2.66, a decent performance for a model of its simplicity. However, its efficacy is notably diminished in critical domains where optimization is imperative. Consequently, we intend to enhance the predictive capacity by incorporating more pertinent variables and employing a more sophisticated modeling approach.

      Show the code -
      ols_preds_map <- tmap_theme(tm_shape(ols_preds) +
      -        tm_polygons(col = "ols_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
      +
      test_preds_map <- tmap_theme(tm_shape(rf_test_preds) +
      +        tm_polygons(col = "rf_test_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
         tm_shape(broad_and_market) +
         tm_lines(col = "lightgrey") +
         tm_layout(frame = FALSE),
      -  "Predicted Permits: OLS")
      +  "Predicted Permits: RF Test")
       
      -ols_error_map <- tmap_theme(tm_shape(ols_preds) +
      +test_error_map <- tmap_theme(tm_shape(rf_test_preds) +
               tm_polygons(col = "abs_error", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Absolute Error") +
         tm_shape(broad_and_market) +
         tm_lines(col = "lightgrey") +
         tm_layout(frame = FALSE),
      -  "Absolute Error: OLS")
      +  "Absolute Error: RF Test") 
       
      -tmap_arrange(ols_preds_map, ols_error_map)
      +tmap_arrange(test_preds_map, test_error_map)
      -

      +

      -

      We find that our OLS model has an MAE of only MAE: 2.68–not bad for such a simple model! Still, it struggles most in the areas where we most need it to succeed, so we will try to introduce better variables and apply a more complex model to improve our predictions.

      -
      -

      4.3.2 Random Forest

      -

      OLS and Random Forest represent different modeling paradigms. OLS is a linear regression model suitable for capturing linear relationships, while Random Forest is an ensemble method capable of capturing non-linear patterns and offering greater flexibility in handling various data scenarios. Considering, Random Forest is generally less sensitive to multicollinearity because it considers subsets of features in each tree and averages their predictions and because the effect of outliers tends to be mitigated, we decided it worth investigating Random Forest as an alternative model.

      -

      Compared to the OLS model, the relationship between predicted vs actual permits…

      +
      +
      +
      +

      5 Model Testing

      +

      Model training, validation, and testing involved three steps. First, we partitioned our data into training, validation, and testing sets. We used data from 2013 through 2021 for initial model training. Next, we evaluated our models’ ability to accurately predict 2022 construction permits using our validation set, which consisted of all permits in 2022. We carried out additional feature engineering and model tuning, iterating based on the results of these training and testing splits. We sought to minimize both the mean absolute error (MAE) of our best model and the distribution of absolute error. Finally, when we were satisfied with the results of our best model, we evaluated it again by training it on all data from 2013 through 2022 and validating it on data from 2023 (all but the last two weeks, which we consider negligible for our purposes), which the model had never “seen” before. As Kuhn and Johnson write in Applied Predictive Modeling (2013), “Ideally, the model should be evaluated on samples that were not used to build or fine-tune the model, so that they provide an unbiased sense of model effectiveness.”

      +

      Again, testing confirms the strength of our model; based on 2023 data, our random forest model produces a MAE of 2.19. We note again that the range of model error is relatively narrow.

      Show the code -
      ggplot(rf_test_preds, aes(x = abs_error)) +
      -  geom_histogram(fill = palette[3], alpha = 0.7, color = NA) +
      -  labs(title = "Distribution of Absolute Error per Block Group",
      -       subtitle = "Random Forest, 2022") +
      -  theme_minimal()
      +
      val_preds_map <- tmap_theme(tm_shape(rf_val_preds) +
      +        tm_polygons(col = "rf_val_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Predicted Permits: RF Validate")
      +
      +val_error_map <- tmap_theme(tm_shape(rf_val_preds) +
      +        tm_polygons(col = "abs_error", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Absolute Error") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Absolute Error: RF Validate")
      +
      +tmap_arrange(val_preds_map, val_error_map)
      -

      +

      Show the code
      suppressMessages(
      -ggplot(rf_test_preds, aes(x = permits_count, y = rf_test_preds)) +
      +ggplot(rf_val_preds, aes(x = permits_count, y = rf_val_preds)) +
         geom_point() +
         labs(title = "Predicted vs. Actual Permits: RF",
      -       subtitle = "2022 Data",
      +       subtitle = "2023 Data",
              x = "Actual Permits",
              y = "Predicted Permits") +
         geom_abline() +
      @@ -10145,103 +10196,9 @@ 

      )

      -

      -
      -
      -Show the code -
      rf_test_mae <- paste0("MAE: ", round(mean(rf_test_preds$abs_error, na.rm = TRUE), 2))
      -
      -
      -

      Compared to the OLS Model, the Random Forest Model has a similar error distribution however, it exhibits a MAE of….

      -
      -
      -Show the code -
      test_preds_map <- tmap_theme(tm_shape(rf_test_preds) +
      -        tm_polygons(col = "rf_test_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Predicted Permits: RF Test")
      -
      -test_error_map <- tmap_theme(tm_shape(rf_test_preds) +
      -        tm_polygons(col = "abs_error", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Absolute Error") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Absolute Error: RF Test") 
      -
      -tmap_arrange(test_preds_map, test_error_map)
      -
      -
      -

      -
      -
      -
      -
      -
      -
      -

      5 Model Validation

      -

      Considering Random Forest’s favorable results and attributes for our study compared to OLS, we will train and test our predictive model using the random forest model.

      -

      We decided to split our training and testing data up to 2022 in an effort to balance permiting activity pre- and post- tax abatement policy.

      -

      [code block here]

      -

      We train and test up to 2022–we use this for model tuning and feature engineering.

      -

      Having settled on our model features and tuning, we now validate on 2023 data.

      -
      -
      -Show the code -
      val_preds_map <- tmap_theme(tm_shape(rf_val_preds) +
      -        tm_polygons(col = "rf_val_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Predicted Permits: RF Validate")
      -
      -val_error_map <- tmap_theme(tm_shape(rf_val_preds) +
      -        tm_polygons(col = "abs_error", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Absolute Error") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Absolute Error: RF Validate")
      -
      -tmap_arrange(val_preds_map, val_error_map)
      -
      -
      -

      -
      -
      -Show the code -
      ggplot(rf_val_preds, aes(x = abs_error)) +
      -  geom_histogram(fill = palette[3], alpha = 0.7, color = NA) +
      -  labs(title = "Distribution of Absolute Error per Block Group",
      -       subtitle = "Random Forest, 2023") +
      -  theme_minimal()
      -
      -
      -

      -
      -
      -Show the code -
      suppressMessages(
      -ggplot(rf_val_preds, aes(x = permits_count, y = rf_val_preds)) +
      -  geom_point() +
      -  labs(title = "Predicted vs. Actual Permits: RF",
      -       subtitle = "2023 Data",
      -       x = "Actual Permits",
      -       y = "Predicted Permits") +
      -  geom_abline() +
      -  geom_smooth(method = "lm", se = FALSE, color = palette[3]) +
      -  theme_minimal()
      -)
      -
      -

      -
      -Show the code -
      rf_val_mae <- paste0("MAE: ", round(mean(rf_val_preds$abs_error, na.rm = TRUE), 2))
      -
      -

      We return an MAE of MAE: 2.19.

      6 Discussion

      @@ -10251,13 +10208,13 @@

      Show the code -
      nbins <- as.integer(sqrt(nrow(rf_val_preds)))
      -vline <- mean(rf_val_preds$abs_error, na.rm = TRUE)
      -
      -ggplot(rf_val_preds, aes(x = abs_error)) +
      -  geom_histogram(fill = palette[3], alpha = 0.7, fill = NA, bins = nbins) +
      -  geom_vline(aes(xintercept = vline)) +
      -  theme_minimal()
      +
      nbins <- as.integer(sqrt(nrow(rf_val_preds)))
      +vline <- mean(rf_val_preds$abs_error, na.rm = TRUE)
      +
      +ggplot(rf_val_preds, aes(x = abs_error)) +
      +  geom_histogram(fill = palette[3], alpha = 0.7, fill = NA, bins = nbins) +
      +  geom_vline(aes(xintercept = vline)) +
      +  theme_minimal()

      @@ -10267,48 +10224,29 @@

      6.2 Generalizabiltiy

      The constructed boxplot, categorizing observations based on racial composition, indicates that the random forest model generalizes effectively, showcasing consistent and relatively low absolute errors across majority non-white and majority white categories. The discernible similarity in error distributions suggests that the model’s predictive performance remains robust across diverse racial compositions, affirming its ability to generalize successfully.

      -
      -
      -Show the code -
      rf_val_preds <- rf_val_preds %>%
      -                      mutate(race_comp = case_when(
      -                        percent_nonwhite >= .50 ~ "Majority Non-White",
      -                        TRUE ~ "Majority White"
      -                      ))
      -
      -ggplot(rf_val_preds, aes(y = abs_error, color = race_comp)) +
      -  geom_boxplot(fill = NA) +
      -  scale_color_manual(values = c(mono_5_orange[5], mono_5_orange[3])) +
      - # labs(title = "C")
      -  theme_minimal()
      -
      -
      -

      -
      -

      We find that error is not related to affordability and actually trends downward with percent nonwhite. (This is probably because there is less total development happening there in majority-minority neighborhoods to begin with, so the magnitude of error is less, even though proportionally it might be more.) Error increases slightly with total pop. This makes sense–more people –> more development.

      Our analysis reveals that the error is not correlated with affordability and demonstrates a downward trend in conjunction with the percentage of the nonwhite population. This observed pattern may be attributed to the likelihood that majority-minority neighborhoods experience a comparatively lower volume of overall development, thereby diminishing the absolute magnitude of error, despite potential proportional increases. Additionally, there is a slight increase in error with the total population, aligning with the intuitive expectation that higher population figures correspond to more extensive development activities.

      Show the code -
      rf_val_preds_long <- rf_val_preds %>%
      -  pivot_longer(cols = c(rent_burden, percent_nonwhite, total_pop, med_inc),
      -               names_to = "variable", values_to = "value") %>%
      -  mutate(variable = case_when(
      -    variable == "med_inc" ~ "Median Income ($)",
      -    variable == "percent_nonwhite" ~ "Nonwhite (%)",
      -    variable == "rent_burden" ~ "Rent Burden (%)",
      -    TRUE ~ "Total Pop."
      -  ))
      -
      -ggplot(rf_val_preds_long, aes(x = value, y = abs_error)) +
      -  geom_point() +
      -  geom_smooth(method = "lm", se = FALSE, color = palette[3]) +
      -  facet_wrap(~ variable, scales = "free_x") +
      -  labs(title = "Generalizability of Absolute Error",
      -       x = "Value",
      -       y = "Absolute Error") +
      -  theme_minimal()
      +
      rf_val_preds_long <- rf_val_preds %>%
      +  pivot_longer(cols = c(rent_burden, percent_nonwhite, total_pop, med_inc),
      +               names_to = "variable", values_to = "value") %>%
      +  mutate(variable = case_when(
      +    variable == "med_inc" ~ "Median Income ($)",
      +    variable == "percent_nonwhite" ~ "Nonwhite (%)",
      +    variable == "rent_burden" ~ "Rent Burden (%)",
      +    TRUE ~ "Total Pop."
      +  ))
      +
      +ggplot(rf_val_preds_long, aes(x = value, y = abs_error)) +
      +  geom_point() +
      +  geom_smooth(method = "lm", se = FALSE, color = palette[3]) +
      +  facet_wrap(~ variable, scales = "free_x") +
      +  labs(title = "Generalizability of Absolute Error",
      +       x = "Value",
      +       y = "Absolute Error") +
      +  theme_minimal()

      @@ -10318,17 +10256,17 @@

      Show the code -
      suppressMessages(
      -  ggplot(rf_val_preds, aes(x = reorder(district, abs_error, FUN = mean), y = abs_error)) +
      -    geom_boxplot(fill = NA, color = palette[3]) +
      -    labs(title = "MAE by Council District",
      -         y = "Mean Absolute Error",
      -         x = "Council District") +
      -    theme_minimal()
      -)
      +
      suppressMessages(
      +  ggplot(rf_val_preds, aes(x = reorder(district, abs_error, FUN = mean), y = abs_error)) +
      +    geom_boxplot(fill = NA, color = palette[3], alpha = 0.7) +
      +    labs(title = "MAE by Council District",
      +         y = "Mean Absolute Error",
      +         x = "Council District") +
      +    theme_minimal()
      +)
      -

      +

      @@ -10340,99 +10278,99 @@

      Show the code -
      filtered_zoning <- zoning %>%
      -                     filter(str_detect(CODE, "RS") | str_detect(CODE, "I"),
      -                            CODE != "I2",
      -                            !str_detect(CODE, "SP")) %>%
      -                     st_join(., rf_val_preds %>% select(rf_val_preds))
      -
      -
      -
      -zoning_map <- tmap_theme(tm_shape(filtered_zoning) +
      -        tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey", title = "Zoning Code") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Mismatched Zoning")
      -  
      -mismatch <- tmap_theme(tm_shape(filtered_zoning) +
      -        tm_polygons(col = "rf_val_preds", border.alpha = 0, colorNA = "lightgrey", palette = mono_5_orange, style = "fisher", title = "Predicted New Permits") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Development Pressure")
      -
      -tmap_arrange(zoning_map, mismatch)
      +
      filtered_zoning <- zoning %>%
      +                     filter(str_detect(CODE, "RS") | str_detect(CODE, "I"),
      +                            CODE != "I2",
      +                            !str_detect(CODE, "SP")) %>%
      +                     st_join(., rf_val_preds %>% select(rf_val_preds))
      +
      +
      +zoning_map <- tmap_theme(tm_shape(filtered_zoning) +
      +        tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey", title = "Zoning Code", palette = zoning_palette) +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE,
      +            legend.height = 0.4),
      +  "Mismatched Zoning")
      +  
      +mismatch <- tmap_theme(tm_shape(filtered_zoning) +
      +        tm_polygons(col = "rf_val_preds", border.alpha = 0, colorNA = "lightgrey", palette = mono_5_orange, style = "fisher", title = "Predicted New Permits") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Development Pressure")
      +
      +tmap_arrange(zoning_map, mismatch)
      -

      +

      We can extract development predictions at the block level to these parcels and then visualize them by highest need.

      Show the code -
      tmap_mode('view')
      -
      -filtered_zoning %>%
      -  filter(rf_val_preds > 10) %>%
      -tm_shape() +
      -        tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey",
      -                    popup.vars = c('rf_val_preds', 'CODE')) +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE)
      +
      tmap_mode('view')
      +
      +filtered_zoning %>%
      +  filter(rf_val_preds > 10) %>%
      +tm_shape() +
      +        tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey",
      +                    popup.vars = c('rf_val_preds', 'CODE'), palette = zoning_palette) +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE)
      -
      - +
      +

      Furthermore, we can identify properties with high potential for assemblage, which suggests the ability to accomodate high-density, multi-unit housing.

      Show the code -
      nbs <- filtered_zoning %>% 
      -  mutate(nb = st_contiguity(geometry))
      -
      -# Create edge list while handling cases with no neighbors
      -edge_list <- tibble::tibble(id = 1:length(nbs$nb), nbs = nbs$nb) %>% 
      -  tidyr::unnest(nbs) %>% 
      -  filter(nbs != 0)
      -
      -# Create a graph with a node for each row in filtered_zoning
      -g <- make_empty_graph(n = nrow(filtered_zoning))
      -V(g)$name <- as.character(1:nrow(filtered_zoning))
      -
      -# Add edges if they exist
      -if (nrow(edge_list) > 0) {
      -  edges <- as.matrix(edge_list)
      -  g <- add_edges(g, c(t(edges)))
      -}
      -
      -# Calculate the number of contiguous neighbors, handling nodes without neighbors
      -n_contiguous <- sapply(V(g)$name, function(node) {
      -  if (node %in% edges) {
      -    length(neighborhood(g, order = 1, nodes = as.numeric(node))[[1]])
      -  } else {
      -    1  # Nodes without neighbors count as 1 (themselves)
      -  }
      -})
      -
      -filtered_zoning <- filtered_zoning %>%
      -                    mutate(n_contig = n_contiguous)
      -
      -filtered_zoning %>%
      -  st_drop_geometry() %>%
      -  select(rf_val_preds,
      -         n_contig,
      -         OBJECTID,
      -         CODE) %>%
      -  filter(rf_val_preds > 10,
      -         n_contig > 2) %>%
      -  arrange(desc(rf_val_preds)) %>%
      -  kablerize(caption = "Poorly-Zoned Properties with High Development Risk")
      +
      nbs <- filtered_zoning %>% 
      +  mutate(nb = st_contiguity(geometry))
      +
      +# Create edge list while handling cases with no neighbors
      +edge_list <- tibble::tibble(id = 1:length(nbs$nb), nbs = nbs$nb) %>% 
      +  tidyr::unnest(nbs) %>% 
      +  filter(nbs != 0)
      +
      +# Create a graph with a node for each row in filtered_zoning
      +g <- make_empty_graph(n = nrow(filtered_zoning))
      +V(g)$name <- as.character(1:nrow(filtered_zoning))
      +
      +# Add edges if they exist
      +if (nrow(edge_list) > 0) {
      +  edges <- as.matrix(edge_list)
      +  g <- add_edges(g, c(t(edges)))
      +}
      +
      +# Calculate the number of contiguous neighbors, handling nodes without neighbors
      +n_contiguous <- sapply(V(g)$name, function(node) {
      +  if (node %in% edges) {
      +    length(neighborhood(g, order = 1, nodes = as.numeric(node))[[1]])
      +  } else {
      +    1  # Nodes without neighbors count as 1 (themselves)
      +  }
      +})
      +
      +filtered_zoning <- filtered_zoning %>%
      +                    mutate(n_contig = n_contiguous)
      +
      +filtered_zoning %>%
      +  st_drop_geometry() %>%
      +  select(rf_val_preds,
      +         n_contig,
      +         OBJECTID,
      +         CODE) %>%
      +  filter(rf_val_preds > 10,
      +         n_contig > 2) %>%
      +  arrange(desc(rf_val_preds)) %>%
      +  kablerize(caption = "Poorly-Zoned Properties with High Development Risk")
      @@ -10768,14 +10706,14 @@

      Show the code -
      tmap_mode('plot')
      -
      -tmap_theme(tm_shape(rf_proj_preds) +
      -        tm_polygons(col = "rf_proj_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Predicted New Permits") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Projected New Development, 2024")
      +
      tmap_mode('plot')
      +
      +tmap_theme(tm_shape(rf_proj_preds) +
      +        tm_polygons(col = "rf_proj_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Predicted New Permits") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Projected New Development, 2024")

      @@ -10784,7 +10722,7 @@

      9 Web Application

      - +

      10 Next Steps

      diff --git a/index.html b/index.html index 84be0d7..ddf0339 100644 --- a/index.html +++ b/index.html @@ -9172,19 +9172,19 @@

      Table of contents

      @@ -9324,9 +9324,10 @@

      -

      3.1 Permits

      -

      Firstly, 10 years of permit data from 2012 to 2023 from the Philadelphia Department of Licenses and Inspections are critical to the study. This study filters only for new construction permits granted for residential projects. In the future, filtering for full and substantial renovations could add more nuance to what constitutes as development pressure.

      +
      +

      3.1 Construction Permits

      +

      Permit data from 2013 through 2023, collected from the Philadelphia Department of Licenses & Inspections, are the basis of our model. We consider only new construction permits granted for residential projects, but in the future, filtering for data on “full” or “substantial” renovations could add nuance to the compelexities of development pressure. Given the granular spatial scale of our analysis, and the need to aggregate Census data to our unit of analysis, we chose to aggregate these permits data to the block group level.

      +

      Construction Permits per Year Philadelphia, PA

      Show the code @@ -9335,176 +9336,187 @@

      tm_facets(along = "year") + tm_shape(broad_and_market) + tm_lines(col = "darkgrey") + - tm_layout(frame = FALSE), - "New Construction Permits per Year\nPhiladelphia, PA") - -suppressMessages( -tmap_animation(tm, "assets/permits_animation.gif", delay = 50) -)

      + tm_layout(frame = FALSE)) + +suppressMessages( +tmap_animation(tm, "assets/permits_animation.gif", delay = 50) +)
      -

      +

      Philadelphia Building Permits, 2013 - 2023
      -

      The spike in new construction permits in 2021 is reasonably attributed to the expiration of a tax abatement program for developers.

      +
      +
      +Show the code +
      ggplot(building_permits %>% filter(!year %in% c(2024)), aes(x = as.factor(year))) +
      +  geom_bar(fill = palette[1], color = NA, alpha = 0.7) +
      +  labs(title = "Permits per Year",
      +       y = "Count") +
      +  theme_minimal() +
      +  theme(axis.title.x = element_blank(),
      +        aspect.ratio = .75)
      +
      +
      +

      +
      +
      +

      We note a significant uptick in new construction permits as we approach 2021, followed by a sharp decline. It is generally acknowledged that this trend was due to the expiration of a tax abatement program for developers.

      When assessing new construction permit count by Council Districts, a few districts issued the bulk of new permits during that 2021 peak. Hover over the lines to see more about the volume of permits and who granted them.

      Show the code -
      perms_x_dist <- st_join(building_permits, council_dists)
      -
      -perms_x_dist_sum <- perms_x_dist %>%
      -                  st_drop_geometry() %>%
      -                  group_by(DISTRICT, year) %>%
      -                  summarize(permits_count = n())
      -
      -perms_x_dist_mean = perms_x_dist_sum %>%
      -                      group_by(year) %>%
      -                      summarize(permits_count = mean(permits_count)) %>%
      -                      mutate(DISTRICT = "Average")
      -
      -perms_x_dist_sum <- bind_rows(perms_x_dist_sum, perms_x_dist_mean) %>%
      -                        mutate(color = ifelse(DISTRICT != "Average", 0, 1))
      -
      -ggplotly(
      -ggplot(perms_x_dist_sum %>% filter(year > 2013, year < 2024), aes(x = year, y = permits_count, color = as.character(color), group = interaction(DISTRICT, color))) +
      -  geom_line(lwd = 0.7) +
      -  labs(title = "Permits per Year by Council District",
      -       y = "Total Permits") +
      -  # facet_wrap(~DISTRICT) +
      -  theme_minimal() +
      -  theme(axis.title.x = element_blank(),
      -        legend.position = "none") +
      -  scale_color_manual(values = c(palette[5], palette[1]))
      -)
      +
      perms_x_dist <- st_join(building_permits, council_dists)
      +
      +perms_x_dist_sum <- perms_x_dist %>%
      +                  st_drop_geometry() %>%
      +                  group_by(DISTRICT, year) %>%
      +                  summarize(permits_count = n())
      +
      +perms_x_dist_mean = perms_x_dist_sum %>%
      +                      group_by(year) %>%
      +                      summarize(permits_count = mean(permits_count)) %>%
      +                      mutate(DISTRICT = "Average")
      +
      +perms_x_dist_sum <- bind_rows(perms_x_dist_sum, perms_x_dist_mean) %>%
      +                        mutate(color = ifelse(DISTRICT != "Average", 0, 1))
      +
      +ggplotly(
      +ggplot(perms_x_dist_sum %>% filter(year > 2013, year < 2024), aes(x = year, y = permits_count, color = as.character(color), group = interaction(DISTRICT, color))) +
      +  geom_line(lwd = 0.7) +
      +  labs(title = "Permits per Year by Council District",
      +       y = "Total Permits") +
      +  # facet_wrap(~DISTRICT) +
      +  theme_minimal() +
      +  theme(axis.title.x = element_blank(),
      +        legend.position = "none") +
      +  scale_color_manual(values = c(palette[5], palette[1]))
      +)
      -
      - +
      +
      -
      -

      3.2 Feature Engineering by Time and Space

      +
      +

      3.2 Spatio-Temporal Features

      New construction exhibits sizable spatial and temporal autocorrelation. In other words, there is a strong relationship between the number of permits in a given block group and the number of permits in neighboring block groups; as well as between the number of permits issued in a block group in a given year and the number of permits issued in that same block group in the previous year. To account for these relationships, we engineer new features, including both space and time lags. We note that all of these engineered features have strong correlation coefficients with our dependent variable, permits_count, and p-values indicating that these relationships are statistically significant.

      Show the code -
      permits_bg_long <- permits_bg %>%
      -                    filter(!year %in% c(2024)) %>%
      -                    st_drop_geometry() %>%
      -                    pivot_longer(
      -                      cols = c(starts_with("lag"), dist_to_2022),
      -                      names_to = "Variable",
      -                      values_to = "Value"
      -                    )
      -
      -
      -ggscatter(permits_bg_long, x = "permits_count", y = "Value", facet.by = "Variable",
      -   add = "reg.line",
      -   add.params = list(color = palette[3], fill = palette[5]),
      -   conf.int = TRUE
      -   ) + stat_cor(method = "pearson", p.accuracy = 0.001, r.accuracy = 0.01)
      +
      permits_bg_long <- permits_bg %>%
      +                    filter(!year %in% c(2024)) %>%
      +                    st_drop_geometry() %>%
      +                    pivot_longer(
      +                      cols = c(starts_with("lag"), dist_to_2022),
      +                      names_to = "Variable",
      +                      values_to = "Value"
      +                    )
      +
      +
      +ggscatter(permits_bg_long, x = "permits_count", y = "Value", facet.by = "Variable",
      +   add = "reg.line",
      +   add.params = list(color = palette[3], fill = palette[5]),
      +   conf.int = TRUE
      +   ) + stat_cor(method = "pearson", p.accuracy = 0.001, r.accuracy = 0.01)

      -
      -

      3.3 Socioeconomics

      -

      Racial Mix (white vs non-white), median income, and housing cost burden are socioeconomic factors that often play an outsized role in affordability in cities like Philadelphia, with a pervasive and persistent history of housing discrimination and systemic disinvestment. This data is all pulled from the US Census Bureau’s American Community Survey 5-Year survey.

      +
      +

      3.3 Socioeconomic Features

      +

      Socioeconomic factors such as race, income, and housing cost burden play an outsized role in affordability in cities like Philadelphia, which are marred by a pervasive and persistent history housing discrimination and systemic disinvestment in poor and minority neighborhoods. To account for these issues, we incorporate various data from the US Census Bureau’s American Community Survey 5-Year survey. Later, we also consider our model’s generalizability across different racial and economic contexts to ensure that it will not inadvertently reinforce structural inequity.

      Spatially, is clear that non-white communities earn lower median incomes and experience higher rates of extreme rent burden (household spends more than 35% of income on gross rent).

      Show the code -
      med_inc <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      -        tm_polygons(col = "med_inc", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Med. Inc. ($)") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "darkgrey") +
      -  tm_layout(frame = FALSE),
      -  "Median Income")
      -  
      -race <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      -        tm_polygons(col = "percent_nonwhite", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Nonwhite (%)") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "darkgrey") +
      -  tm_layout(frame = FALSE),
      -  "Race")
      -  
      -rent_burd <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      -        tm_polygons(col = "ext_rent_burden", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Rent Burden (%)") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "darkgrey") +
      -  tm_layout(frame = FALSE),
      -  "Extreme Rent Burden")
      -  
      -tmap_arrange(med_inc, race, rent_burd)
      +
      med_inc <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      +        tm_polygons(col = "med_inc", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Med. Inc. ($)") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "darkgrey") +
      +  tm_layout(frame = FALSE),
      +  "Median Income")
      +  
      +race <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      +        tm_polygons(col = "percent_nonwhite", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Nonwhite (%)") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "darkgrey") +
      +  tm_layout(frame = FALSE),
      +  "Race")
      +  
      +rent_burd <- tmap_theme(tm_shape(permits_bg %>% filter(year == 2022)) +
      +        tm_polygons(col = "ext_rent_burden", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Rent Burden (%)") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "darkgrey") +
      +  tm_layout(frame = FALSE),
      +  "Extreme Rent Burden")
      +  
      +tmap_arrange(med_inc, race, rent_burd)

      -

      Considering the strong spatial relationship between socioeconomics and certain areas of Philadelphia, we will be sure to investigate our model’s generalizability against race and income.

      -
      -

      4 Build Predictive Models

      +
      +

      4 Model Building

      “All the complaints about City zoning regulations really boil down to the fact that City Council has suppressed infill housing or restricted multi-family uses, which has served to push average housing costs higher.” - Jon Geeting, Philly 3.0 Engagement Director

      SmartZoning® seeks to predict where permits are most likely to be filed as a measure to predict urban growth. As discussed, predicting growth is fraught because growth is influenced by political forces rather than by plans published by the city’s Planning Commission. Comprehensive plans, typically set on ten-year timelines, tend to become mere suggestions, ultimately subject to the prerogatives of city council members rather than serving as steadfast guides for smart growth. With these dynamics in mind, SmartZoning’s prediction model accounts for socioeconomics, council district, and time-space lag.

      -
      -

      4.1 Tests for Correlation

      -

      The goal is to select variables that most significantly correlate to permit count to include in the predictive model. Correlation is a type of association test. For example, are permit counts more closely associated to population or to median income? Or, do racial mix and rent burden offer redundant insight? These are the types of subtle but important distinctions we aim to seek out.

      +
      +

      4.1 Tests for Correlation and Collinearity

      4.1.1 Correlation Coefficients

      +

      In building our model, we aim to select variables that correlate significantly with permit_count. Using a correlation matrix, we can assess whether our predictors are, in fact, meaningfully associated with our dependent variable. As it turns out, socioeconomic variables are not (we exclude the other variables, which we have previously established to be significant), but we retain them for the sake of later analysis.

      Show the code -
      corr_vars <- c("total_pop",
      -               "med_inc",
      -               "percent_nonwhite",
      -               "percent_renters",
      -               "rent_burden",
      -               "ext_rent_burden")
      -
      -corr_dat <- permits_bg %>% select(all_of(corr_vars), permits_count) %>% select(where(is.numeric)) %>% st_drop_geometry() %>% unique() %>% na.omit()
      -
      -corr <- round(cor(corr_dat), 2)
      -p.mat <- cor_pmat(corr_dat)
      -
      -ggcorrplot(corr, p.mat = p.mat, hc.order = TRUE,
      -    type = "full", insig = "blank", lab = TRUE, colors = c(palette[2], "white", palette[3])) +
      -  annotate(
      -  geom = "rect",
      -  xmin = .5, xmax = 7.5, ymin = 4.5, ymax = 5.5,
      -  fill = "transparent", color = "red", alpha = 0.5
      -)
      +
      corr_vars <- c("total_pop",
      +               "med_inc",
      +               "percent_nonwhite",
      +               "percent_renters",
      +               "rent_burden",
      +               "ext_rent_burden")
      +
      +corr_dat <- permits_bg %>% select(all_of(corr_vars), permits_count) %>% select(where(is.numeric)) %>% st_drop_geometry() %>% unique() %>% na.omit()
      +
      +corr <- round(cor(corr_dat), 2)
      +p.mat <- cor_pmat(corr_dat)
      +
      +ggcorrplot(corr, p.mat = p.mat, hc.order = FALSE,
      +    type = "full", insig = "blank", lab = TRUE, colors = c(palette[2], "white", palette[3])) +
      +  annotate(
      +  geom = "rect",
      +  xmin = .5, xmax = 7.5, ymin = 6.5, ymax = 7.5,
      +  fill = "transparent", color = "red", alpha = 0.5
      +)
      -

      +

      4.1.2 VIF

      -

      To ensure that our predictive model does not have multicollinearity, or multiple values telling the same story about permit counts, we use the VIF test. The table below lists each variables’s VIF score. Variables that have over a 5 are considered to potentially have some multicollinearity, and those over 10 certainly need to be flagged. Generally the council district and zoning overlays such as historic districts may be conflicting.

      -

      Based on VIF, we drop:

      -

      hist_dist_na 33.120644 district8 32.900255 district4 32.164688 district9 30.834357 district5 29.393431 district3 29.092806 district2 28.580678 district1 27.199582 district7 26.741373 hist_dist_historic_street_paving_thematic_district 26.735386 district6 19.912382 overlay_fne 15.601603 overlay_ne 11.179327 overlay_nis 7.717070 overlay_ndo 6.867713 overlay_fdo 6.574022 overlay_edo 5.595256 overlay_vdo 5.400210

      +

      We also aim to minimize or eliminate multicollinearity in our model. For this purpose, we evaluate the variance inflation factor (VIF) of a given predictor. The table below lists the VIF of all of our predictors; we exclude any with a VIF of 5 or more from our final model, including district, which is council district, and several historic district and planning overlays.

      Show the code -
      ols <- lm(permits_count ~ ., data = permits_bg %>% filter(year < 2024) %>% select(-c(mapname, geoid10, year)) %>% st_drop_geometry())
      -vif(ols) %>%
      -  data.frame() %>%
      -  clean_names() %>%
      -  select(-df) %>%
      -  arrange(desc(gvif)) %>%
      -  kablerize()
      +
      ols <- lm(permits_count ~ ., data = permits_bg %>% filter(year < 2024) %>% select(-c(mapname, geoid10, year)) %>% st_drop_geometry())
      +vif(ols) %>%
      +  data.frame() %>%
      +  clean_names() %>%
      +  select(-df) %>%
      +  arrange(desc(gvif)) %>%
      +  kablerize()
      @@ -9954,19 +9966,6 @@

      Show the code -
      ggplot(building_permits %>% filter(!year %in% c(2024)), aes(x = as.factor(year))) +
      -  geom_bar(fill = palette[1], color = NA, alpha = 0.7) +
      -  labs(title = "Permits per Year",
      -       y = "Count") +
      -  theme_minimal() +
      -  theme(axis.title.x = element_blank(),
      -        aspect.ratio = .75)
      -
      -
      -

      -
      -
      -Show the code
      ggplot(permits_bg %>% st_drop_geometry %>% filter(!year %in% c(2024)), aes(x = permits_count)) +
         geom_histogram(fill = palette[1], color = NA, alpha = 0.7) +
         labs(title = "Permits per Block Group per Year",
      @@ -9983,9 +9982,9 @@ 

      -

      4.2 Examine Spatial Patterns

      -

      To to identify spatial clusters, or hotspots, in geographic data, we performed a Local Moran’s I test. It assesses the degree of spatial autocorrelation, which is the extent to which the permit counts in a block group tend to be similar to neighboring block group. We used a p-value of 0.1 as our hotspot threshold.

      +
      +

      4.2 Spatial Patterns

      +

      In addition to correlation between non-spatial variables, our dependent variable, permits_count, displays a high degree of spatial autocorrelation. That is, the number of permits at a given location is closely related to the number of permits at neighboring locations. We’ve accounted for this in our model by factoring in spatial lag, and we explore it here by evaluating the local Moran’s I values, which is the measure of how concentrated high or low values are at a given location. Here, we identify hotspots for new construction in 2023 by looking at statistically signficant concentrations of new building permits.

      Show the code @@ -10010,50 +10009,61 @@

      morans_i <- tmap_theme(tm_shape(lisa) + tm_polygons(col = "ii", border.alpha = 0, style = "jenks", palette = mono_5_green, title = "Moran's I"), - "Local Moran's I") + "Local Moran's I (2023)") p_value <- tmap_theme(tm_shape(lisa) + tm_polygons(col = "p_ii", border.alpha = 0, style = "jenks", palette = mono_5_green, title = "P-Value"), - "Moran's I P-Value") + "Moran's I P-Value (2023)") sig_hotspots <- tmap_theme(tm_shape(lisa) + tm_polygons(col = "hotspot", border.alpha = 0, style = "cat", palette = c(mono_5_green[1], mono_5_green[5]), textNA = "Not a Hotspot", title = "Hotspot?"), - "New Construction Hotspots") + "Construction Hotspots (2023)") tmap_arrange(morans_i, p_value, sig_hotspots, ncol = 3)

      -

      +

      Emergeging hotspots…? If I can get it to work.

      Show the code -
      # stc <- as_spacetime(permits_bg %>% select(permits_count, geoid10, year) %>% na.omit(),
      -#                  .loc_col = "geoid10",
      -#                  .time_col = "year")
      -# 
      -# # conduct EHSA
      -# ehsa <- emerging_hotspot_analysis(
      -#   x = stc,
      -#   .var = "permits_count",
      -#   k = 1,
      -#   nsim = 5
      -# )
      -# 
      -# count(ehsa, classification)
      +
      # # Prepare the data
      +# permits_data <- permits_bg %>%
      +#   select(permits_count, geoid10, year) %>%
      +#   na.omit()
      +# 
      +# # Check for infinite values or other anomalies
      +# if(any(is.infinite(permits_data$permits_count), na.rm = TRUE)) {
      +#   stop("Infinite values found in permits_count")
      +# }
      +# 
      +# # Create spacetime object
      +# stc <- as_spacetime(permits_data,
      +#                     .loc_col = "geoid10",
      +#                     .time_col = "year")
      +# 
      +# # Run emerging hotspot analysis
      +# ehsa <- emerging_hotspot_analysis(
      +#   x = stc,
      +#   .var = "permits_count",
      +#   k = 1,
      +#   nsim = 3
      +# )
      +# 
      +# # Analyze the result
      +# count(ehsa, classification)

      4.3 Compare Models

      -

      Make sure to note that we train, test, and then validate. So these first models are based on 2022 data, and then we run another on 2023 (and then predict 2024 at the end).

      -

      There are various regression models available, each with its assumptions, strengths, and weaknesses. We compared Ordinary Least Square, Poisson, and Random Forest. This comparative study allowed us to consider the model’s accuracy, if it overfit, its generalizability, as well as compuationl efficiency.

      -

      The Poisson model was unviable because it overvalued outliers and therefore is not detailed below.

      +

      To actually build our model, we have a range to choose from. OLS, or least squares regression, is among the most common; here, we use it as the basis for comparison with a random forest model, which is somewhat more sophisticated. We also considered a Poisson model, although found that it drastically overpredicted for outliers, and we therefore discarded it. As a point of comparison, we built both OLS and random forest models, trained them on data from 2013 through 2021, tested them on 2022 data, dn compared the results for accuracy, overfitting, and generalizability.

      4.3.1 OLS

      -

      OLS (Ordinary least squares) is a method to explore relationships between a dependent variable and one or more explanatory variables. It considers the strength and direction of these relationships and the goodness of model fit. Our model incorporates three engineered groups of features: space lag, time lag, and distance to 2022. We include this last variable because of the Philadelphia tax abatement policy that led to a significant increase in residential development in the years immediately before 2022 discussed earlier. We used this as a baseline model to compare to Poisson and Random Forest. Given how tightly aligned the observed and predicted prices are we performed dozens of variable combinations to rule out over fitting. We are confident that our variables are generalizable and do not over-fit.

      +

      OLS (Ordinary least squares) is a method to explore relationships between a dependent variable and one or more explanatory variables. It considers the strength and direction of these relationships and the goodness of model fit. Our model incorporates three engineered groups of features: space lag, time lag, and distance to 2022. We include this last variable because of the Philadelphia tax abatement policy that led to a significant increase in residential development in the years immediately before 2022 discussed earlier. We used this as a baseline model to compare to Poisson and Random Forest.

      +

      Overall, we found that our basic OLS model performed quite well; with a mean absolute error (MAE) of 2.68, it is fairly accurate in prediciting future development. We also note that it overpredicts in most cases which, given our goal of anticipating and preparing for high demand for future development, is preferrable to underpredicting. That said, it still produces a handful of outliers that deviate substantially from the predicted value. As a result, we considered a random forest model to see if it would handle these outliers better.

      Show the code @@ -10072,71 +10082,112 @@

      + +
      Show the code -
      ggplot(ols_preds, aes(x = abs_error)) +
      -  geom_histogram(fill = palette[3], color = NA, alpha = 0.7) +
      -  labs(title = "Distribution of Absolute Error per Block Group",
      -       subtitle = "OLS, 2022") +
      -  theme_minimal()
      +
      ols_preds_map <- tmap_theme(tm_shape(ols_preds) +
      +        tm_polygons(col = "ols_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Predicted Permits: OLS")
      +
      +ols_error_map <- tmap_theme(tm_shape(ols_preds) +
      +        tm_polygons(col = "abs_error", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Absolute Error") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Absolute Error: OLS")
      +
      +tmap_arrange(ols_preds_map, ols_error_map)
      -

      +

      +
      +
      +
      +

      4.3.2 Random Forest

      +

      Random forest models are superior to OLS in their ability to capture non-linear patterns, outliers, and so forth. They also tend to be less sensitive to multicolinearity. Thus, we considered whether a random forest model would improve on some of the weaknesses of the OLS model. We found that this was indeed the case; the random forest model yielded a MAE of 2.91. Furthermore, the range of absolute error in the model was sizably reduced, with outliers exerting less of an impact on the model.

      +
      Show the code -
      ols_mae <- paste0("MAE: ", round(mean(ols_preds$abs_error, na.rm = TRUE), 2))
      +
      suppressMessages(
      +ggplot(rf_test_preds, aes(x = permits_count, y = rf_test_preds)) +
      +  geom_point() +
      +  labs(title = "Predicted vs. Actual Permits: RF",
      +       subtitle = "2022 Data",
      +       x = "Actual Permits",
      +       y = "Predicted Permits") +
      +  geom_abline() +
      +  geom_smooth(method = "lm", se = FALSE, color = palette[3]) +
      +  theme_minimal()
      +)
      +
      +

      +
      -

      Our OLS model exhibits a Mean Absolute Error (MAE) of 2.66, a decent performance for a model of its simplicity. However, its efficacy is notably diminished in critical domains where optimization is imperative. Consequently, we intend to enhance the predictive capacity by incorporating more pertinent variables and employing a more sophisticated modeling approach.

      Show the code -
      ols_preds_map <- tmap_theme(tm_shape(ols_preds) +
      -        tm_polygons(col = "ols_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
      +
      test_preds_map <- tmap_theme(tm_shape(rf_test_preds) +
      +        tm_polygons(col = "rf_test_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
         tm_shape(broad_and_market) +
         tm_lines(col = "lightgrey") +
         tm_layout(frame = FALSE),
      -  "Predicted Permits: OLS")
      +  "Predicted Permits: RF Test")
       
      -ols_error_map <- tmap_theme(tm_shape(ols_preds) +
      +test_error_map <- tmap_theme(tm_shape(rf_test_preds) +
               tm_polygons(col = "abs_error", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Absolute Error") +
         tm_shape(broad_and_market) +
         tm_lines(col = "lightgrey") +
         tm_layout(frame = FALSE),
      -  "Absolute Error: OLS")
      +  "Absolute Error: RF Test") 
       
      -tmap_arrange(ols_preds_map, ols_error_map)
      +tmap_arrange(test_preds_map, test_error_map)
      -

      +

      -

      We find that our OLS model has an MAE of only MAE: 2.68–not bad for such a simple model! Still, it struggles most in the areas where we most need it to succeed, so we will try to introduce better variables and apply a more complex model to improve our predictions.

      -
      -

      4.3.2 Random Forest

      -

      OLS and Random Forest represent different modeling paradigms. OLS is a linear regression model suitable for capturing linear relationships, while Random Forest is an ensemble method capable of capturing non-linear patterns and offering greater flexibility in handling various data scenarios. Considering, Random Forest is generally less sensitive to multicollinearity because it considers subsets of features in each tree and averages their predictions and because the effect of outliers tends to be mitigated, we decided it worth investigating Random Forest as an alternative model.

      -

      Compared to the OLS model, the relationship between predicted vs actual permits…

      +
      +
      +
      +

      5 Model Testing

      +

      Model training, validation, and testing involved three steps. First, we partitioned our data into training, validation, and testing sets. We used data from 2013 through 2021 for initial model training. Next, we evaluated our models’ ability to accurately predict 2022 construction permits using our validation set, which consisted of all permits in 2022. We carried out additional feature engineering and model tuning, iterating based on the results of these training and testing splits. We sought to minimize both the mean absolute error (MAE) of our best model and the distribution of absolute error. Finally, when we were satisfied with the results of our best model, we evaluated it again by training it on all data from 2013 through 2022 and validating it on data from 2023 (all but the last two weeks, which we consider negligible for our purposes), which the model had never “seen” before. As Kuhn and Johnson write in Applied Predictive Modeling (2013), “Ideally, the model should be evaluated on samples that were not used to build or fine-tune the model, so that they provide an unbiased sense of model effectiveness.”

      +

      Again, testing confirms the strength of our model; based on 2023 data, our random forest model produces a MAE of 2.19. We note again that the range of model error is relatively narrow.

      Show the code -
      ggplot(rf_test_preds, aes(x = abs_error)) +
      -  geom_histogram(fill = palette[3], alpha = 0.7, color = NA) +
      -  labs(title = "Distribution of Absolute Error per Block Group",
      -       subtitle = "Random Forest, 2022") +
      -  theme_minimal()
      +
      val_preds_map <- tmap_theme(tm_shape(rf_val_preds) +
      +        tm_polygons(col = "rf_val_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Predicted Permits: RF Validate")
      +
      +val_error_map <- tmap_theme(tm_shape(rf_val_preds) +
      +        tm_polygons(col = "abs_error", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Absolute Error") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Absolute Error: RF Validate")
      +
      +tmap_arrange(val_preds_map, val_error_map)
      -

      +

      Show the code
      suppressMessages(
      -ggplot(rf_test_preds, aes(x = permits_count, y = rf_test_preds)) +
      +ggplot(rf_val_preds, aes(x = permits_count, y = rf_val_preds)) +
         geom_point() +
         labs(title = "Predicted vs. Actual Permits: RF",
      -       subtitle = "2022 Data",
      +       subtitle = "2023 Data",
              x = "Actual Permits",
              y = "Predicted Permits") +
         geom_abline() +
      @@ -10145,103 +10196,9 @@ 

      )

      -

      -
      -
      -Show the code -
      rf_test_mae <- paste0("MAE: ", round(mean(rf_test_preds$abs_error, na.rm = TRUE), 2))
      -
      -
      -

      Compared to the OLS Model, the Random Forest Model has a similar error distribution however, it exhibits a MAE of….

      -
      -
      -Show the code -
      test_preds_map <- tmap_theme(tm_shape(rf_test_preds) +
      -        tm_polygons(col = "rf_test_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Predicted Permits: RF Test")
      -
      -test_error_map <- tmap_theme(tm_shape(rf_test_preds) +
      -        tm_polygons(col = "abs_error", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Absolute Error") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Absolute Error: RF Test") 
      -
      -tmap_arrange(test_preds_map, test_error_map)
      -
      -
      -

      -
      -
      -
      -
      -
      -
      -

      5 Model Validation

      -

      Considering Random Forest’s favorable results and attributes for our study compared to OLS, we will train and test our predictive model using the random forest model.

      -

      We decided to split our training and testing data up to 2022 in an effort to balance permiting activity pre- and post- tax abatement policy.

      -

      [code block here]

      -

      We train and test up to 2022–we use this for model tuning and feature engineering.

      -

      Having settled on our model features and tuning, we now validate on 2023 data.

      -
      -
      -Show the code -
      val_preds_map <- tmap_theme(tm_shape(rf_val_preds) +
      -        tm_polygons(col = "rf_val_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Permits") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Predicted Permits: RF Validate")
      -
      -val_error_map <- tmap_theme(tm_shape(rf_val_preds) +
      -        tm_polygons(col = "abs_error", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey", title = "Absolute Error") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Absolute Error: RF Validate")
      -
      -tmap_arrange(val_preds_map, val_error_map)
      -
      -
      -

      -
      -
      -Show the code -
      ggplot(rf_val_preds, aes(x = abs_error)) +
      -  geom_histogram(fill = palette[3], alpha = 0.7, color = NA) +
      -  labs(title = "Distribution of Absolute Error per Block Group",
      -       subtitle = "Random Forest, 2023") +
      -  theme_minimal()
      -
      -
      -

      -
      -
      -Show the code -
      suppressMessages(
      -ggplot(rf_val_preds, aes(x = permits_count, y = rf_val_preds)) +
      -  geom_point() +
      -  labs(title = "Predicted vs. Actual Permits: RF",
      -       subtitle = "2023 Data",
      -       x = "Actual Permits",
      -       y = "Predicted Permits") +
      -  geom_abline() +
      -  geom_smooth(method = "lm", se = FALSE, color = palette[3]) +
      -  theme_minimal()
      -)
      -
      -

      -
      -Show the code -
      rf_val_mae <- paste0("MAE: ", round(mean(rf_val_preds$abs_error, na.rm = TRUE), 2))
      -
      -

      We return an MAE of MAE: 2.19.

      6 Discussion

      @@ -10251,13 +10208,13 @@

      Show the code -
      nbins <- as.integer(sqrt(nrow(rf_val_preds)))
      -vline <- mean(rf_val_preds$abs_error, na.rm = TRUE)
      -
      -ggplot(rf_val_preds, aes(x = abs_error)) +
      -  geom_histogram(fill = palette[3], alpha = 0.7, fill = NA, bins = nbins) +
      -  geom_vline(aes(xintercept = vline)) +
      -  theme_minimal()
      +
      nbins <- as.integer(sqrt(nrow(rf_val_preds)))
      +vline <- mean(rf_val_preds$abs_error, na.rm = TRUE)
      +
      +ggplot(rf_val_preds, aes(x = abs_error)) +
      +  geom_histogram(fill = palette[3], alpha = 0.7, fill = NA, bins = nbins) +
      +  geom_vline(aes(xintercept = vline)) +
      +  theme_minimal()

      @@ -10267,48 +10224,29 @@

      6.2 Generalizabiltiy

      The constructed boxplot, categorizing observations based on racial composition, indicates that the random forest model generalizes effectively, showcasing consistent and relatively low absolute errors across majority non-white and majority white categories. The discernible similarity in error distributions suggests that the model’s predictive performance remains robust across diverse racial compositions, affirming its ability to generalize successfully.

      -
      -
      -Show the code -
      rf_val_preds <- rf_val_preds %>%
      -                      mutate(race_comp = case_when(
      -                        percent_nonwhite >= .50 ~ "Majority Non-White",
      -                        TRUE ~ "Majority White"
      -                      ))
      -
      -ggplot(rf_val_preds, aes(y = abs_error, color = race_comp)) +
      -  geom_boxplot(fill = NA) +
      -  scale_color_manual(values = c(mono_5_orange[5], mono_5_orange[3])) +
      - # labs(title = "C")
      -  theme_minimal()
      -
      -
      -

      -
      -

      We find that error is not related to affordability and actually trends downward with percent nonwhite. (This is probably because there is less total development happening there in majority-minority neighborhoods to begin with, so the magnitude of error is less, even though proportionally it might be more.) Error increases slightly with total pop. This makes sense–more people –> more development.

      Our analysis reveals that the error is not correlated with affordability and demonstrates a downward trend in conjunction with the percentage of the nonwhite population. This observed pattern may be attributed to the likelihood that majority-minority neighborhoods experience a comparatively lower volume of overall development, thereby diminishing the absolute magnitude of error, despite potential proportional increases. Additionally, there is a slight increase in error with the total population, aligning with the intuitive expectation that higher population figures correspond to more extensive development activities.

      Show the code -
      rf_val_preds_long <- rf_val_preds %>%
      -  pivot_longer(cols = c(rent_burden, percent_nonwhite, total_pop, med_inc),
      -               names_to = "variable", values_to = "value") %>%
      -  mutate(variable = case_when(
      -    variable == "med_inc" ~ "Median Income ($)",
      -    variable == "percent_nonwhite" ~ "Nonwhite (%)",
      -    variable == "rent_burden" ~ "Rent Burden (%)",
      -    TRUE ~ "Total Pop."
      -  ))
      -
      -ggplot(rf_val_preds_long, aes(x = value, y = abs_error)) +
      -  geom_point() +
      -  geom_smooth(method = "lm", se = FALSE, color = palette[3]) +
      -  facet_wrap(~ variable, scales = "free_x") +
      -  labs(title = "Generalizability of Absolute Error",
      -       x = "Value",
      -       y = "Absolute Error") +
      -  theme_minimal()
      +
      rf_val_preds_long <- rf_val_preds %>%
      +  pivot_longer(cols = c(rent_burden, percent_nonwhite, total_pop, med_inc),
      +               names_to = "variable", values_to = "value") %>%
      +  mutate(variable = case_when(
      +    variable == "med_inc" ~ "Median Income ($)",
      +    variable == "percent_nonwhite" ~ "Nonwhite (%)",
      +    variable == "rent_burden" ~ "Rent Burden (%)",
      +    TRUE ~ "Total Pop."
      +  ))
      +
      +ggplot(rf_val_preds_long, aes(x = value, y = abs_error)) +
      +  geom_point() +
      +  geom_smooth(method = "lm", se = FALSE, color = palette[3]) +
      +  facet_wrap(~ variable, scales = "free_x") +
      +  labs(title = "Generalizability of Absolute Error",
      +       x = "Value",
      +       y = "Absolute Error") +
      +  theme_minimal()

      @@ -10318,17 +10256,17 @@

      Show the code -
      suppressMessages(
      -  ggplot(rf_val_preds, aes(x = reorder(district, abs_error, FUN = mean), y = abs_error)) +
      -    geom_boxplot(fill = NA, color = palette[3]) +
      -    labs(title = "MAE by Council District",
      -         y = "Mean Absolute Error",
      -         x = "Council District") +
      -    theme_minimal()
      -)
      +
      suppressMessages(
      +  ggplot(rf_val_preds, aes(x = reorder(district, abs_error, FUN = mean), y = abs_error)) +
      +    geom_boxplot(fill = NA, color = palette[3], alpha = 0.7) +
      +    labs(title = "MAE by Council District",
      +         y = "Mean Absolute Error",
      +         x = "Council District") +
      +    theme_minimal()
      +)
      -

      +

      @@ -10340,99 +10278,99 @@

      Show the code -
      filtered_zoning <- zoning %>%
      -                     filter(str_detect(CODE, "RS") | str_detect(CODE, "I"),
      -                            CODE != "I2",
      -                            !str_detect(CODE, "SP")) %>%
      -                     st_join(., rf_val_preds %>% select(rf_val_preds))
      -
      -
      -
      -zoning_map <- tmap_theme(tm_shape(filtered_zoning) +
      -        tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey", title = "Zoning Code") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Mismatched Zoning")
      -  
      -mismatch <- tmap_theme(tm_shape(filtered_zoning) +
      -        tm_polygons(col = "rf_val_preds", border.alpha = 0, colorNA = "lightgrey", palette = mono_5_orange, style = "fisher", title = "Predicted New Permits") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Development Pressure")
      -
      -tmap_arrange(zoning_map, mismatch)
      +
      filtered_zoning <- zoning %>%
      +                     filter(str_detect(CODE, "RS") | str_detect(CODE, "I"),
      +                            CODE != "I2",
      +                            !str_detect(CODE, "SP")) %>%
      +                     st_join(., rf_val_preds %>% select(rf_val_preds))
      +
      +
      +zoning_map <- tmap_theme(tm_shape(filtered_zoning) +
      +        tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey", title = "Zoning Code", palette = zoning_palette) +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE,
      +            legend.height = 0.4),
      +  "Mismatched Zoning")
      +  
      +mismatch <- tmap_theme(tm_shape(filtered_zoning) +
      +        tm_polygons(col = "rf_val_preds", border.alpha = 0, colorNA = "lightgrey", palette = mono_5_orange, style = "fisher", title = "Predicted New Permits") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Development Pressure")
      +
      +tmap_arrange(zoning_map, mismatch)
      -

      +

      We can extract development predictions at the block level to these parcels and then visualize them by highest need.

      Show the code -
      tmap_mode('view')
      -
      -filtered_zoning %>%
      -  filter(rf_val_preds > 10) %>%
      -tm_shape() +
      -        tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey",
      -                    popup.vars = c('rf_val_preds', 'CODE')) +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE)
      +
      tmap_mode('view')
      +
      +filtered_zoning %>%
      +  filter(rf_val_preds > 10) %>%
      +tm_shape() +
      +        tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey",
      +                    popup.vars = c('rf_val_preds', 'CODE'), palette = zoning_palette) +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE)
      -
      - +
      +

      Furthermore, we can identify properties with high potential for assemblage, which suggests the ability to accomodate high-density, multi-unit housing.

      Show the code -
      nbs <- filtered_zoning %>% 
      -  mutate(nb = st_contiguity(geometry))
      -
      -# Create edge list while handling cases with no neighbors
      -edge_list <- tibble::tibble(id = 1:length(nbs$nb), nbs = nbs$nb) %>% 
      -  tidyr::unnest(nbs) %>% 
      -  filter(nbs != 0)
      -
      -# Create a graph with a node for each row in filtered_zoning
      -g <- make_empty_graph(n = nrow(filtered_zoning))
      -V(g)$name <- as.character(1:nrow(filtered_zoning))
      -
      -# Add edges if they exist
      -if (nrow(edge_list) > 0) {
      -  edges <- as.matrix(edge_list)
      -  g <- add_edges(g, c(t(edges)))
      -}
      -
      -# Calculate the number of contiguous neighbors, handling nodes without neighbors
      -n_contiguous <- sapply(V(g)$name, function(node) {
      -  if (node %in% edges) {
      -    length(neighborhood(g, order = 1, nodes = as.numeric(node))[[1]])
      -  } else {
      -    1  # Nodes without neighbors count as 1 (themselves)
      -  }
      -})
      -
      -filtered_zoning <- filtered_zoning %>%
      -                    mutate(n_contig = n_contiguous)
      -
      -filtered_zoning %>%
      -  st_drop_geometry() %>%
      -  select(rf_val_preds,
      -         n_contig,
      -         OBJECTID,
      -         CODE) %>%
      -  filter(rf_val_preds > 10,
      -         n_contig > 2) %>%
      -  arrange(desc(rf_val_preds)) %>%
      -  kablerize(caption = "Poorly-Zoned Properties with High Development Risk")
      +
      nbs <- filtered_zoning %>% 
      +  mutate(nb = st_contiguity(geometry))
      +
      +# Create edge list while handling cases with no neighbors
      +edge_list <- tibble::tibble(id = 1:length(nbs$nb), nbs = nbs$nb) %>% 
      +  tidyr::unnest(nbs) %>% 
      +  filter(nbs != 0)
      +
      +# Create a graph with a node for each row in filtered_zoning
      +g <- make_empty_graph(n = nrow(filtered_zoning))
      +V(g)$name <- as.character(1:nrow(filtered_zoning))
      +
      +# Add edges if they exist
      +if (nrow(edge_list) > 0) {
      +  edges <- as.matrix(edge_list)
      +  g <- add_edges(g, c(t(edges)))
      +}
      +
      +# Calculate the number of contiguous neighbors, handling nodes without neighbors
      +n_contiguous <- sapply(V(g)$name, function(node) {
      +  if (node %in% edges) {
      +    length(neighborhood(g, order = 1, nodes = as.numeric(node))[[1]])
      +  } else {
      +    1  # Nodes without neighbors count as 1 (themselves)
      +  }
      +})
      +
      +filtered_zoning <- filtered_zoning %>%
      +                    mutate(n_contig = n_contiguous)
      +
      +filtered_zoning %>%
      +  st_drop_geometry() %>%
      +  select(rf_val_preds,
      +         n_contig,
      +         OBJECTID,
      +         CODE) %>%
      +  filter(rf_val_preds > 10,
      +         n_contig > 2) %>%
      +  arrange(desc(rf_val_preds)) %>%
      +  kablerize(caption = "Poorly-Zoned Properties with High Development Risk")
      @@ -10768,14 +10706,14 @@

      Show the code -
      tmap_mode('plot')
      -
      -tmap_theme(tm_shape(rf_proj_preds) +
      -        tm_polygons(col = "rf_proj_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Predicted New Permits") +
      -  tm_shape(broad_and_market) +
      -  tm_lines(col = "lightgrey") +
      -  tm_layout(frame = FALSE),
      -  "Projected New Development, 2024")
      +
      tmap_mode('plot')
      +
      +tmap_theme(tm_shape(rf_proj_preds) +
      +        tm_polygons(col = "rf_proj_preds", border.alpha = 0, palette = mono_5_green, style = "fisher", colorNA = "lightgrey", title = "Predicted New Permits") +
      +  tm_shape(broad_and_market) +
      +  tm_lines(col = "lightgrey") +
      +  tm_layout(frame = FALSE),
      +  "Projected New Development, 2024")

      @@ -10784,7 +10722,7 @@

      9 Web Application

      - +

      10 Next Steps