#Assignment 4- linear model is Moran's I and interpret spatial regression model 
#Research Question: What factors have the highest correlation to poverty in Chicago? 

library(sf)     
## Linking to GEOS 3.10.2, GDAL 3.4.2, PROJ 8.2.1; sf_use_s2() is TRUE
library(dplyr)   
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(spData) 
## To access larger datasets in this package, install the spDataLarge
## package with: `install.packages('spDataLarge',
## repos='https://nowosad.github.io/drat/', type='source')`
library(ggplot2)
library(ggthemes)
library(spdep)
library(spatialreg)
## Loading required package: Matrix
## 
## Attaching package: 'spatialreg'
## The following objects are masked from 'package:spdep':
## 
##     get.ClusterOption, get.coresOption, get.mcOption,
##     get.VerboseOption, get.ZeroPolicyOption, set.ClusterOption,
##     set.coresOption, set.mcOption, set.VerboseOption,
##     set.ZeroPolicyOption
library(GWmodel)
## Loading required package: robustbase
## Loading required package: sp
## Loading required package: Rcpp
## Welcome to GWmodel version 2.3-1.
library(tidyr)
## 
## Attaching package: 'tidyr'
## The following objects are masked from 'package:Matrix':
## 
##     expand, pack, unpack
setwd("/Users/Aiesha/Desktop/DIDA 370/chicago_airbnb")
chicago <- st_read("airbnb_Chicago 2015.shp") 
## Reading layer `airbnb_Chicago 2015' from data source 
##   `/Users/Aiesha/Desktop/DIDA 370/chicago_airbnb/airbnb_Chicago 2015.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 77 features and 20 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -87.94011 ymin: 41.64454 xmax: -87.52414 ymax: 42.02304
## Geodetic CRS:  WGS 84
ggplot()+
  geom_sf(data = chicago, aes(fill=as.numeric(poverty)))+
  scale_fill_steps(
    name = "Poverty",
    low = "lightsteelblue1",
    high = "tomato1",
    n.breaks = 5,
    show.limits = T)+
  theme_void()

#Simple Regression Model, poverty is dependent 

#create our variables for the model:
model <- chicago %>% 
  select(c(unemployed, without_hs, dependency, num_spots, geometry, poverty)) %>% 
  filter(!poverty %in% "NA")
  #mutate(poverty = as.numeric(poverty))

summary(lm1 <- lm(poverty ~ unemployed + without_hs + dependency + num_spots, data = model)) 
## 
## Call:
## lm(formula = poverty ~ unemployed + without_hs + dependency + 
##     num_spots, data = model)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -14.5526  -3.7946  -0.2939   3.8109  17.0702 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  5.308938   5.952610   0.892  0.37544    
## unemployed   1.350643   0.135636   9.958 3.53e-15 ***
## without_hs   0.213038   0.069361   3.071  0.00301 ** 
## dependency  -0.259300   0.183618  -1.412  0.16221    
## num_spots    0.009649   0.007601   1.269  0.20839    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 6.451 on 72 degrees of freedom
## Multiple R-squared:  0.7034, Adjusted R-squared:  0.6869 
## F-statistic: 42.69 on 4 and 72 DF,  p-value: < 2.2e-16
#Let's test for spatial autocorrelation in the residuals!
#Create the weights first
chicago_list <- model %>% 
  poly2nb(st_geometry(model)) %>% 
  nb2listw(zero.policy = TRUE) 

#run the Moran's I test for regression residuals
lm.morantest(lm1, chicago_list)
## 
##  Global Moran I for regression residuals
## 
## data:  
## model: lm(formula = poverty ~ unemployed + without_hs + dependency +
## num_spots, data = model)
## weights: chicago_list
## 
## Moran I statistic standard deviate = 3.7122, p-value = 0.0001027
## alternative hypothesis: greater
## sample estimates:
## Observed Moran I      Expectation         Variance 
##      0.216016690     -0.039309965      0.004730657
lm_error <- errorsarlm(poverty ~ unemployed + without_hs + dependency + num_spots,
              data = model,
              listw = chicago_list,
              zero.policy = TRUE, 
              na.action = na.omit)

summary(lm_error)
## 
## Call:errorsarlm(formula = poverty ~ unemployed + without_hs + dependency + 
##     num_spots, data = model, listw = chicago_list, na.action = na.omit, 
##     zero.policy = TRUE)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -13.34566  -4.23562  -0.42275   2.75451  12.64263 
## 
## Type: error 
## Coefficients: (asymptotic standard errors) 
##               Estimate Std. Error z value  Pr(>|z|)
## (Intercept) -1.3336792  6.0290520 -0.2212 0.8249299
## unemployed   1.0418742  0.1478779  7.0455 1.848e-12
## without_hs   0.3057668  0.0800513  3.8196 0.0001336
## dependency   0.0269340  0.1853243  0.1453 0.8844466
## num_spots    0.0028586  0.0072320  0.3953 0.6926451
## 
## Lambda: 0.64063, LR test value: 12.733, p-value: 0.00035935
## Asymptotic standard error: 0.10315
##     z-value: 6.2109, p-value: 5.2677e-10
## Wald statistic: 38.575, p-value: 5.2677e-10
## 
## Log likelihood: -243.8556 for error model
## ML residual variance (sigma squared): 29.672, (sigma: 5.4472)
## Number of observations: 77 
## Number of parameters estimated: 7 
## AIC: 501.71, (AIC for lm: 512.44)
# From this we can see that lambda is 0.64 which is statistically significant because it is closer to 1. This suggests that there is significant spatial autocorrelation in the residuals. In addition, the AIC value of 501.71 which is lower than the AIC for the linear model of 512.44 which means that there was in improvement in the model. 
#Spatial autocorrelation in the residuals of this model

seResiduals <- rep(0, length(model$poverty))
#create an index based on the order of the residuals in the lm_error object
resIndex <- lm_error$residuals %>% names() %>% as.integer();
#use the index to fill in the seResiduals object with corresponding residual values
seResiduals[resIndex] <- lm_error$residuals

#perform the Moran Test
chicago_list %>%
  moran.test(seResiduals, ., zero.policy = TRUE) 
## 
##  Moran I test under randomisation
## 
## data:  seResiduals  
## weights: .    
## 
## Moran I statistic standard deviate = -0.29478, p-value = 0.6159
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##      -0.034384258      -0.013157895       0.005185026
#Since the p-value is 0.6159, which is greater than 0.05, this means the Moran test is is insignificant. 
#Spatial lag model
lm_lag <- lagsarlm(poverty ~ unemployed + without_hs + dependency + num_spots,
              data = model,
              listw = chicago_list,
              zero.policy = TRUE, 
              na.action = na.omit)

summary(lm_lag)
## 
## Call:lagsarlm(formula = poverty ~ unemployed + without_hs + dependency + 
##     num_spots, data = model, listw = chicago_list, na.action = na.omit, 
##     zero.policy = TRUE)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -12.81473  -3.82159  -0.80766   3.40439  15.32690 
## 
## Type: lag 
## Coefficients: (asymptotic standard errors) 
##               Estimate Std. Error z value  Pr(>|z|)
## (Intercept)  0.8903049  5.6148974  0.1586  0.874015
## unemployed   1.1205339  0.1452171  7.7163 1.199e-14
## without_hs   0.2002305  0.0646313  3.0980  0.001948
## dependency  -0.1998272  0.1689150 -1.1830  0.236807
## num_spots    0.0094193  0.0069885  1.3478  0.177715
## 
## Rho: 0.27716, LR test value: 6.6178, p-value: 0.010097
## Asymptotic standard error: 0.10419
##     z-value: 2.6601, p-value: 0.007812
## Wald statistic: 7.0761, p-value: 0.007812
## 
## Log likelihood: -246.913 for lag model
## ML residual variance (sigma squared): 35.127, (sigma: 5.9268)
## Number of observations: 77 
## Number of parameters estimated: 7 
## AIC: NA (not available for weighted model), (AIC for lm: 512.44)
## LM test for residual autocorrelation
## test value: 2.0017, p-value: 0.15712
#Check for spatial autocorrelation in these residuals
seResiduals <- rep(0, length(model$poverty))
resIndex <- lm_lag$residuals %>% names() %>% as.integer();
seResiduals[resIndex] <- lm_lag$residuals

#perform the Moran Test
chicago_list %>%
  moran.test(seResiduals, ., zero.policy = TRUE) 
## 
##  Moran I test under randomisation
## 
## data:  seResiduals  
## weights: .    
## 
## Moran I statistic standard deviate = 1.2666, p-value = 0.1027
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       0.077755919      -0.013157895       0.005152423
LM <- lm.LMtests(lm1, chicago_list,test = "all")
LM
## 
##  Lagrange multiplier diagnostics for spatial dependence
## 
## data:  
## model: lm(formula = poverty ~ unemployed + without_hs + dependency +
## num_spots, data = model)
## weights: chicago_list
## 
## LMerr = 8.4306, df = 1, p-value = 0.00369
## 
## 
##  Lagrange multiplier diagnostics for spatial dependence
## 
## data:  
## model: lm(formula = poverty ~ unemployed + without_hs + dependency +
## num_spots, data = model)
## weights: chicago_list
## 
## LMlag = 7.159, df = 1, p-value = 0.007459
## 
## 
##  Lagrange multiplier diagnostics for spatial dependence
## 
## data:  
## model: lm(formula = poverty ~ unemployed + without_hs + dependency +
## num_spots, data = model)
## weights: chicago_list
## 
## RLMerr = 2.2136, df = 1, p-value = 0.1368
## 
## 
##  Lagrange multiplier diagnostics for spatial dependence
## 
## data:  
## model: lm(formula = poverty ~ unemployed + without_hs + dependency +
## num_spots, data = model)
## weights: chicago_list
## 
## RLMlag = 0.94203, df = 1, p-value = 0.3318
## 
## 
##  Lagrange multiplier diagnostics for spatial dependence
## 
## data:  
## model: lm(formula = poverty ~ unemployed + without_hs + dependency +
## num_spots, data = model)
## weights: chicago_list
## 
## SARMA = 9.3726, df = 2, p-value = 0.009221
#This shows that the LMerr test is the most significant because it has the lowest p-value of 0.00369 while LMlag has a p-value of 0.007459. We can also see that the p-value for RLMerr test is 0.1369 which is more significant than the RLMlag test with a p-value of 0.3318. 
#Let's pick the optimum bandwidth for our regression
bwVal <- GWmodel::bw.gwr(poverty ~ unemployed + without_hs + dependency + num_spots,
                         data = model %>% sf::as_Spatial(), 
                         approach = 'AICc', kernel = 'bisquare', 
                         adaptive = TRUE)
## Adaptive bandwidth (number of nearest neighbours): 55 AICc value: 508.0122 
## Adaptive bandwidth (number of nearest neighbours): 42 AICc value: 502.0065 
## Adaptive bandwidth (number of nearest neighbours): 33 AICc value: 502.5195 
## Adaptive bandwidth (number of nearest neighbours): 46 AICc value: 502.8133 
## Adaptive bandwidth (number of nearest neighbours): 37 AICc value: 502.3383 
## Adaptive bandwidth (number of nearest neighbours): 42 AICc value: 502.0065
bwVal
## [1] 42
lm.gwr <- gwr.basic(poverty ~ unemployed + without_hs + dependency + num_spots,
                     data = model %>% sf::as_Spatial(), 
                     bw = bwVal, kernel = "bisquare", adaptive = TRUE)

#Let's check the output of the model!
print(lm.gwr)
##    ***********************************************************************
##    *                       Package   GWmodel                             *
##    ***********************************************************************
##    Program starts at: 2024-04-26 18:44:18 
##    Call:
##    gwr.basic(formula = poverty ~ unemployed + without_hs + dependency + 
##     num_spots, data = model %>% sf::as_Spatial(), bw = bwVal, 
##     kernel = "bisquare", adaptive = TRUE)
## 
##    Dependent (y) variable:  poverty
##    Independent variables:  unemployed without_hs dependency num_spots
##    Number of data points: 77
##    ***********************************************************************
##    *                    Results of Global Regression                     *
##    ***********************************************************************
## 
##    Call:
##     lm(formula = formula, data = data)
## 
##    Residuals:
##      Min       1Q   Median       3Q      Max 
## -14.5526  -3.7946  -0.2939   3.8109  17.0702 
## 
##    Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
##    (Intercept)  5.308938   5.952610   0.892  0.37544    
##    unemployed   1.350643   0.135636   9.958 3.53e-15 ***
##    without_hs   0.213038   0.069361   3.071  0.00301 ** 
##    dependency  -0.259300   0.183618  -1.412  0.16221    
##    num_spots    0.009649   0.007601   1.269  0.20839    
## 
##    ---Significance stars
##    Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 
##    Residual standard error: 6.451 on 72 degrees of freedom
##    Multiple R-squared: 0.7034
##    Adjusted R-squared: 0.6869 
##    F-statistic: 42.69 on 4 and 72 DF,  p-value: < 2.2e-16 
##    ***Extra Diagnostic information
##    Residual sum of squares: 2996.493
##    Sigma(hat): 6.320858
##    AIC:  512.4438
##    AICc:  513.6438
##    BIC:  475.5694
##    ***********************************************************************
##    *          Results of Geographically Weighted Regression              *
##    ***********************************************************************
## 
##    *********************Model calibration information*********************
##    Kernel function: bisquare 
##    Adaptive bandwidth: 42 (number of nearest neighbours)
##    Regression points: the same locations as observations are used.
##    Distance metric: Euclidean distance metric is used.
## 
##    ****************Summary of GWR coefficient estimates:******************
##                      Min.     1st Qu.      Median     3rd Qu.    Max.
##    Intercept  -61.6494894 -23.4452369  -3.5147861   3.4656277 13.4621
##    unemployed   0.8167436   1.0086143   1.1296304   1.6670148  1.9304
##    without_hs  -0.0954411   0.0577141   0.1513663   0.2958841  0.6051
##    dependency  -0.4148439  -0.1978481   0.1693656   0.5116104  1.4683
##    num_spots   -0.0011847   0.0058865   0.0161795   0.1013088  0.3107
##    ************************Diagnostic information*************************
##    Number of data points: 77 
##    Effective number of parameters (2trace(S) - trace(S'S)): 19.63031 
##    Effective degrees of freedom (n-2trace(S) + trace(S'S)): 57.36969 
##    AICc (GWR book, Fotheringham, et al. 2002, p. 61, eq 2.33): 502.0065 
##    AIC (GWR book, Fotheringham, et al. 2002,GWR p. 96, eq. 4.22): 474.6029 
##    BIC (GWR book, Fotheringham, et al. 2002,GWR p. 61, eq. 2.34): 449.7179 
##    Residual sum of squares: 1749.689 
##    R-square value:  0.8268223 
##    Adjusted R-square value:  0.7665145 
## 
##    ***********************************************************************
##    Program stops at: 2024-04-26 18:44:18
#Add the coefficient for education to the model data
model$gwr_exp_coeff <- lm.gwr$SDF$without_hs
#There's a built in function to plot this, but we need to transform our sf object into an sp object instead
model1 <- as(model, Class = "Spatial")
#plot it!
p1 <- spplot(model1, "gwr_exp_coeff")

p1

model$gwr_exp_coeff <- lm.gwr$SDF$unemployed
model1 <- as(model, Class = "Spatial")
#plot it!
p2 <- spplot(model1, "gwr_exp_coeff")

p2

library(cowplot)
## 
## Attaching package: 'cowplot'
## The following object is masked from 'package:ggthemes':
## 
##     theme_map
plot_grid(p1, p2, 
          labels = c('A) Without HS Diploma', 'B) Unemployed'),
          hjust = -0.3, vjust = 4, label_size = 10)

Based on the results of my model, unemployed and without HS diploma are statistically significant and have on impact on poverty. They also have some of the lowest p-values with unemployed being more statistically significant than a HS diploma.