diff --git a/.nojekyll b/.nojekyll index 8477f44..252e374 100644 --- a/.nojekyll +++ b/.nojekyll @@ -1 +1 @@ -f50c4fc0 \ No newline at end of file +83c1aad0 \ No newline at end of file diff --git a/assets/permits_animation.gif b/assets/permits_animation.gif index 911fe1f..0f53bd7 100644 Binary files a/assets/permits_animation.gif and b/assets/permits_animation.gif differ diff --git a/final.html b/final.html index 352077f..7b719d1 100644 --- a/final.html +++ b/final.html @@ -6,7 +6,7 @@ - + Predicting New Construction in Philadelphia + + + +

3.1.1 Feature Engineering

@@ -8524,22 +9408,23 @@

Show the code
permits_bg_long <- permits_bg %>%
-                    st_drop_geometry() %>%
-                    pivot_longer(
-                      cols = c(starts_with("lag"), dist_to_2022),
-                      names_to = "Variable",
-                      values_to = "Value"
-                    )
-
+                    filter(year != 2023) %>%
+                    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 = "blue", fill = "lightgray"),
-   conf.int = TRUE
-   ) + stat_cor(method = "pearson", p.accuracy = 0.001, r.accuracy = 0.01)
+ +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)
-

+

@@ -8558,24 +9443,25 @@

Show the code
permits_train <- filter(permits_bg %>% select(-mapname), year < 2022)
 permits_test <- filter(permits_bg %>% select(-mapname), year == 2022)
-
-reg <- lm(permits_count ~ ., data = st_drop_geometry(permits_train))
-
-predictions <- predict(reg, permits_test)
-predictions <- cbind(permits_test, predictions)
-
-predictions <- predictions %>%
-                  mutate(abs_error = abs(permits_count - predictions),
-                         pct_error = abs_error / permits_count)
-
-ggplot(predictions, aes(x = permits_count, y = predictions)) +
-  geom_point() +
-  labs(title = "Predicted vs. Actual Permits",
-       subtitle = "2022") +
-  geom_smooth(method = "lm", se = FALSE)
+permits_validate <- filter(permits_bg %>% select(-mapname), year == 2023) + +reg <- lm(permits_count ~ ., data = st_drop_geometry(permits_train)) + +predictions <- predict(reg, permits_test) +predictions <- cbind(permits_test, predictions) + +predictions <- predictions %>% + mutate(abs_error = abs(permits_count - predictions), + pct_error = abs_error / permits_count) + +ggplot(predictions, aes(x = permits_count, y = predictions)) + + geom_point() + + labs(title = "Predicted vs. Actual Permits", + subtitle = "2022") + + geom_smooth(method = "lm", se = FALSE)
-

+

Show the code @@ -8588,7 +9474,7 @@

tm_layout(frame = FALSE)

-

+

@@ -8616,7 +9502,7 @@

geom_smooth(method = "lm", se = FALSE)
-

+

Show the code @@ -8629,10 +9515,10 @@

tm_layout(frame = FALSE)

-

+

-

We find that our OLS model has an MAE of only MAE: 2.44–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.

+

We find that our OLS model has an MAE of only MAE: 2.25–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 Random Forest Regression

@@ -8657,7 +9543,7 @@

geom_smooth(method = "lm", se = FALSE)
-

+

Show the code @@ -8670,7 +9556,7 @@

tm_layout(frame = FALSE)

-

+

@@ -8691,8 +9577,15 @@

geom_vline(aes(xintercept = vline))
-

+

+
+Show the code +
hmm <- permits_bg %>%
+  st_drop_geometry() %>%
+  group_by(year) %>%
+  summarize_all(.funs = list(~sum(is.na(.)))) # Check NA for all columns
+
@@ -8700,28 +9593,30 @@

Show the code -
tm_shape(acs19) +
-        tm_polygons(col = "Percent_Nonwhite", border.alpha = 0, palette = 'viridis', style = "fisher", colorNA = "lightgrey") +
-  tm_shape(broad_and_market) +
-  tm_lines(col = "lightgrey") +
-  tm_layout(frame = FALSE)
+
# tm_shape(acs22) +
+#         tm_polygons(col = "Percent_Nonwhite", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey") +
+#   tm_shape(broad_and_market) +
+#   tm_lines(col = "lightgrey") +
+#   tm_layout(frame = FALSE)
+# 
+# 
+# tm_shape(acs22) +
+#         tm_polygons(col = "Ext_Rent_Burden", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey") +
+#   tm_shape(broad_and_market) +
+#   tm_lines(col = "lightgrey") +
+#   tm_layout(frame = FALSE)
+
+rf_predictions <- rf_predictions %>%
+                      mutate(race_comp = case_when(
+                        percent_nonwhite >= .50 ~ "Majority Non-White",
+                        TRUE ~ "Majority White"
+                      ))
+
+ggplot(rf_predictions, aes(y = abs_error, color = race_comp)) +
+  geom_boxplot(fill = NA)
-

-
-
-Show the code -
rf_predictions <- rf_predictions %>%
-                      mutate(race_comp = case_when(
-                        percent_nonwhite >= .50 ~ "Majority Non-White",
-                        TRUE ~ "Majority White"
-                      ))
-
-ggplot(rf_predictions, aes(y = abs_error, color = race_comp)) +
-  geom_boxplot(fill = NA)
-
-
-

+

How does this generalize across neighborhoods?

@@ -8735,17 +9630,18 @@

Show the code
filtered_zoning <- zoning %>%
-                     filter(str_detect(CODE, "RS") | str_detect(CODE, "I"))
-
+                     filter(str_detect(CODE, "RS") | str_detect(CODE, "I"),
+                            CODE != "I2")
 
-tm_shape(filtered_zoning) +
-        tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey") +
-  tm_shape(broad_and_market) +
-  tm_lines(col = "lightgrey") +
-  tm_layout(frame = FALSE)
+ +tm_shape(filtered_zoning) + + tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey") + + tm_shape(broad_and_market) + + tm_lines(col = "lightgrey") + + tm_layout(frame = FALSE)
-

+

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

@@ -8764,7 +9660,7 @@

tm_layout(frame = FALSE)
-

+

@@ -8783,8 +9679,8 @@

-
- +
+

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

@@ -8829,7 +9725,8 @@

CODE) %>% filter(rf_predictions > 10, n_contig > 2) %>% - kablerize(caption = "Poorly-Zoned Properties with High Development Risk") + arrange(desc(rf_predictions)) %>% + kablerize(caption = "Poorly-Zoned Properties with High Development Risk")
@@ -8845,550 +9742,277 @@

- - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - - - - - - - - - - - - - - - + + - - - - - - - - + - - + + - - - - - - - - + - - - - - - - - - + + - + - - - - - - - - - - - - - - - - - - - - - - - + + - + - - - - - - - - - + + - + - - - - + + + + - - + + - + - - + + - + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - - - - + + + + + - - + + - + - - + + - - + + - - - - - - - - - + + - + - - - - - - - - - + + - + - - + + - - + + - - + + - + - - + + - - - - - - - - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - + + - + - - - - - - - - - + + - + - - - - - - - - - - - - - - - - + + - + - - - - - - - - - + + - + - - - - - - - - - - - - - - - - + + - - + + - - + + - - + + - - - - - + + + + + - - - - - + + + + + - - + + - + - - - - - - - - - - - - - - - - + + - - + + - - + + - - - - - - - - + - - - - - - - - - - - - - - - - - - - + + + + +
27512.16710757538.37310 3604I2
85821.5859761524ICMX
90312.9468361595RSA5
91621.5859781615ICMX
152211.244374255916717 RSA5
163121.58597499334.18023 32736IRMX
164321.5859762756ICMX
167021.585977280310410 ICMX
167121.5859732804IRMX
186534.3893033128IRMX
209912.9468363492RSA5
225111.4208043744IRMX
268512.9468364533RSA5
316810.58817499434.18023 3550610411 RSA5
343921.5859766067ICMX
355412.9468366289RSA5
361621.58597499534.18023 36405RSA5
383612.946837686910412 ICMX
384634.38930528434.18023 36901ICMX
386512.946836694311160 RSA5
415529.6927037646ICMX
417811.21383178431.03953 377043128 IRMX
459312.9468368805RSA5
469723.0356339094RSA5
475216.0827359244IRMX
480010.58817366931.03953 393716901 ICMX
491021.5859739662RSA5
521135.68783396425.55263 3104117646 ICMX
521235.687833104121240725.55263425776 RSA5
521335.6878387521.73580 3104131615 ICMX
534518.21887156321.73580 3107602736 IRMX
550139.00537160221.73580 311150ICMX2804IRMX
550635.68783344821.73580 3111616405 RSA5
561611.24437470021.73580 311449RSA39661RSA5
599611.00043923921.73580 412339I220073ICMX
620611.00043449220.66737 3128089093 RSA5
625811.000431366219.53400 312932ICMX27869IRMX
631216.08273613058ICMX512519.05720310759IRMX
641223.99983398715.37260 3133147704 IRMX
670322.58767778614.19870 313979I317168ICMX
670511.00043313981RSA3
672013.26530789313.97167 31401917408 RSA5
6793.211.00043814223I2
679422.58767600812.64667 31422412931 ICMX
680822.58767644412.64667 314257I213980RSA3
685511.00043658912.64667 31437314372 RSA5
686411.00043659912.64667 3 14401 RSA5
686511.00043314402RSA5
696513.26530669612.30283 31464914648 ICMX
701412.94683814748ICMX
719211.24437315167RSA2
744639.00537315720I2
748711.00043615820RSA5
763713.26530316181RSA5
788539.00537733512.30283 31671916179 RSA5
810515.75340998412.30283 31717021527 ICMX
813213.26530317217ICMX
822015.48503581811.93540 31741012473 RSA5
854313.56143318033RSD3
907513.56143319078RSA3
936211.24437831511.93540 31959318254 RSA3
960721.58597420075ICMX
980212.167101292311.93540 32044426627 RSA5
985413.56143420536RSA2
1037713.26530321529ICMX
1065113.56143417711.82093 322004RSD18265IRMX
1287729.69270514511.82093 425778RSA510795IRMX
1292911.24437425868RSA1454411.5650059243IRMX
1316413.56143326249RSD1605811.56500613057ICMX
1349410.85073303111.14353 3267595506 RSA5
1359911.24437326935RSA3
1381711.24437327284RSA2
1389211.24437459011.14353 327394RSD39370ICMX
1411013.26530215410.89000 427776I2
1415816.066803278713744 IRMX
14719.221.585972828949I2
14719.312.946832828949I2
1472012.94683628950RSA5624810.01617413532ICMX
@@ -9415,9 +10039,19 @@

-
- +
+ +

+

+
+

5.4 2024 Predictions

+

Just for shits and giggles, throw in 2024 predictions. (Can use data from 2023.)

+
+
+Show the code +
# need to create a new dataframe with year = 2024, spatial and temporal lag based on 2023, and most recent ACS data (2022)
+
diff --git a/index.html b/index.html index 352077f..7b719d1 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ - + Predicting New Construction in Philadelphia + + + +

3.1.1 Feature Engineering

@@ -8524,22 +9408,23 @@

Show the code
permits_bg_long <- permits_bg %>%
-                    st_drop_geometry() %>%
-                    pivot_longer(
-                      cols = c(starts_with("lag"), dist_to_2022),
-                      names_to = "Variable",
-                      values_to = "Value"
-                    )
-
+                    filter(year != 2023) %>%
+                    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 = "blue", fill = "lightgray"),
-   conf.int = TRUE
-   ) + stat_cor(method = "pearson", p.accuracy = 0.001, r.accuracy = 0.01)
+ +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)
-

+

@@ -8558,24 +9443,25 @@

Show the code
permits_train <- filter(permits_bg %>% select(-mapname), year < 2022)
 permits_test <- filter(permits_bg %>% select(-mapname), year == 2022)
-
-reg <- lm(permits_count ~ ., data = st_drop_geometry(permits_train))
-
-predictions <- predict(reg, permits_test)
-predictions <- cbind(permits_test, predictions)
-
-predictions <- predictions %>%
-                  mutate(abs_error = abs(permits_count - predictions),
-                         pct_error = abs_error / permits_count)
-
-ggplot(predictions, aes(x = permits_count, y = predictions)) +
-  geom_point() +
-  labs(title = "Predicted vs. Actual Permits",
-       subtitle = "2022") +
-  geom_smooth(method = "lm", se = FALSE)
+permits_validate <- filter(permits_bg %>% select(-mapname), year == 2023) + +reg <- lm(permits_count ~ ., data = st_drop_geometry(permits_train)) + +predictions <- predict(reg, permits_test) +predictions <- cbind(permits_test, predictions) + +predictions <- predictions %>% + mutate(abs_error = abs(permits_count - predictions), + pct_error = abs_error / permits_count) + +ggplot(predictions, aes(x = permits_count, y = predictions)) + + geom_point() + + labs(title = "Predicted vs. Actual Permits", + subtitle = "2022") + + geom_smooth(method = "lm", se = FALSE)
-

+

Show the code @@ -8588,7 +9474,7 @@

tm_layout(frame = FALSE)

-

+

@@ -8616,7 +9502,7 @@

geom_smooth(method = "lm", se = FALSE)
-

+

Show the code @@ -8629,10 +9515,10 @@

tm_layout(frame = FALSE)

-

+

-

We find that our OLS model has an MAE of only MAE: 2.44–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.

+

We find that our OLS model has an MAE of only MAE: 2.25–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 Random Forest Regression

@@ -8657,7 +9543,7 @@

geom_smooth(method = "lm", se = FALSE)
-

+

Show the code @@ -8670,7 +9556,7 @@

tm_layout(frame = FALSE)

-

+

@@ -8691,8 +9577,15 @@

geom_vline(aes(xintercept = vline))
-

+

+
+Show the code +
hmm <- permits_bg %>%
+  st_drop_geometry() %>%
+  group_by(year) %>%
+  summarize_all(.funs = list(~sum(is.na(.)))) # Check NA for all columns
+
@@ -8700,28 +9593,30 @@

Show the code -
tm_shape(acs19) +
-        tm_polygons(col = "Percent_Nonwhite", border.alpha = 0, palette = 'viridis', style = "fisher", colorNA = "lightgrey") +
-  tm_shape(broad_and_market) +
-  tm_lines(col = "lightgrey") +
-  tm_layout(frame = FALSE)
+
# tm_shape(acs22) +
+#         tm_polygons(col = "Percent_Nonwhite", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey") +
+#   tm_shape(broad_and_market) +
+#   tm_lines(col = "lightgrey") +
+#   tm_layout(frame = FALSE)
+# 
+# 
+# tm_shape(acs22) +
+#         tm_polygons(col = "Ext_Rent_Burden", border.alpha = 0, palette = mono_5_orange, style = "fisher", colorNA = "lightgrey") +
+#   tm_shape(broad_and_market) +
+#   tm_lines(col = "lightgrey") +
+#   tm_layout(frame = FALSE)
+
+rf_predictions <- rf_predictions %>%
+                      mutate(race_comp = case_when(
+                        percent_nonwhite >= .50 ~ "Majority Non-White",
+                        TRUE ~ "Majority White"
+                      ))
+
+ggplot(rf_predictions, aes(y = abs_error, color = race_comp)) +
+  geom_boxplot(fill = NA)
-

-
-
-Show the code -
rf_predictions <- rf_predictions %>%
-                      mutate(race_comp = case_when(
-                        percent_nonwhite >= .50 ~ "Majority Non-White",
-                        TRUE ~ "Majority White"
-                      ))
-
-ggplot(rf_predictions, aes(y = abs_error, color = race_comp)) +
-  geom_boxplot(fill = NA)
-
-
-

+

How does this generalize across neighborhoods?

@@ -8735,17 +9630,18 @@

Show the code
filtered_zoning <- zoning %>%
-                     filter(str_detect(CODE, "RS") | str_detect(CODE, "I"))
-
+                     filter(str_detect(CODE, "RS") | str_detect(CODE, "I"),
+                            CODE != "I2")
 
-tm_shape(filtered_zoning) +
-        tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey") +
-  tm_shape(broad_and_market) +
-  tm_lines(col = "lightgrey") +
-  tm_layout(frame = FALSE)
+ +tm_shape(filtered_zoning) + + tm_polygons(col = "CODE", border.alpha = 0, colorNA = "lightgrey") + + tm_shape(broad_and_market) + + tm_lines(col = "lightgrey") + + tm_layout(frame = FALSE)
-

+

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

@@ -8764,7 +9660,7 @@

tm_layout(frame = FALSE)
-

+

@@ -8783,8 +9679,8 @@

-
- +
+

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

@@ -8829,7 +9725,8 @@

CODE) %>% filter(rf_predictions > 10, n_contig > 2) %>% - kablerize(caption = "Poorly-Zoned Properties with High Development Risk") + arrange(desc(rf_predictions)) %>% + kablerize(caption = "Poorly-Zoned Properties with High Development Risk")
@@ -8845,550 +9742,277 @@

- - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - - - - - - - - - - - - - - - + + - - - - - - - - + - - + + - - - - - - - - + - - - - - - - - - + + - + - - - - - - - - - - - - - - - - - - - - - - - + + - + - - - - - - - - - + + - + - - - - + + + + - - + + - + - - + + - + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - - - - + + + + + - - + + - + - - + + - - + + - - - - - - - - - + + - + - - - - - - - - - + + - + - - + + - - + + - - + + - + - - + + - - - - - - - - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - + + - + - - - - - - - - - + + - + - - - - - - - - - - - - - - - - + + - + - - - - - - - - - + + - + - - - - - - - - - - - - - - - - + + - - + + - - + + - - + + - - - - - + + + + + - - - - - + + + + + - - + + - + - - - - - - - - - - - - - - - - + + - - + + - - + + - - - - - - - - + - - - - - - - - - - - - - - - - - - - + + + + +
27512.16710757538.37310 3604I2
85821.5859761524ICMX
90312.9468361595RSA5
91621.5859781615ICMX
152211.244374255916717 RSA5
163121.58597499334.18023 32736IRMX
164321.5859762756ICMX
167021.585977280310410 ICMX
167121.5859732804IRMX
186534.3893033128IRMX
209912.9468363492RSA5
225111.4208043744IRMX
268512.9468364533RSA5
316810.58817499434.18023 3550610411 RSA5
343921.5859766067ICMX
355412.9468366289RSA5
361621.58597499534.18023 36405RSA5
383612.946837686910412 ICMX
384634.38930528434.18023 36901ICMX
386512.946836694311160 RSA5
415529.6927037646ICMX
417811.21383178431.03953 377043128 IRMX
459312.9468368805RSA5
469723.0356339094RSA5
475216.0827359244IRMX
480010.58817366931.03953 393716901 ICMX
491021.5859739662RSA5
521135.68783396425.55263 3104117646 ICMX
521235.687833104121240725.55263425776 RSA5
521335.6878387521.73580 3104131615 ICMX
534518.21887156321.73580 3107602736 IRMX
550139.00537160221.73580 311150ICMX2804IRMX
550635.68783344821.73580 3111616405 RSA5
561611.24437470021.73580 311449RSA39661RSA5
599611.00043923921.73580 412339I220073ICMX
620611.00043449220.66737 3128089093 RSA5
625811.000431366219.53400 312932ICMX27869IRMX
631216.08273613058ICMX512519.05720310759IRMX
641223.99983398715.37260 3133147704 IRMX
670322.58767778614.19870 313979I317168ICMX
670511.00043313981RSA3
672013.26530789313.97167 31401917408 RSA5
6793.211.00043814223I2
679422.58767600812.64667 31422412931 ICMX
680822.58767644412.64667 314257I213980RSA3
685511.00043658912.64667 31437314372 RSA5
686411.00043659912.64667 3 14401 RSA5
686511.00043314402RSA5
696513.26530669612.30283 31464914648 ICMX
701412.94683814748ICMX
719211.24437315167RSA2
744639.00537315720I2
748711.00043615820RSA5
763713.26530316181RSA5
788539.00537733512.30283 31671916179 RSA5
810515.75340998412.30283 31717021527 ICMX
813213.26530317217ICMX
822015.48503581811.93540 31741012473 RSA5
854313.56143318033RSD3
907513.56143319078RSA3
936211.24437831511.93540 31959318254 RSA3
960721.58597420075ICMX
980212.167101292311.93540 32044426627 RSA5
985413.56143420536RSA2
1037713.26530321529ICMX
1065113.56143417711.82093 322004RSD18265IRMX
1287729.69270514511.82093 425778RSA510795IRMX
1292911.24437425868RSA1454411.5650059243IRMX
1316413.56143326249RSD1605811.56500613057ICMX
1349410.85073303111.14353 3267595506 RSA5
1359911.24437326935RSA3
1381711.24437327284RSA2
1389211.24437459011.14353 327394RSD39370ICMX
1411013.26530215410.89000 427776I2
1415816.066803278713744 IRMX
14719.221.585972828949I2
14719.312.946832828949I2
1472012.94683628950RSA5624810.01617413532ICMX
@@ -9415,9 +10039,19 @@

-
- +
+ +

+

+
+

5.4 2024 Predictions

+

Just for shits and giggles, throw in 2024 predictions. (Can use data from 2023.)

+
+
+Show the code +
# need to create a new dataframe with year = 2024, spatial and temporal lag based on 2023, and most recent ACS data (2022)
+