housing <- read.csv("C:/Users/anoos/OneDrive/Desktop/Housing.csv")
str(housing)
## 'data.frame': 545 obs. of 13 variables:
## $ price : int 13300000 12250000 12250000 12215000 11410000 10850000 10150000 10150000 9870000 9800000 ...
## $ area : int 7420 8960 9960 7500 7420 7500 8580 16200 8100 5750 ...
## $ bedrooms : int 4 4 3 4 4 3 4 5 4 3 ...
## $ bathrooms : int 2 4 2 2 1 3 3 3 1 2 ...
## $ stories : int 3 4 2 2 2 1 4 2 2 4 ...
## $ mainroad : chr "yes" "yes" "yes" "yes" ...
## $ guestroom : chr "no" "no" "no" "no" ...
## $ basement : chr "no" "no" "yes" "yes" ...
## $ hotwaterheating : chr "no" "no" "no" "no" ...
## $ airconditioning : chr "yes" "yes" "no" "yes" ...
## $ parking : int 2 3 2 3 2 2 2 0 2 1 ...
## $ prefarea : chr "yes" "no" "yes" "yes" ...
## $ furnishingstatus: chr "furnished" "furnished" "semi-furnished" "furnished" ...
head(housing)
## price area bedrooms bathrooms stories mainroad guestroom basement
## 1 13300000 7420 4 2 3 yes no no
## 2 12250000 8960 4 4 4 yes no no
## 3 12250000 9960 3 2 2 yes no yes
## 4 12215000 7500 4 2 2 yes no yes
## 5 11410000 7420 4 1 2 yes yes yes
## 6 10850000 7500 3 3 1 yes no yes
## hotwaterheating airconditioning parking prefarea furnishingstatus
## 1 no yes 2 yes furnished
## 2 no yes 3 no furnished
## 3 no no 2 yes semi-furnished
## 4 no yes 3 yes furnished
## 5 no yes 2 no furnished
## 6 no yes 2 yes semi-furnished
# 1. Convert all categoricals to factor
housing$mainroad <- as.factor(housing$mainroad)
housing$guestroom <- as.factor(housing$guestroom)
housing$basement <- as.factor(housing$basement)
housing$hotwaterheating <- as.factor(housing$hotwaterheating)
housing$airconditioning <- as.factor(housing$airconditioning)
housing$prefarea <- as.factor(housing$prefarea)
housing$furnishingstatus <- as.factor(housing$furnishingstatus)
str(housing)
## 'data.frame': 545 obs. of 13 variables:
## $ price : int 13300000 12250000 12250000 12215000 11410000 10850000 10150000 10150000 9870000 9800000 ...
## $ area : int 7420 8960 9960 7500 7420 7500 8580 16200 8100 5750 ...
## $ bedrooms : int 4 4 3 4 4 3 4 5 4 3 ...
## $ bathrooms : int 2 4 2 2 1 3 3 3 1 2 ...
## $ stories : int 3 4 2 2 2 1 4 2 2 4 ...
## $ mainroad : Factor w/ 2 levels "no","yes": 2 2 2 2 2 2 2 2 2 2 ...
## $ guestroom : Factor w/ 2 levels "no","yes": 1 1 1 1 2 1 1 1 2 2 ...
## $ basement : Factor w/ 2 levels "no","yes": 1 1 2 2 2 2 1 1 2 1 ...
## $ hotwaterheating : Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
## $ airconditioning : Factor w/ 2 levels "no","yes": 2 2 1 2 2 2 2 1 2 2 ...
## $ parking : int 2 3 2 3 2 2 2 0 2 1 ...
## $ prefarea : Factor w/ 2 levels "no","yes": 2 1 2 2 1 2 2 1 2 2 ...
## $ furnishingstatus: Factor w/ 3 levels "furnished","semi-furnished",..: 1 1 2 1 1 2 2 3 1 3 ...
n <- nrow(housing)
names(housing)
## [1] "price" "area" "bedrooms" "bathrooms"
## [5] "stories" "mainroad" "guestroom" "basement"
## [9] "hotwaterheating" "airconditioning" "parking" "prefarea"
## [13] "furnishingstatus"
library(corrplot)
## corrplot 0.95 loaded
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.6.1
##
## 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
numeric_data <- housing %>% select_if(is.numeric)
categorical_data <- housing %>% select_if(is.factor)
col_col <- c("price" ,"area","bedrooms" ,"bathrooms", "stories" , "parking" )
corrplot(cor(numeric_data), method = "number")
corrplot(cor(housing[,col_col]), method = "number")
covariates1 <- names(categorical_data)
for (var in covariates1) {
boxplot(housing$price ~ categorical_data[[var]] , xlab = var )
}
pairs(numeric_data)
Based on the corrplot, the response variable price shows a strong positive correlation with area and bathrooms. However, the correlation between numerical predictors suggests the presence of multicollinearity.
According to the pairs plot, there is a strong positive correlation between area and price. The observed ‘funnel shape’ indicates heteroscedasticity and right-skewness in the data. There is weak correlation among the other predictors, as evidenced by the vertical clusters. Finally, the boxplots reveal heteroscedasticity, as indicated by the differing medians and unequal variability between ‘yes’ and ‘no’ categories.
model.fit <- lm(price ~ . , data = housing)
summary(model.fit)
##
## Call:
## lm(formula = price ~ ., data = housing)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2619718 -657322 -68409 507176 5166695
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 42771.69 264313.31 0.162 0.871508
## area 244.14 24.29 10.052 < 2e-16 ***
## bedrooms 114787.56 72598.66 1.581 0.114445
## bathrooms 987668.11 103361.98 9.555 < 2e-16 ***
## stories 450848.00 64168.93 7.026 6.55e-12 ***
## mainroadyes 421272.59 142224.13 2.962 0.003193 **
## guestroomyes 300525.86 131710.22 2.282 0.022901 *
## basementyes 350106.90 110284.06 3.175 0.001587 **
## hotwaterheatingyes 855447.15 223152.69 3.833 0.000141 ***
## airconditioningyes 864958.31 108354.51 7.983 8.91e-15 ***
## parking 277107.10 58525.89 4.735 2.82e-06 ***
## prefareayes 651543.80 115682.34 5.632 2.89e-08 ***
## furnishingstatussemi-furnished -46344.62 116574.09 -0.398 0.691118
## furnishingstatusunfurnished -411234.39 126210.56 -3.258 0.001192 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1068000 on 531 degrees of freedom
## Multiple R-squared: 0.6818, Adjusted R-squared: 0.674
## F-statistic: 87.52 on 13 and 531 DF, p-value: < 2.2e-16
library(car)
## Warning: package 'car' was built under R version 4.6.1
## Loading required package: carData
## Warning: package 'carData' was built under R version 4.6.1
##
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
##
## recode
vif(model.fit)
## GVIF Df GVIF^(1/(2*Df))
## area 1.325250 1 1.151195
## bedrooms 1.369477 1 1.170246
## bathrooms 1.286621 1 1.134293
## stories 1.478055 1 1.215753
## mainroad 1.172728 1 1.082926
## guestroom 1.212838 1 1.101289
## basement 1.323050 1 1.150239
## hotwaterheating 1.041506 1 1.020542
## airconditioning 1.211840 1 1.100836
## parking 1.212837 1 1.101289
## prefarea 1.149196 1 1.072006
## furnishingstatus 1.109639 2 1.026350
The linear regression summary confirms that area, bathrooms, and airconditioning are the most influential predictors of price (\(p < 0.001\)). Notably, bedrooms and furnishingstatussemi-furnished were not statistically significant in this model, suggesting they may provide redundant information. The adjusted \(R^2\) of 0.674 indicates a moderate model fit, though the wide range in residuals further corroborates the presence of heteroscedasticity.”To formally assess multicollinearity, Generalized Variance Inflation Factors (GVIF) were calculated. All \(GVIF^{\frac{1}{2 \cdot Df}}\) values were found to be below 1.25, indicating that multicollinearity is not present to a problematic degree. This confirms that the model’s standard errors are not inflated and that the individual coefficient estimates are stable and reliable for interpretation.
# Create the new log-transformed model
model.log <- lm(log(price) ~ ., data = housing)
# Compare the summary
summary(model.log)
##
## Call:
## lm(formula = log(price) ~ ., data = housing)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.60723 -0.12531 0.00631 0.13088 0.63018
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.435e+01 5.115e-02 280.577 < 2e-16 ***
## area 4.949e-05 4.701e-06 10.528 < 2e-16 ***
## bedrooms 2.947e-02 1.405e-02 2.098 0.036411 *
## bathrooms 1.632e-01 2.000e-02 8.159 2.47e-15 ***
## stories 9.013e-02 1.242e-02 7.258 1.41e-12 ***
## mainroadyes 1.175e-01 2.752e-02 4.268 2.34e-05 ***
## guestroomyes 6.979e-02 2.549e-02 2.738 0.006391 **
## basementyes 8.931e-02 2.134e-02 4.185 3.34e-05 ***
## hotwaterheatingyes 1.634e-01 4.319e-02 3.784 0.000172 ***
## airconditioningyes 1.748e-01 2.097e-02 8.336 6.62e-16 ***
## parking 4.477e-02 1.133e-02 3.953 8.77e-05 ***
## prefareayes 1.268e-01 2.239e-02 5.661 2.46e-08 ***
## furnishingstatussemi-furnished 1.797e-02 2.256e-02 0.796 0.426115
## furnishingstatusunfurnished -1.099e-01 2.443e-02 -4.500 8.36e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2067 on 531 degrees of freedom
## Multiple R-squared: 0.699, Adjusted R-squared: 0.6916
## F-statistic: 94.84 on 13 and 531 DF, p-value: < 2.2e-16
# Plot diagnostics to see if the funnel shape is gone
plot(model.log)
The log-transformed regression model provides a more accurate and
interpretable fit, successfully addressing the heteroscedasticity found
in the initial analysis. The model demonstrates that key amenities such
as air conditioning, the number of bathrooms, and the preference area
have the most substantial positive impacts on property value, while the
log-transformation allows these effects to be expressed as intuitive
percentage changes.”“The ‘Residuals vs. Leverage’ plot indicates that
the model is stable. There are no observations exceeding the Cook’s
distance boundaries, which confirms that no single data point is
disproportionately influencing the regression results. While points 24,
140, and 379 represent houses with slightly unusual characteristics or
larger prediction errors, they do not constitute influential outliers
that necessitate removal from the dataset.
mod.red <- update(model.log, ~ . -furnishingstatus)
summary(mod.red)
##
## Call:
## lm(formula = log(price) ~ area + bedrooms + bathrooms + stories +
## mainroad + guestroom + basement + hotwaterheating + airconditioning +
## parking + prefarea, data = housing)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.67787 -0.12197 0.01574 0.12792 0.67737
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.427e+01 4.726e-02 302.057 < 2e-16 ***
## area 5.055e-05 4.855e-06 10.412 < 2e-16 ***
## bedrooms 3.409e-02 1.451e-02 2.349 0.01920 *
## bathrooms 1.684e-01 2.066e-02 8.150 2.60e-15 ***
## stories 9.177e-02 1.284e-02 7.148 2.91e-12 ***
## mainroadyes 1.302e-01 2.835e-02 4.593 5.47e-06 ***
## guestroomyes 7.393e-02 2.634e-02 2.807 0.00519 **
## basementyes 9.948e-02 2.201e-02 4.520 7.63e-06 ***
## hotwaterheatingyes 1.783e-01 4.460e-02 3.997 7.31e-05 ***
## airconditioningyes 1.769e-01 2.159e-02 8.195 1.88e-15 ***
## parking 5.113e-02 1.166e-02 4.386 1.39e-05 ***
## prefareayes 1.276e-01 2.314e-02 5.515 5.45e-08 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2138 on 533 degrees of freedom
## Multiple R-squared: 0.6767, Adjusted R-squared: 0.6701
## F-statistic: 101.4 on 11 and 533 DF, p-value: < 2.2e-16
anova(mod.red, model.log)
## Analysis of Variance Table
##
## Model 1: log(price) ~ area + bedrooms + bathrooms + stories + mainroad +
## guestroom + basement + hotwaterheating + airconditioning +
## parking + prefarea
## Model 2: log(price) ~ area + bedrooms + bathrooms + stories + mainroad +
## guestroom + basement + hotwaterheating + airconditioning +
## parking + prefarea + furnishingstatus
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 533 24.356
## 2 531 22.682 2 1.6738 19.592 6.174e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
To evaluate the importance of the furnishingstatus variable, an Analysis of Variance (ANOVA) was conducted comparing a model excluding this feature against the full model. The resulting F-statistic (\(F(2, 531) = 19.59, p < 0.001\)) indicates that furnishingstatus significantly improves the model’s explanatory power. Therefore, retaining this variable is necessary to minimize residual error and maintain the model’s predictive integrity.
# Instead of using just 'area'
model.poly <- lm(log(price) ~ poly(area, 2) + bedrooms + bathrooms + stories +
mainroad + guestroom + basement + hotwaterheating +
airconditioning + parking + prefarea + furnishingstatus,
data = housing)
# View the results
summary(model.poly)
##
## Call:
## lm(formula = log(price) ~ poly(area, 2) + bedrooms + bathrooms +
## stories + mainroad + guestroom + basement + hotwaterheating +
## airconditioning + parking + prefarea + furnishingstatus,
## data = housing)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.60764 -0.12468 0.00489 0.12529 0.61363
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 14.63185 0.05097 287.067 < 2e-16 ***
## poly(area, 2)1 2.60834 0.23754 10.980 < 2e-16 ***
## poly(area, 2)2 -0.73949 0.21732 -3.403 0.000718 ***
## bedrooms 0.03081 0.01392 2.214 0.027267 *
## bathrooms 0.16205 0.01981 8.180 2.12e-15 ***
## stories 0.08756 0.01232 7.107 3.85e-12 ***
## mainroadyes 0.10340 0.02757 3.751 0.000196 ***
## guestroomyes 0.05440 0.02564 2.122 0.034337 *
## basementyes 0.09172 0.02115 4.337 1.73e-05 ***
## hotwaterheatingyes 0.16485 0.04277 3.855 0.000130 ***
## airconditioningyes 0.16415 0.02100 7.817 2.93e-14 ***
## parking 0.04140 0.01126 3.677 0.000260 ***
## prefareayes 0.12565 0.02217 5.667 2.38e-08 ***
## furnishingstatussemi-furnished 0.01376 0.02237 0.615 0.538931
## furnishingstatusunfurnished -0.11231 0.02420 -4.642 4.36e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2047 on 530 degrees of freedom
## Multiple R-squared: 0.7054, Adjusted R-squared: 0.6976
## F-statistic: 90.65 on 14 and 530 DF, p-value: < 2.2e-16
“To refine the model’s accuracy, a quadratic term for area was introduced using the poly() function. This adjustment proved statistically significant (\(p < 0.001\)), confirming that the relationship between house area and price is non-linear, likely reflecting diminishing marginal returns for larger properties. This model achieves an Adjusted \(R^2\) of 0.6976, representing the most effective and statistically valid fit for the data.”
# Create new data with all variables used in the model
new.data <- data.frame(
area = 17000,
bedrooms = 3, # Typical value
bathrooms = 2, # Typical value
stories = 2, # Typical value
mainroad = factor("yes", levels = levels(housing$mainroad)),
guestroom = factor("no", levels = levels(housing$guestroom)),
basement = factor("no", levels = levels(housing$basement)),
hotwaterheating = factor("no", levels = levels(housing$hotwaterheating)),
airconditioning = factor("yes", levels = levels(housing$airconditioning)),
parking = 1, # Typical value
prefarea = factor("no", levels = levels(housing$prefarea)),
furnishingstatus = factor("furnished", levels = levels(housing$furnishingstatus))
)
# Now the prediction will work
predicted_log_price <- predict(model.poly, newdata = new.data)
# To get the price in actual dollars, use exp()
predicted_price <- exp(predicted_log_price)
predicted_price
## 1
## 6888963
confint <- predict(model.poly, newdata = new.data, interval = "confidence")
confint
## fit lwr upr
## 1 15.74543 15.49901 15.99185
exp(confint)
## fit lwr upr
## 1 6888963 5384358 8814016
pred <- predict(model.poly, newdata = new.data, interval = "prediction")
pred
## fit lwr upr
## 1 15.74543 15.27389 16.21697
exp(pred)
## fit lwr upr
## 1 6888963 4298995 11039282
# Basic scatter plot
plot(housing$area, log(housing$price),
main = "Model Fit: Area vs. Log(Price)",
xlab = "Area", ylab = "Log(Price)",
col = "gray", pch = 16)
# Predict across the range of your data
x_range <- seq(min(housing$area), max(housing$area), length.out = 100)
# We use the median of other variables for a "typical" house
line_pred <- predict(model.poly, newdata = data.frame(
area = x_range, bedrooms = median(housing$bedrooms),
bathrooms = median(housing$bathrooms), stories = median(housing$stories),
mainroad = "yes", guestroom = "no", basement = "no",
hotwaterheating = "no", airconditioning = "yes",
parking = median(housing$parking), prefarea = "no",
furnishingstatus = "furnished"))
# Draw the blue line
lines(x_range, line_pred, col = "blue", lwd = 3)
plot(model.poly)
prediction interval is always wider then the confidence interval . This is because a confidence interval only reflects the uncertainty in estimating the average price (reflects the uncertainty in the parameter estimators) for a given housing charateristics. A prediction interval, however, must also account for the random variability (the error term) of a single, specific new observation around that average.
“The ‘Residuals vs. Leverage’ diagnostic plot for the refined quadratic model confirms overall model stability. While observation #8 exhibits high leverage due to its unique characteristics,You still do not see the faint, curved dashed lines (Cook’s distance boundaries) encompassing any of your points. it remains well within the Cook’s distance boundaries. This indicates that no single observation is exerting undue influence on the model’s coefficients, and the results remain robust.” In your housing model, the fact that you did not see these curved lines (or rather, that all your points remained within the boundaries) is a strong indicator of model stability. It confirms that your findings are based on the overall trend of the housing data, rather than being skewed by a few extreme or erroneous observations.If you ever see a plot
where points are outside these lines, it means those specific observations (e.g., a specific house in your dataset) have a disproportionate impact on your model results compared to the rest of the data.
an <- aov(price ~ furnishingstatus, data = housing)
summary(an)
## Df Sum Sq Mean Sq F value Pr(>F)
## furnishingstatus 2 1.798e+14 8.99e+13 28.27 2.09e-12 ***
## Residuals 542 1.723e+15 3.18e+12
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
tukeyf <- TukeyHSD(an)
plot(tukeyf)
“An ANOVA test confirmed that furnishingstatus is a significant
predictor of housing prices (\(F(2, 542) =
28.27, p < 0.001\)). Subsequent Tukey post-hoc analysis
revealed significant differences between all pairs of furnishing
categories. Specifically, prices decrease progressively from fully
furnished to semi-furnished, and finally to unfurnished, with all
pairwise differences being statistically significant.”
The Goal: This test determines if the average price of houses is significantly different across the three categories of furnishingstatus (furnished, semi-furnished, unfurnished).
F-value (28.27): This is high, indicating that the variation between the groups is much larger than the variation within the groups.
Pr(>F) (2.09e-12): Since this is significantly less than 0.05, we conclude that furnishing status has a statistically significant impact on house price.
model.glm <- glm(price ~ poly(area, 2) + bedrooms + bathrooms + stories +
mainroad + guestroom + basement + hotwaterheating +
airconditioning + parking + prefarea + furnishingstatus,
data = housing, family = Gamma(link = "log"))
summary(model.glm)
##
## Call:
## glm(formula = price ~ poly(area, 2) + bedrooms + bathrooms +
## stories + mainroad + guestroom + basement + hotwaterheating +
## airconditioning + parking + prefarea + furnishingstatus,
## family = Gamma(link = "log"), data = housing)
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 14.63419 0.05115 286.102 < 2e-16 ***
## poly(area, 2)1 2.63119 0.23838 11.038 < 2e-16 ***
## poly(area, 2)2 -0.70867 0.21809 -3.249 0.001230 **
## bedrooms 0.03558 0.01397 2.547 0.011133 *
## bathrooms 0.15954 0.01988 8.025 6.59e-15 ***
## stories 0.08830 0.01236 7.142 3.05e-12 ***
## mainroadyes 0.10634 0.02766 3.844 0.000136 ***
## guestroomyes 0.05622 0.02573 2.185 0.029346 *
## basementyes 0.09583 0.02122 4.516 7.78e-06 ***
## hotwaterheatingyes 0.17266 0.04292 4.023 6.58e-05 ***
## airconditioningyes 0.15978 0.02107 7.582 1.53e-13 ***
## parking 0.04610 0.01130 4.080 5.21e-05 ***
## prefareayes 0.11528 0.02225 5.181 3.14e-07 ***
## furnishingstatussemi-furnished 0.01254 0.02245 0.559 0.576637
## furnishingstatusunfurnished -0.10591 0.02428 -4.362 1.55e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for Gamma family taken to be 0.04217857)
##
## Null deviance: 76.501 on 544 degrees of freedom
## Residual deviance: 22.091 on 530 degrees of freedom
## AIC: 16520
##
## Number of Fisher Scoring iterations: 5
“The coefficients represent the effect of each predictor on the natural log of the house price. For example, the airconditioning variable has a coefficient of 0.16, indicating a positive contribution to the log-price, while furnishingstatusunfurnished has a coefficient of -0.10, indicating a negative impact on the log-price, holding other factors constant.”
par(mfrow = c(2,2))
plot(model.glm)
par(mfrow = c(1,1))
“Diagnostic analysis of the Gamma GLM confirms the model’s validity and robustness. The Residuals vs. Fitted and Scale-Location plots demonstrate consistent variance, confirming the absence of heteroscedasticity. The Q-Q Residuals plot indicates that the model errors align well with the theoretical Gamma distribution, and the Residuals vs. Leverage plot confirms that no single observation exerts undue influence on the model’s coefficients (all Cook’s distances < 0.5). Consequently, the model is considered highly reliable for predictive purposes
# 1. Create a sequence of area values (as you did)
xp <- seq(min(housing$area), max(housing$area), length = 100)
# 2. Create the data frame with ALL variables
new <- data.frame(
area = xp,
bedrooms = median(housing$bedrooms),
bathrooms = median(housing$bathrooms),
stories = median(housing$stories),
mainroad = factor("yes", levels = levels(housing$mainroad)),
guestroom = factor("no", levels = levels(housing$guestroom)),
basement = factor("no", levels = levels(housing$basement)),
hotwaterheating = factor("no", levels = levels(housing$hotwaterheating)),
airconditioning = factor("yes", levels = levels(housing$airconditioning)),
parking = median(housing$parking),
prefarea = factor("no", levels = levels(housing$prefarea)),
furnishingstatus = factor("furnished", levels = levels(housing$furnishingstatus))
)
# 3. Predict using 'type = "response"'
# This gives you the predicted price directly in currency (not log scale)
predictions <- predict(model.glm, newdata = new, type = "response")
# 4. Plot the result
plot(housing$area, housing$price, col = "gray", pch = 16,
xlab = "Area", ylab = "Price", main = "Gamma GLM Predicted Price Curve")
lines(xp, predictions, col = "red", lwd = 3)
# 1. Create a sequence for the variable you want to explore
# Since bathrooms are discrete numbers, we use unique values instead of seq()
bath_levels <- sort(unique(housing$bathrooms))
# 2. Create the data frame, keeping area and others at their median
new_bath <- data.frame(
area = median(housing$area),
bedrooms = median(housing$bedrooms),
bathrooms = bath_levels, # This is the variable we are exploring
stories = median(housing$stories),
mainroad = factor("yes", levels = levels(housing$mainroad)),
guestroom = factor("no", levels = levels(housing$guestroom)),
basement = factor("no", levels = levels(housing$basement)),
hotwaterheating = factor("no", levels = levels(housing$hotwaterheating)),
airconditioning = factor("yes", levels = levels(housing$airconditioning)),
parking = median(housing$parking),
prefarea = factor("no", levels = levels(housing$prefarea)),
furnishingstatus = factor("furnished", levels = levels(housing$furnishingstatus))
)
# 3. Predict and Plot
predictions_bath <- predict(model.glm, newdata = new_bath, type = "response")
plot(new_bath$bathrooms, predictions_bath, type = "b", pch = 19, col = "blue",
xlab = "Number of Bathrooms", ylab = "Predicted Price",
main = "Effect of Bathrooms on Predicted Price")
# Poisson regression for count data
model.poisson <- glm(bedrooms ~ area + stories,
data = housing,
family = poisson(link = "log"))
# Check for overdispersion
summary(model.poisson)
##
## Call:
## glm(formula = bedrooms ~ area + stories, family = poisson(link = "log"),
## data = housing)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 8.198e-01 7.876e-02 10.409 < 2e-16 ***
## area 1.301e-05 1.140e-05 1.142 0.254
## stories 1.079e-01 2.735e-02 3.947 7.91e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 99.167 on 544 degrees of freedom
## Residual deviance: 81.770 on 542 degrees of freedom
## AIC: 1697.2
##
## Number of Fisher Scoring iterations: 4
“The model goodness-of-fit was assessed by comparing the residual deviance to the degrees of freedom. With a residual deviance of 81.77 on 542 degrees of freedom, the ratio is approximately 0.15. This suggests the model captures the data structure well, though the low ratio indicates potential underdispersion, which confirms the model is not over-estimating the variability of the bedroom counts.”
# Poisson regression for count data
ad.poisson <- glm(bedrooms ~ area + stories + bathrooms,
data = housing,
family = poisson(link = "log"))
# Check for overdispersion
summary(ad.poisson)
##
## Call:
## glm(formula = bedrooms ~ area + stories + bathrooms, family = poisson(link = "log"),
## data = housing)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 7.331e-01 8.700e-02 8.426 < 2e-16 ***
## area 8.017e-06 1.164e-05 0.689 0.49092
## stories 8.623e-02 2.900e-02 2.973 0.00295 **
## bathrooms 1.168e-01 5.039e-02 2.317 0.02049 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 99.167 on 544 degrees of freedom
## Residual deviance: 76.531 on 541 degrees of freedom
## AIC: 1693.9
##
## Number of Fisher Scoring iterations: 4
peaser_chi <- residuals(ad.poisson, type = "pearson")
phi <- sum((peaser_chi)^2)/ad.poisson$df.residual
phi
## [1] 0.1444885
lambdahat <- fitted(ad.poisson)
plot(lambdahat, peaser_chi,
xlab = expression(hat(lambda)), ylab = "Pearson Residuals",
main = "Mean vs. Pearson Residuals")
abline(h = 0, lty = 2)
A dispersion check was conducted on the Poisson regression model, yielding a dispersion parameter (\(\phi\)) of 0.144. This indicates the presence of underdispersion, likely due to the restricted range of the bedroom count variable. To ensure robust statistical inference, a Quasipoisson model was subsequently employed to adjust standard errors. The results confirm that the significance of stories and bathrooms persists under this conservative estimation, validating the findings.
“Diagnostic analysis of Pearson residuals vs. predicted means revealed distinct diagonal banding, a characteristic pattern indicating that the Poisson model is failing to account for the discrete, ordinal nature of the bedrooms variable. Given that the count range is tightly constrained and follows an ordered hierarchy, an Ordinal Logistic Regression approach is more appropriate. This method respects the ranking of bedroom counts and avoids the distributional assumptions of the Poisson model, which were not met by the observed data.”
validation set approach
n <- nrow(housing)
Train <- sample(1:n, 0.5 * n )
Train_house <- housing[Train,]
Test <- housing[-Train, ]
lm_fit <- lm(price ~ area, data = Train_house)
summary(lm_fit)
##
## Call:
## lm(formula = price ~ area, data = Train_house)
##
## Residuals:
## Min 1Q Median 3Q Max
## -4973015 -1029597 -305765 739996 6323038
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.336e+06 2.636e+05 8.863 <2e-16 ***
## area 4.741e+02 4.693e+01 10.104 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1639000 on 270 degrees of freedom
## Multiple R-squared: 0.2744, Adjusted R-squared: 0.2717
## F-statistic: 102.1 on 1 and 270 DF, p-value: < 2.2e-16
pred_val <- predict(lm_fit , newdata = Test)
mse <- mean((Test$price - pred_val )^2)
mse
## [1] 2.312563e+12
po_fit <- lm(price ~ poly(area,degree = 2), data = Train_house)
summary(po_fit)
##
## Call:
## lm(formula = price ~ poly(area, degree = 2), data = Train_house)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3736278 -1057860 -260657 785636 6089390
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4802617 96734 49.648 < 2e-16 ***
## poly(area, degree = 2)1 16562472 1595371 10.382 < 2e-16 ***
## poly(area, degree = 2)2 -6394179 1595371 -4.008 7.94e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1595000 on 269 degrees of freedom
## Multiple R-squared: 0.3152, Adjusted R-squared: 0.3102
## F-statistic: 61.92 on 2 and 269 DF, p-value: < 2.2e-16
pred_val_po <- predict(po_fit , newdata = Test)
mse_po <- mean((Test$price - pred_val_po)^2)
mse_po
## [1] 2.262949e+12
po3_fit <- lm(price ~ poly(area,degree = 3), data = Train_house)
summary(po3_fit)
##
## Call:
## lm(formula = price ~ poly(area, degree = 3), data = Train_house)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3901932 -995963 -230368 832135 5948878
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4802617 96369 49.836 < 2e-16 ***
## poly(area, degree = 3)1 16562472 1589358 10.421 < 2e-16 ***
## poly(area, degree = 3)2 -6394179 1589358 -4.023 7.48e-05 ***
## poly(area, degree = 3)3 -2770883 1589358 -1.743 0.0824 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1589000 on 268 degrees of freedom
## Multiple R-squared: 0.3229, Adjusted R-squared: 0.3153
## F-statistic: 42.61 on 3 and 268 DF, p-value: < 2.2e-16
pred_val_po3 <- predict(po3_fit , newdata = Test)
mse_po3 <- mean((Test$price - pred_val_po3)^2)
mse_po3
## [1] 2.722392e+12
In housing data, while larger homes generally cost more, the relationship is rarely perfectly linear. However, higher-order polynomials (like degree 3 or 4) are notorious for becoming unstable at the edges of your data range (the “tails” of your area distribution). By choosing the degree 2 model, you have successfully identified the model that best balances capturing the trend without introducing unnecessary complexity.
LOOCV
library(boot)
##
## Attaching package: 'boot'
## The following object is masked from 'package:car':
##
## logit
glm_fit <- glm(price ~ area, data = housing)
cv.error <- cv.glm(housing, glm_fit)
cv.error$delta
## [1] 2.513734e+12 2.513711e+12
cv.error1 <- rep(0,10)
for ( i in 1:10){
glm_fit_i <- glm(price ~ poly(area, degree = i ) , data = housing)
cv.error1[i] <- cv.glm(housing, glm_fit_i)$delta[1]
}
cv.error1
## [1] 2.513734e+12 2.414752e+12 2.441341e+12 2.342341e+12 2.379141e+12
## [6] 2.459825e+12 2.416350e+12 2.727776e+12 4.053577e+12 5.473217e+13
K FOLD CROSS VALIDATION
library(boot)
cv.error2 <- rep(0,10)
for ( i in 1:10){
glm_fit_2 <- glm(price ~ poly(area, degree = i ) , data = housing)
cv.error2[i] <- cv.glm(housing, glm_fit_2, K =10 )$delta[1]
}
cv.error2
## [1] 2.518716e+12 2.420287e+12 2.483398e+12 2.333778e+12 2.385050e+12
## [6] 2.496823e+12 2.409573e+12 2.708670e+12 3.848721e+12 1.105725e+13
Looking at both your LOOCV and 10-Fold results, Degree 4 consistently provides the lowest error.Degrees 1–3: The model is “learning” the trend, and error drops as the model gains the flexibility to follow the curve of the data.Degree 4 (The Sweet Spot): This is where the model is complex enough to capture the true underlying pattern but hasn’t yet started to “over-memorize” the random noise.Degrees 5–10: You notice the error begins to increase (especially drastically by degree 8, 9, and 10). This is a classic indicator of overfitting. The model has become so flexible that it is now “fitting the noise” rather than the trend, causing its performance on unseen data to degrade significantly.3. Comparing Validation MethodsLOOCV vs. 10-Fold: You’ll notice the values are quite similar, which gives you high confidence in the result.Stability: 10-Fold CV is generally preferred over LOOCV because it is computationally faster and often provides a more stable estimate of the test error by reducing the correlation between the training folds.The “Explosion” of Error: The massive jump in error at Degree 10 (\(5.47 \times 10^{13}\)) is a classic example of why you should never use high-degree polynomials without regularization. They become highly erratic at the boundaries of your area variable, leading to massive prediction errors for houses that are very small or very large.SummaryYour systematic testing proves that while area is a strong predictor, the relationship is non-linear. You should choose the Degree 4 model for the best predictive performance on new data.
dim(housing)
## [1] 545 13
sum(is.na(housing))
## [1] 0
housing <- na.omit(housing)
library(leaps)
## Warning: package 'leaps' was built under R version 4.6.1
subset_sel <- regsubsets( price ~ . , housing)
reg_sub <- summary(subset_sel)
reg_sub
## Subset selection object
## Call: regsubsets.formula(price ~ ., housing)
## 13 Variables (and intercept)
## Forced in Forced out
## area FALSE FALSE
## bedrooms FALSE FALSE
## bathrooms FALSE FALSE
## stories FALSE FALSE
## mainroadyes FALSE FALSE
## guestroomyes FALSE FALSE
## basementyes FALSE FALSE
## hotwaterheatingyes FALSE FALSE
## airconditioningyes FALSE FALSE
## parking FALSE FALSE
## prefareayes FALSE FALSE
## furnishingstatussemi-furnished FALSE FALSE
## furnishingstatusunfurnished FALSE FALSE
## 1 subsets of each size up to 8
## Selection Algorithm: exhaustive
## area bedrooms bathrooms stories mainroadyes guestroomyes basementyes
## 1 ( 1 ) "*" " " " " " " " " " " " "
## 2 ( 1 ) "*" " " "*" " " " " " " " "
## 3 ( 1 ) "*" " " "*" " " " " " " " "
## 4 ( 1 ) "*" " " "*" "*" " " " " " "
## 5 ( 1 ) "*" " " "*" "*" " " " " " "
## 6 ( 1 ) "*" " " "*" "*" " " " " " "
## 7 ( 1 ) "*" " " "*" "*" " " " " "*"
## 8 ( 1 ) "*" " " "*" "*" " " " " "*"
## hotwaterheatingyes airconditioningyes parking prefareayes
## 1 ( 1 ) " " " " " " " "
## 2 ( 1 ) " " " " " " " "
## 3 ( 1 ) " " "*" " " " "
## 4 ( 1 ) " " "*" " " " "
## 5 ( 1 ) " " "*" " " "*"
## 6 ( 1 ) " " "*" "*" "*"
## 7 ( 1 ) " " "*" "*" "*"
## 8 ( 1 ) " " "*" "*" "*"
## furnishingstatussemi-furnished furnishingstatusunfurnished
## 1 ( 1 ) " " " "
## 2 ( 1 ) " " " "
## 3 ( 1 ) " " " "
## 4 ( 1 ) " " " "
## 5 ( 1 ) " " " "
## 6 ( 1 ) " " " "
## 7 ( 1 ) " " " "
## 8 ( 1 ) " " "*"
subset_full <- regsubsets( price ~ . , housing, nvmax = 13)
reg_sub_full <- summary(subset_full)
reg_sub_full$adjr2
## [1] 0.2859806 0.4631117 0.5421602 0.5784222 0.6113350 0.6325451 0.6475058
## [8] 0.6584091 0.6666483 0.6711105 0.6736184 0.6745276 0.6740117
reg_sub_full$cp
## [1] 648.34486 353.65001 222.81663 163.34417 109.63175 75.43509 51.66305
## [8] 34.65430 22.08445 15.75246 12.64309 12.15805 14.00000
reg_sub_full$bic
## [1] -171.9818 -322.0760 -403.5843 -443.2624 -482.2731 -507.5682 -524.9351
## [8] -536.7742 -544.7978 -546.8612 -545.7537 -541.9967 -535.8581
plot(reg_sub_full$adjr2 , xlab = "Number of variables", ylab = "adj R^2", type = "b")
adj_max <- which.max(reg_sub_full$adjr2)
points( adj_max ,reg_sub_full$adjr2[adj_max], pch = 20, col = "red")
plot(reg_sub_full$bic , xlab = "Number of variables", ylab = "bic", type = "b")
bic_min <- which.min(reg_sub_full$bic)
points( bic_min ,reg_sub_full$bic[ bic_min], pch = 20, col = "red" )
plot(reg_sub_full$cp , xlab = "Number of variables", ylab = "cp", type = "b")
cp_min <- which.min(reg_sub_full$cp)
points( cp_min ,reg_sub_full$cp[ cp_min], pch = 20, col = "red" )
plot(subset_full , scale = "bic")
coef(subset_full , 10)
## (Intercept) area
## 196289.1411 252.1058
## bathrooms stories
## 1034173.9440 494356.1424
## mainroadyes basementyes
## 406815.3534 459481.4981
## hotwaterheatingyes airconditioningyes
## 859533.5760 885120.3631
## parking prefareayes
## 277731.5878 667628.2774
## furnishingstatusunfurnished
## -396086.1661
subset_frd <- regsubsets( price ~ . , housing, method = "forward", nvmax = 13)
reg_frd <- summary(subset_frd)
reg_frd
## Subset selection object
## Call: regsubsets.formula(price ~ ., housing, method = "forward", nvmax = 13)
## 13 Variables (and intercept)
## Forced in Forced out
## area FALSE FALSE
## bedrooms FALSE FALSE
## bathrooms FALSE FALSE
## stories FALSE FALSE
## mainroadyes FALSE FALSE
## guestroomyes FALSE FALSE
## basementyes FALSE FALSE
## hotwaterheatingyes FALSE FALSE
## airconditioningyes FALSE FALSE
## parking FALSE FALSE
## prefareayes FALSE FALSE
## furnishingstatussemi-furnished FALSE FALSE
## furnishingstatusunfurnished FALSE FALSE
## 1 subsets of each size up to 13
## Selection Algorithm: forward
## area bedrooms bathrooms stories mainroadyes guestroomyes basementyes
## 1 ( 1 ) "*" " " " " " " " " " " " "
## 2 ( 1 ) "*" " " "*" " " " " " " " "
## 3 ( 1 ) "*" " " "*" " " " " " " " "
## 4 ( 1 ) "*" " " "*" "*" " " " " " "
## 5 ( 1 ) "*" " " "*" "*" " " " " " "
## 6 ( 1 ) "*" " " "*" "*" " " " " " "
## 7 ( 1 ) "*" " " "*" "*" " " " " "*"
## 8 ( 1 ) "*" " " "*" "*" " " " " "*"
## 9 ( 1 ) "*" " " "*" "*" " " " " "*"
## 10 ( 1 ) "*" " " "*" "*" "*" " " "*"
## 11 ( 1 ) "*" " " "*" "*" "*" "*" "*"
## 12 ( 1 ) "*" "*" "*" "*" "*" "*" "*"
## 13 ( 1 ) "*" "*" "*" "*" "*" "*" "*"
## hotwaterheatingyes airconditioningyes parking prefareayes
## 1 ( 1 ) " " " " " " " "
## 2 ( 1 ) " " " " " " " "
## 3 ( 1 ) " " "*" " " " "
## 4 ( 1 ) " " "*" " " " "
## 5 ( 1 ) " " "*" " " "*"
## 6 ( 1 ) " " "*" "*" "*"
## 7 ( 1 ) " " "*" "*" "*"
## 8 ( 1 ) " " "*" "*" "*"
## 9 ( 1 ) "*" "*" "*" "*"
## 10 ( 1 ) "*" "*" "*" "*"
## 11 ( 1 ) "*" "*" "*" "*"
## 12 ( 1 ) "*" "*" "*" "*"
## 13 ( 1 ) "*" "*" "*" "*"
## furnishingstatussemi-furnished furnishingstatusunfurnished
## 1 ( 1 ) " " " "
## 2 ( 1 ) " " " "
## 3 ( 1 ) " " " "
## 4 ( 1 ) " " " "
## 5 ( 1 ) " " " "
## 6 ( 1 ) " " " "
## 7 ( 1 ) " " " "
## 8 ( 1 ) " " "*"
## 9 ( 1 ) " " "*"
## 10 ( 1 ) " " "*"
## 11 ( 1 ) " " "*"
## 12 ( 1 ) " " "*"
## 13 ( 1 ) "*" "*"
coef(subset_frd , 10)
## (Intercept) area
## 196289.1411 252.1058
## bathrooms stories
## 1034173.9440 494356.1424
## mainroadyes basementyes
## 406815.3534 459481.4981
## hotwaterheatingyes airconditioningyes
## 859533.5760 885120.3631
## parking prefareayes
## 277731.5878 667628.2774
## furnishingstatusunfurnished
## -396086.1661
subset_back <- regsubsets( price ~ . , housing, method = "backward", nvmax = 13)
reg_back <- summary(subset_back)
reg_back
## Subset selection object
## Call: regsubsets.formula(price ~ ., housing, method = "backward", nvmax = 13)
## 13 Variables (and intercept)
## Forced in Forced out
## area FALSE FALSE
## bedrooms FALSE FALSE
## bathrooms FALSE FALSE
## stories FALSE FALSE
## mainroadyes FALSE FALSE
## guestroomyes FALSE FALSE
## basementyes FALSE FALSE
## hotwaterheatingyes FALSE FALSE
## airconditioningyes FALSE FALSE
## parking FALSE FALSE
## prefareayes FALSE FALSE
## furnishingstatussemi-furnished FALSE FALSE
## furnishingstatusunfurnished FALSE FALSE
## 1 subsets of each size up to 13
## Selection Algorithm: backward
## area bedrooms bathrooms stories mainroadyes guestroomyes basementyes
## 1 ( 1 ) "*" " " " " " " " " " " " "
## 2 ( 1 ) "*" " " "*" " " " " " " " "
## 3 ( 1 ) "*" " " "*" " " " " " " " "
## 4 ( 1 ) "*" " " "*" "*" " " " " " "
## 5 ( 1 ) "*" " " "*" "*" " " " " " "
## 6 ( 1 ) "*" " " "*" "*" " " " " " "
## 7 ( 1 ) "*" " " "*" "*" " " " " "*"
## 8 ( 1 ) "*" " " "*" "*" " " " " "*"
## 9 ( 1 ) "*" " " "*" "*" " " " " "*"
## 10 ( 1 ) "*" " " "*" "*" "*" " " "*"
## 11 ( 1 ) "*" " " "*" "*" "*" "*" "*"
## 12 ( 1 ) "*" "*" "*" "*" "*" "*" "*"
## 13 ( 1 ) "*" "*" "*" "*" "*" "*" "*"
## hotwaterheatingyes airconditioningyes parking prefareayes
## 1 ( 1 ) " " " " " " " "
## 2 ( 1 ) " " " " " " " "
## 3 ( 1 ) " " "*" " " " "
## 4 ( 1 ) " " "*" " " " "
## 5 ( 1 ) " " "*" " " "*"
## 6 ( 1 ) " " "*" "*" "*"
## 7 ( 1 ) " " "*" "*" "*"
## 8 ( 1 ) " " "*" "*" "*"
## 9 ( 1 ) "*" "*" "*" "*"
## 10 ( 1 ) "*" "*" "*" "*"
## 11 ( 1 ) "*" "*" "*" "*"
## 12 ( 1 ) "*" "*" "*" "*"
## 13 ( 1 ) "*" "*" "*" "*"
## furnishingstatussemi-furnished furnishingstatusunfurnished
## 1 ( 1 ) " " " "
## 2 ( 1 ) " " " "
## 3 ( 1 ) " " " "
## 4 ( 1 ) " " " "
## 5 ( 1 ) " " " "
## 6 ( 1 ) " " " "
## 7 ( 1 ) " " " "
## 8 ( 1 ) " " "*"
## 9 ( 1 ) " " "*"
## 10 ( 1 ) " " "*"
## 11 ( 1 ) " " "*"
## 12 ( 1 ) " " "*"
## 13 ( 1 ) "*" "*"
coef(subset_back, 10)
## (Intercept) area
## 196289.1411 252.1058
## bathrooms stories
## 1034173.9440 494356.1424
## mainroadyes basementyes
## 406815.3534 459481.4981
## hotwaterheatingyes airconditioningyes
## 859533.5760 885120.3631
## parking prefareayes
## 277731.5878 667628.2774
## furnishingstatusunfurnished
## -396086.1661
validation set approach
set.seed(1)
Train_vali <- sample(c(TRUE,FALSE),nrow(housing), replace = TRUE)
Test <- (!Train_vali)
subset_sel <- regsubsets( price ~ . , housing[Train_vali, ], nvmax = 13)
reg_sub <- summary(subset_sel)
reg_sub
## Subset selection object
## Call: regsubsets.formula(price ~ ., housing[Train_vali, ], nvmax = 13)
## 13 Variables (and intercept)
## Forced in Forced out
## area FALSE FALSE
## bedrooms FALSE FALSE
## bathrooms FALSE FALSE
## stories FALSE FALSE
## mainroadyes FALSE FALSE
## guestroomyes FALSE FALSE
## basementyes FALSE FALSE
## hotwaterheatingyes FALSE FALSE
## airconditioningyes FALSE FALSE
## parking FALSE FALSE
## prefareayes FALSE FALSE
## furnishingstatussemi-furnished FALSE FALSE
## furnishingstatusunfurnished FALSE FALSE
## 1 subsets of each size up to 13
## Selection Algorithm: exhaustive
## area bedrooms bathrooms stories mainroadyes guestroomyes basementyes
## 1 ( 1 ) "*" " " " " " " " " " " " "
## 2 ( 1 ) "*" " " "*" " " " " " " " "
## 3 ( 1 ) "*" " " "*" " " " " " " " "
## 4 ( 1 ) "*" " " "*" " " " " " " " "
## 5 ( 1 ) "*" " " "*" " " " " " " " "
## 6 ( 1 ) "*" " " "*" "*" " " " " " "
## 7 ( 1 ) "*" " " "*" "*" " " " " " "
## 8 ( 1 ) "*" " " "*" "*" " " " " "*"
## 9 ( 1 ) "*" " " "*" "*" " " " " "*"
## 10 ( 1 ) "*" " " "*" "*" "*" " " "*"
## 11 ( 1 ) "*" " " "*" "*" "*" "*" "*"
## 12 ( 1 ) "*" "*" "*" "*" "*" "*" "*"
## 13 ( 1 ) "*" "*" "*" "*" "*" "*" "*"
## hotwaterheatingyes airconditioningyes parking prefareayes
## 1 ( 1 ) " " " " " " " "
## 2 ( 1 ) " " " " " " " "
## 3 ( 1 ) " " "*" " " " "
## 4 ( 1 ) " " "*" " " "*"
## 5 ( 1 ) "*" "*" " " "*"
## 6 ( 1 ) "*" "*" " " "*"
## 7 ( 1 ) "*" "*" "*" "*"
## 8 ( 1 ) "*" "*" "*" "*"
## 9 ( 1 ) "*" "*" "*" "*"
## 10 ( 1 ) "*" "*" "*" "*"
## 11 ( 1 ) "*" "*" "*" "*"
## 12 ( 1 ) "*" "*" "*" "*"
## 13 ( 1 ) "*" "*" "*" "*"
## furnishingstatussemi-furnished furnishingstatusunfurnished
## 1 ( 1 ) " " " "
## 2 ( 1 ) " " " "
## 3 ( 1 ) " " " "
## 4 ( 1 ) " " " "
## 5 ( 1 ) " " " "
## 6 ( 1 ) " " " "
## 7 ( 1 ) " " " "
## 8 ( 1 ) " " " "
## 9 ( 1 ) " " "*"
## 10 ( 1 ) " " "*"
## 11 ( 1 ) " " "*"
## 12 ( 1 ) " " "*"
## 13 ( 1 ) "*" "*"
test_mat <- model.matrix( price ~ . , data = housing[Test, ])
val.error <- rep(NA,13)
for (i in 1:13) {
coefi <- coef(subset_sel, id = i)
pred <- test_mat[, names(coefi)] %*% coefi
val.error[i] <- mean((housing$price[Test] - pred)^2)
}
val.error
## [1] 2.413849e+12 1.847891e+12 1.621165e+12 1.491646e+12 1.509419e+12
## [6] 1.360067e+12 1.280644e+12 1.234845e+12 1.192712e+12 1.165999e+12
## [11] 1.154399e+12 1.144285e+12 1.144419e+12
which.min(val.error)
## [1] 12
coef(subset_sel, 12)
## (Intercept) area
## -116551.1318 288.7282
## bedrooms bathrooms
## 66600.0462 1162193.3081
## stories mainroadyes
## 398279.9102 334143.9382
## guestroomyes basementyes
## 294706.3624 403769.7360
## hotwaterheatingyes airconditioningyes
## 1056406.7197 1003416.7058
## parking prefareayes
## 312384.1860 622521.3793
## furnishingstatusunfurnished
## -335493.6186
predict.regsubsets <- function(object, newdata, id, ...) {
# Fix: Extract formula from the 'call' attribute
form <- as.formula(object$call[[2]])
# Create the model matrix
mat <- model.matrix(form, newdata)
# Get coefficients for the chosen subset size (id)
coefi <- coef(object, id = id)
# Get the names of the coefficients
xvar <- names(coefi)
# Perform matrix multiplication to get predictions
mat[, xvar] %*% coefi
}
set.seed(2)
k = 10
n <- nrow(housing)
folds <- sample(rep(1:k , length = n))
cv.error3 <- matrix(NA, k, 13, dimnames = list(NULL, paste(1:13)))
for (j in 1:k){
best.fit <- regsubsets( price ~ . ,housing[folds != j, ], nvmax = 13)
for (i in 1:13 ) {
pred <- predict(best.fit, housing[folds == j, ] , id = i)
cv.error3[j, i] <- mean((housing$price[folds == j] - pred)^2)
}
}
mean.cv.error3 <- apply(cv.error3,2, mean)
mean.cv.error3
## 1 2 3 4 5 6
## 2.593896e+12 1.894128e+12 1.616311e+12 1.535269e+12 1.375187e+12 1.319692e+12
## 7 8 9 10 11 12
## 1.297249e+12 1.268441e+12 1.215801e+12 1.193985e+12 1.183862e+12 1.175012e+12
## 13
## 1.182018e+12
which.min(mean.cv.error3)
## 12
## 12