# Section 1: In this study, the goal is to use Multiple Linear Regression to investigate one central question: What environmental and neighborhood characteristics are most strongly associated with home prices, and how can these factors be used to estimate residential property values and inform future policies?
# My primary statistical modeling approach was using a multiple linear regression model with variables that most directly relate to the research question. I focused on factors such as pupil-to-teacher ratios, nitric oxide concentrations, and lower-status population percentages to examine the relationships between neighborhood and environmental characteristics with housing prices. I used the findings from this regression model to support recommendations for future city policies, with air quality and access to education being two areas that warrant further investigation due to their relationships with housing costs. In addition, the expanded model included interactions between various factors, such as nitric oxide concentration influencing the relationship between the average number of rooms and housing values. The main policy takeaway for the city planning board is that initiatives to improve environmental quality and educational resources across Boston neighborhoods could have important implications for neighborhood development and housing affordability.
# Section 2: Exploratory Data Analysis
# install.packages("caret", repos = "https://cloud.r-project.org")
# install.packages("car", repos = "https://cloud.r-project.org")
# install.packages("tidyverse", repos = "https://cloud.r-project.org")
library(tidyverse) # 1. Load required packages
library(caret)
library(car)
df <- read.csv("HousingData.csv") # Import Housing Data csv
head(df) # Display the first 6 rows
## CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT
## 1 0.00632 18 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98
## 2 0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14
## 3 0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03
## 4 0.03237 0 2.18 0 0.458 6.998 45.8 6.0622 3 222 18.7 394.63 2.94
## 5 0.06905 0 2.18 0 0.458 7.147 54.2 6.0622 3 222 18.7 396.90 NA
## 6 0.02985 0 2.18 0 0.458 6.430 58.7 6.0622 3 222 18.7 394.12 5.21
## MEDV
## 1 24.0
## 2 21.6
## 3 34.7
## 4 33.4
## 5 36.2
## 6 28.7
summary(df) # Summarize variable distributions
## CRIM ZN INDUS CHAS
## Min. : 0.00632 Min. : 0.00 Min. : 0.46 Min. :0.00000
## 1st Qu.: 0.08190 1st Qu.: 0.00 1st Qu.: 5.19 1st Qu.:0.00000
## Median : 0.25372 Median : 0.00 Median : 9.69 Median :0.00000
## Mean : 3.61187 Mean : 11.21 Mean :11.08 Mean :0.06996
## 3rd Qu.: 3.56026 3rd Qu.: 12.50 3rd Qu.:18.10 3rd Qu.:0.00000
## Max. :88.97620 Max. :100.00 Max. :27.74 Max. :1.00000
## NAs :20 NAs :20 NAs :20 NAs :20
## NOX RM AGE DIS
## Min. :0.3850 Min. :3.561 Min. : 2.90 Min. : 1.130
## 1st Qu.:0.4490 1st Qu.:5.886 1st Qu.: 45.17 1st Qu.: 2.100
## Median :0.5380 Median :6.208 Median : 76.80 Median : 3.207
## Mean :0.5547 Mean :6.285 Mean : 68.52 Mean : 3.795
## 3rd Qu.:0.6240 3rd Qu.:6.623 3rd Qu.: 93.97 3rd Qu.: 5.188
## Max. :0.8710 Max. :8.780 Max. :100.00 Max. :12.127
## NAs :20
## RAD TAX PTRATIO B
## Min. : 1.000 Min. :187.0 Min. :12.60 Min. : 0.32
## 1st Qu.: 4.000 1st Qu.:279.0 1st Qu.:17.40 1st Qu.:375.38
## Median : 5.000 Median :330.0 Median :19.05 Median :391.44
## Mean : 9.549 Mean :408.2 Mean :18.46 Mean :356.67
## 3rd Qu.:24.000 3rd Qu.:666.0 3rd Qu.:20.20 3rd Qu.:396.23
## Max. :24.000 Max. :711.0 Max. :22.00 Max. :396.90
##
## LSTAT MEDV
## Min. : 1.730 Min. : 5.00
## 1st Qu.: 7.125 1st Qu.:17.02
## Median :11.430 Median :21.20
## Mean :12.715 Mean :22.53
## 3rd Qu.:16.955 3rd Qu.:25.00
## Max. :37.970 Max. :50.00
## NAs :20
str(df)
## 'data.frame': 506 obs. of 14 variables:
## $ CRIM : num 0.00632 0.02731 0.02729 0.03237 0.06905 ...
## $ ZN : num 18 0 0 0 0 0 12.5 12.5 12.5 12.5 ...
## $ INDUS : num 2.31 7.07 7.07 2.18 2.18 2.18 7.87 7.87 7.87 7.87 ...
## $ CHAS : int 0 0 0 0 0 0 NA 0 0 NA ...
## $ NOX : num 0.538 0.469 0.469 0.458 0.458 0.458 0.524 0.524 0.524 0.524 ...
## $ RM : num 6.58 6.42 7.18 7 7.15 ...
## $ AGE : num 65.2 78.9 61.1 45.8 54.2 58.7 66.6 96.1 100 85.9 ...
## $ DIS : num 4.09 4.97 4.97 6.06 6.06 ...
## $ RAD : int 1 2 2 3 3 3 5 5 5 5 ...
## $ TAX : int 296 242 242 222 222 222 311 311 311 311 ...
## $ PTRATIO: num 15.3 17.8 17.8 18.7 18.7 18.7 15.2 15.2 15.2 15.2 ...
## $ B : num 397 397 393 395 397 ...
## $ LSTAT : num 4.98 9.14 4.03 2.94 NA ...
## $ MEDV : num 24 21.6 34.7 33.4 36.2 28.7 22.9 27.1 16.5 18.9 ...
names(df) # Display column names
## [1] "CRIM" "ZN" "INDUS" "CHAS" "NOX" "RM" "AGE"
## [8] "DIS" "RAD" "TAX" "PTRATIO" "B" "LSTAT" "MEDV"
# HOUSE AGE vs PROPERTY PRICE
ggplot(df, aes(x = AGE, y = MEDV)) + # Relationship between house age and property price
geom_point() +
geom_smooth(method = "lm", se = TRUE) +
labs(
title = "Property Price vs. House Age",
x = "% of Homes Built Before 1940",
y = "Median Home Value ($1,000s)"
) +
theme_minimal()

# NUMBER OF ROOMS vs PROPERTY PRICE
ggplot(df, aes(x = RM, y = MEDV)) + # Relationship between number of rooms and property price
geom_point() +
geom_smooth(method = "lm", se = TRUE) +
labs(
title = "Property Price vs. Number of Rooms",
x = "Number of Rooms",
y = "Median Home Value ($1,000s)"
) +
theme_minimal()

# NITROGEN OXIDE CONCENTRATION vs PROPERTY PRICE
ggplot(df, aes(x = NOX, y = MEDV)) + # Environmental metric impact on property price
geom_point() +
geom_smooth(method = "lm", se = TRUE) +
labs(
title = "Property Price vs. Nitrogen Oxide Concentration",
x = "Nitrogen Oxide Concentration",
y = "Median Home Value ($1,000s)"
) +
theme_minimal()

# NEIGHBORHOOD LOWER STATUS POPULATION vs PROPERTY PRICE
ggplot(df, aes(x = LSTAT, y = MEDV)) + # Neighborhood factors impact on property price
geom_point() +
geom_smooth(method = "lm", se = TRUE) +
labs(
title = "Property Price vs. Lower Neighborhood Status",
x = "Percentage of Lower-Status Neighborhood Population",
y = "Median Home Value ($1,000s)"
) +
theme_minimal()

# SCHOOL RATING vs PROPERTY PRICE
ggplot(df, aes(x = PTRATIO, y = MEDV)) + # Educational factor impact on property price
geom_point() +
geom_smooth(method = "lm", se = TRUE) +
labs(
title = "Property Price vs. Pupil-Teacher Ratio",
x = "Pupil to Teacher Ratio",
y = "Median Home Value ($1,000s)"
) +
theme_minimal()

# CRIME RATE vs PROPERTY PRICE
ggplot(df, aes(x = CRIM, y = MEDV)) + # Crime rate impact on property price
geom_point() +
geom_smooth(method = "lm", se = TRUE) +
labs(
title = "Property Price vs. Crime Rate",
x = "Crime Rate",
y = "Median Home Value ($1,000s)"
) +
theme_minimal()

# Section 3: Model Building & Selection
set.seed(42)
train_index <- caret::createDataPartition(
y = df$MEDV,
p = 0.80,
list = FALSE
)
train <- df[train_index, ]
test <- df[-train_index, ]
nrow(train) # Check that 80-20 split functions correctly (407-99)
## [1] 407
nrow(test)
## [1] 99
# Baseline Model 1 without interaction terms
model1 <- lm(MEDV ~ RM + AGE + NOX + CRIM + PTRATIO + LSTAT, data = train)
summary(model1)
##
## Call:
## lm(formula = MEDV ~ RM + AGE + NOX + CRIM + PTRATIO + LSTAT,
## data = train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -13.5060 -3.0007 -0.4043 1.8420 28.8216
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 16.53159 4.71265 3.508 0.00051 ***
## RM 5.00076 0.49464 10.110 < 2e-16 ***
## AGE 0.01849 0.01436 1.288 0.19866
## NOX -6.90850 3.30502 -2.090 0.03731 *
## CRIM -0.09035 0.03017 -2.994 0.00295 **
## PTRATIO -0.94266 0.12917 -7.298 1.97e-12 ***
## LSTAT -0.42518 0.06147 -6.917 2.19e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.728 on 351 degrees of freedom
## (49 observations deleted due to missingness)
## Multiple R-squared: 0.7172, Adjusted R-squared: 0.7124
## F-statistic: 148.3 on 6 and 351 DF, p-value: < 2.2e-16
# Expanded Model 2 with interaction terms with home size
model2 <- lm(MEDV ~ RM*PTRATIO + RM*LSTAT + RM*NOX + AGE + NOX + CRIM + PTRATIO + LSTAT, data = train)
summary(model2)
##
## Call:
## lm(formula = MEDV ~ RM * PTRATIO + RM * LSTAT + RM * NOX + AGE +
## NOX + CRIM + PTRATIO + LSTAT, data = train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -8.8422 -2.1696 -0.4935 1.8040 28.4770
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -148.45859 18.53089 -8.011 1.73e-14 ***
## RM 29.93027 2.85452 10.485 < 2e-16 ***
## PTRATIO 5.13058 0.81645 6.284 9.86e-10 ***
## LSTAT 1.10376 0.23593 4.678 4.15e-06 ***
## NOX 65.71571 17.66443 3.720 0.000232 ***
## AGE 0.02455 0.01141 2.150 0.032205 *
## CRIM -0.12452 0.02363 -5.271 2.39e-07 ***
## RM:PTRATIO -0.90118 0.12696 -7.098 7.14e-12 ***
## RM:LSTAT -0.28209 0.04092 -6.893 2.57e-11 ***
## RM:NOX -10.99551 2.91261 -3.775 0.000188 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3.68 on 348 degrees of freedom
## (49 observations deleted due to missingness)
## Multiple R-squared: 0.8302, Adjusted R-squared: 0.8258
## F-statistic: 189 on 9 and 348 DF, p-value: < 2.2e-16
# Interpretation: The interaction terms between the average number of rooms (RM) and the other predictors indicate whether the relationship between housing value and the number of rooms changes depending on these variables. Low p-values and high absolute t-statistics suggest that the corresponding interaction terms are statistically significant. The negative coefficient estimates for the relevant predictors indicate that, holding other variables constant, increases in these predictors are associated with lower predicted housing values. For the interaction terms specifically, a negative coefficient suggests that the effect of the number of rooms on predicted housing value becomes less positive/more negative as the interacting predictor increases.
# The coefficient for the NOX (Nitric Oxide Concentration) stood out the most as a variable in this multiple linear regression model. With a coefficient estimate of 65.7, this indicates that, according to the model, an increase in NOX is associated with an increase in predicted housing value. As a result, this factor needs further investigation to draw stronger conclusions about its relationship with housing prices and determine whether it has any implications for future policy recommendations.
# Predictions
pred1 <- predict(model1, newdata = test)
pred2 <- predict(model2, newdata = test)
# MAE
mae1 <- mean(abs(test$MEDV - pred1), na.rm = TRUE)
mae2 <- mean(abs(test$MEDV - pred2), na.rm = TRUE)
# RMSE
rmse1 <- sqrt(mean((test$MEDV - pred1)^2, na.rm = TRUE))
rmse2 <- sqrt(mean((test$MEDV - pred2)^2, na.rm = TRUE))
# R-squared
r2_1 <- 1 - sum((test$MEDV - pred1)^2, na.rm = TRUE) /
sum((test$MEDV - mean(test$MEDV, na.rm = TRUE))^2, na.rm = TRUE)
r2_2 <- 1 - sum((test$MEDV - pred2)^2, na.rm = TRUE) /
sum((test$MEDV - mean(test$MEDV, na.rm = TRUE))^2, na.rm = TRUE)
# Results table
results <- data.frame(
Model = c("Baseline", "Interaction"),
MAE = c(mae1, mae2),
RMSE = c(rmse1, rmse2),
R_squared = c(r2_1, r2_2)
)
missing_rows <- df[!complete.cases(df), ] # Troubleshooting: View rows with NA values
View(missing_rows)
print(results)
## Model MAE RMSE R_squared
## 1 Baseline 3.869352 5.856873 0.6797927
## 2 Interaction 3.065204 4.778176 0.7868801
# Section 4: Assumption Testing & Influential Observations
# Interaction model
plot(model2, which = 1)

plot(model2, which = 2)

# Heteroscedasticity Assessment: There is no substantial evidence of heteroscedasticity in the observations based on the Residuals vs. Fitted plot. The residuals appear to be relatively evenly distributed around zero across the range of fitted housing values with no pronounced curve or funnel shape. This suggests that the model maintains relatively constant residual variance across predicted housing prices.
# Normality Assessment: Based on the Normal Q-Q Residuals plot, there is evidence that the residuals are not normally distributed. The standardized residuals deviate from the diagonal reference line, particularly toward the higher theoretical quantiles. This suggests that the residuals do not follow a normal distribution.
# Cook's Distance
cooks <- cooks.distance(model2)
plot(cooks,
type = "h",
main = "Cook's Distance",
xlab = "Observation",
ylab = "Cook's Distance")

sort(cooks, decreasing = TRUE)[1:5] # Obtain top 5 Cook Distance observations
## 366 365 371 372 381
## 0.4015849 0.3917210 0.2132627 0.1136842 0.0836675
train[c(366, 365, 371, 372, 381,367), ] # Observe top 5 highest Cook's distance observations
## CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT
## 453 5.09017 0 18.1 0 0.713 6.297 91.8 2.3682 24 666 20.2 385.09 17.27
## 450 7.52601 0 18.1 0 0.713 6.417 98.3 2.1850 24 666 20.2 304.21 19.31
## 460 6.80117 0 18.1 0 0.713 6.081 84.4 2.7175 24 666 20.2 396.90 14.70
## 463 6.65492 0 18.1 0 0.713 6.317 83.0 2.7344 24 666 20.2 396.90 13.99
## 474 4.64689 0 18.1 0 0.614 6.980 67.6 2.5329 24 666 20.2 374.68 NA
## 455 9.51363 0 18.1 0 0.713 6.728 94.1 2.4961 24 666 20.2 6.68 18.71
## MEDV
## 453 16.1
## 450 13.0
## 460 20.0
## 463 19.5
## 474 29.8
## 455 14.9
# Influential Observations: Based on the Cook's Distance graph and further inspection of observations with high influence, I believe that these extreme observations should be retained. There are no apparent errors or discrepancies in the data for these observations, suggesting that they represent legitimate variation within the dataset. Removing these observations could eliminate meaningful information and make the dataset less representative. For example, removing data points with high crime rates would diminish the true trends of factors and housing costs across Boston. Therefore, I recommend retaining these observations in the regression models.
# Section 5: Limitations and Policy Implications
#1. Based on the model coefficients, the results suggest that factors such as nitric oxide concentration and pupil-to-teacher ratios need further investigation. Both variables yielded positive coefficients in the MLR model, indicating that higher NOX concentrations and PTRATIOs are associated with higher predicted housing values, holding other variables constant. As a result, policies targeting areas of Boston with high nitric oxide concentrations and pupil-to-teacher ratios could have potential implications for housing affordability and neighborhood development. For example, expanding educational resources and hiring additional teachers could help address differences in educational opportunities across neighborhoods. Additionally, investing in green spaces and improving environmental quality could improve neighborhood conditions. The MLR Model suggests that these factors are worth possibly investigating further and could be imrpotant to consider by the city planning board for future policies.
#2. The limitations of this model include the fact that the dataset contains a limited number of Boston-area housing observations that may be outdated. With a broader goal of understanding how factors such as urban infrastructure and environmental characteristics affect home prices, the data may be sensitive to Boston-specific factors that are not accounted for by the model and may not represent overall housing market trends. In addition, there are a limited number of explanatory variables included in the linear regression models that could potentially impact model performance. For example, the goal is to investigate how square footage interacts with environmental factors, but the variable used in the model is the average number of rooms per dwelling since there is no explicit square footage measure. As a result, this model does not account for the actual overall size of a home.
# Another limitation is that several potentially significant characteristics that could influence housing prices are not included in the dataset. Factors such as education quality, access to public transportation, and proximity to green spaces, could all contribute to property value. Leaving out these variables may limit the model's ability to fully explain variations in housing prices and could influence the estimated coefficients of the variables that are included. Incorporating these additional characteristics could provide a more comprehensive understanding of the relationship between neighborhood characteristics and housing values. As a result, these omitted variables and dataset-specific constraints could be holding back the model's ability to accurately gauge the impacts of the MLR variables on home prices.