La regressione lineare è un metodo statistico utilizzato per modellare la relazione tra una variabile dipendente \(y\) e una o più variabili indipendenti \(x\). L’equazione della regressione lineare semplice è:
\[ y = \beta_0 + \beta_1 x + \varepsilon \]
dove:
- \(y\) è la variabile dipendente
(output o risposta).
- \(x\) è la variabile indipendente
(predittore o input).
- \(\beta_0\) è l’intercetta, cioè il
valore di \(y\) quando \(x = 0\).
- \(\beta_1\) è il coefficiente di
regressione, che rappresenta la variazione attesa di \(y\) per un’unità di incremento in \(x\).
- \(\varepsilon\) è l’errore residuo,
che rappresenta la parte di \(y\) non
spiegata dal modello.
Affinché un modello di regressione lineare sia valido e fornisca inferenze affidabili, deve rispettare alcune ipotesi fondamentali. Queste ipotesi sono alla base del modello statistico e dell’interpretazione dei risultati.
La relazione tra la variabile dipendente \(y\) e le variabili indipendenti \(x_1, x_2, ..., x_n\) deve essere lineare. Questo significa che il modello assume la forma:
\[ y = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + ... + \beta_n x_n + \varepsilon \]
Se la relazione non è lineare, il modello può essere inadeguato e potrebbero essere necessarie trasformazioni delle variabili.
Gli errori (\(\varepsilon\)) devono essere indipendenti tra loro. In altre parole, non devono esserci correlazioni sistematiche tra gli errori associati a diverse osservazioni.
Gli errori devono seguire una distribuzione normale con media zero:
\[ \varepsilon \sim N(0, \sigma^2) \]
Questa ipotesi è importante per l’inferenza statistica, in particolare per i test di significatività dei coefficienti (\(p\)-value) e la costruzione di intervalli di confidenza.
La varianza degli errori deve essere costante lungo tutti i valori della variabile indipendente:
\[ Var(\varepsilon_i) = \sigma^2, \quad \forall i \]
Nella regressione multipla, le variabili indipendenti non devono essere fortemente correlate tra loro (multicollinearità).
Queste ipotesi sono essenziali per garantire che la regressione lineare fornisca risultati affidabili. Se una o più ipotesi non sono rispettate, potrebbero essere necessarie tecniche correttive come:
Questo dataset contiene informazioni su 5000 proprietà, rendendolo una risorsa completa per esplorare le tendenze del mercato immobiliare e costruire modelli predittivi per i prezzi delle case. I dati includono diverse caratteristiche che catturano i dettagli della proprietà, la posizione e le condizioni di mercato, offrendo ampie opportunità per l’esplorazione dei dati, la visualizzazione e le applicazioni di machine learning.
library(tidyverse)
library(DescTools)
library(GGally)
library(caret)
library(kableExtra)
library(pander)
library(skimr)
library(ISLR)
library(MASS)
# Set the working directory
setwd("C:\\Users\\Windows 10\\OneDrive\\Desktop\\LUISS LESSON\\02 script\\Lesson 3 Linear Regression")
# Import the dataset
df = read.csv("sampled_house_prices.csv", header=T, sep=';')
# df = Credit
str(df)
## 'data.frame': 5000 obs. of 15 variables:
## $ price : num 475000 316000 802000 905000 700000 ...
## $ bedrooms : int 4 4 4 4 4 3 7 3 4 3 ...
## $ bathrooms : int 2 2 2 2 2 1 4 2 2 2 ...
## $ sqft_living : int 2040 2120 2130 3330 2440 900 3470 1580 2520 1570 ...
## $ sqft_lot : int 16200 46173 8734 9557 9450 10511 16264 7941 15205 16817 ...
## $ floors : num 2 2 2 2 1.5 1 2 2 1 2 ...
## $ waterfront : chr "N" "N" "N" "N" ...
## $ view : int 0 0 2 0 0 0 0 0 0 0 ...
## $ condition : chr "Average" "Average" "Good" "Average" ...
## $ grade : int 8 7 8 10 7 6 9 7 7 7 ...
## $ sqft_above : int 2040 2120 2130 3330 2440 900 3470 1580 2040 1570 ...
## $ sqft_basement: int 0 0 0 0 0 0 0 0 480 0 ...
## $ yr_renovated : int 0 0 0 0 2014 0 0 0 0 0 ...
## $ sqft_living15: int 2530 2000 2550 3360 1720 1460 3040 1730 1680 1600 ...
## $ sqft_lot15 : int 15389 46173 8800 9755 7503 10643 13500 8051 10000 16817 ...
# Mutate character variables into categorical ones
df = df %>% mutate(across(where(is.character), as.factor))
# Show data
df %>%
slice(1:10) %>%
kbl() %>%
kable_styling()
price | bedrooms | bathrooms | sqft_living | sqft_lot | floors | waterfront | view | condition | grade | sqft_above | sqft_basement | yr_renovated | sqft_living15 | sqft_lot15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
475000 | 4 | 2 | 2040 | 16200 | 2.0 | N | 0 | Average | 8 | 2040 | 0 | 0 | 2530 | 15389 |
316000 | 4 | 2 | 2120 | 46173 | 2.0 | N | 0 | Average | 7 | 2120 | 0 | 0 | 2000 | 46173 |
802000 | 4 | 2 | 2130 | 8734 | 2.0 | N | 2 | Good | 8 | 2130 | 0 | 0 | 2550 | 8800 |
905000 | 4 | 2 | 3330 | 9557 | 2.0 | N | 0 | Average | 10 | 3330 | 0 | 0 | 3360 | 9755 |
700000 | 4 | 2 | 2440 | 9450 | 1.5 | N | 0 | Average | 7 | 2440 | 0 | 2014 | 1720 | 7503 |
178500 | 3 | 1 | 900 | 10511 | 1.0 | N | 0 | Good | 6 | 900 | 0 | 0 | 1460 | 10643 |
950000 | 7 | 4 | 3470 | 16264 | 2.0 | N | 0 | Good | 9 | 3470 | 0 | 0 | 3040 | 13500 |
247000 | 3 | 2 | 1580 | 7941 | 2.0 | N | 0 | Good | 7 | 1580 | 0 | 0 | 1730 | 8051 |
387846 | 4 | 2 | 2520 | 15205 | 1.0 | N | 0 | Good | 7 | 2040 | 480 | 0 | 1680 | 10000 |
370000 | 3 | 2 | 1570 | 16817 | 2.0 | N | 0 | Average | 7 | 1570 | 0 | 0 | 1600 | 16817 |
Plot Distribution per variabili quantitative
for (col in colnames(df)) {
if (is.numeric(df[[col]])) {
PlotFdist(df[[col]], main = col, xlab = col)
}
}
Key Points della Visualizzazione:
df <- df %>%
mutate(
across(c(bedrooms, bathrooms, floors, view, grade), as.factor),
yr_renovated = as.factor(case_when(
yr_renovated == 0 ~ "0",
TRUE ~ "1"
)))
Pair Plot delle variabili quantitative
# Pair Plot for numerical variables
df %>% select_if(is.numeric) %>% ggpairs()
ggplot(df, aes(x = price, y = sqft_living)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE, color = "blue") +
labs(title = "Price ~ Sq Feet", x = "Rating", y = "Price")
1) Dividere il dataset in train set e test set
set.seed(1234)
train_index <- createDataPartition(df$price, p = 0.8, list = FALSE)
train_data <- df[train_index, ]
test_data <- df[-train_index, ]
# Apply linear regression model
model <- lm(price ~ sqft_living, data = train_data)
summary(model)
##
## Call:
## lm(formula = price ~ sqft_living, data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -978484 -149094 -22031 108124 4081808
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -54407.598 10260.478 -5.303 1.2e-07 ***
## sqft_living 288.938 4.528 63.810 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 264100 on 3999 degrees of freedom
## Multiple R-squared: 0.5045, Adjusted R-squared: 0.5044
## F-statistic: 4072 on 1 and 3999 DF, p-value: < 2.2e-16
Quando applichiamo un modello di regressione lineare
al dataset Credit, potremmo ottenere un valore negativo
per l’intercetta (\(\beta_0\)). Questo
potrebbe sembrare strano, perché il prezzo delle case
(Price
) è sempre positivo nella realtà.
L’intercetta rappresenta il valore previsto della variabile
dipendente (Price
) quando tutte le variabili indipendenti
sono uguali a zero. In alcuni casi, questo non ha molto senso pratico,
portando ad un’intercetta negativa che non ha un’interpretazione
concreta.
Price
Un altro motivo per cui il modello può comportarsi in modo anomalo è
che la variabile Price
è strettamente
positiva e può avere una distribuzione asimmetrica. La
regressione lineare funziona quando la variabile dipendente è
distribuita più simmetricamente e su tutto l’asse dei numeri reali,
compresi i valori negativi. In sintesi, stiamo violando l’ipotesi di
normalità
Per migliorare l’adattamento del modello, possiamo applicare una
trasformazione a Price
, ad esempio:
Price
sottraendo la media e
dividendo per la deviazione standard (standardizzazione):Price
distribuito intorno allo zero.# Trasformazione logaritmica delle delle variabili
df_log = df %>% mutate(across(is.numeric,log1p))
# Residuals Histogram
PlotFdist(df_log$price, main='log_price')
df_log %>% select_if(is.numeric) %>% ggpairs()
train_index <- createDataPartition(df_log$price, p = 0.8, list = FALSE)
train_data <- df_log[train_index, ]
test_data <- df_log[-train_index, ]
# Apply linear regression model
model <- lm(price ~ sqft_living, data = train_data)
summary(model)
##
## Call:
## lm(formula = price ~ sqft_living, data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.09995 -0.29371 0.01756 0.24928 1.30220
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 6.71200 0.10747 62.46 <2e-16 ***
## sqft_living 0.84034 0.01422 59.10 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.3841 on 3999 degrees of freedom
## Multiple R-squared: 0.4662, Adjusted R-squared: 0.4661
## F-statistic: 3492 on 1 and 3999 DF, p-value: < 2.2e-16
In conclusione, se notiamo un’intercetta negativa che non ha senso pratico, potremmo dover controllare la distribuzione della nostra variabile dipendente e applicare una trasformazione appropriata.
3) Applicare il modello sul test set
# Generiamo le previsioni sui dati originali
predictions <- exp(predict(model, newdata = test_data, type = "response"))
# Trasformazione inversa
4) Valutare la bontà di adattamento del modello attraverso la statistica \(R^2\)
\(R^2 = 1 - \frac{\sum (y_i - \hat{y}_i)^2}{\sum (y_i - \bar{y})^2}\)
# Evaluate the model using R-squared
actual_values <- exp(test_data$price)
rss <- sum((actual_values - predictions)^2)
tss <- sum((actual_values - mean(actual_values))^2)
rsquared <- 1 - (rss / tss)
print(paste("R2:", round(rsquared, 2)))
## [1] "R2: 0.43"
# Make a DataFrame
residuals_df <- data.frame(
predictions = predictions,
actual_values = actual_values,
residuals = actual_values - predictions
)
Lo scopo del seguente grafico è assicurarsi che non ci sia un trend sistematico nei dati per assicurare omoschedasticità dei residui e indipendenza tra errori e predizioni
# Residual vs Fitted
ggplot(residuals_df, aes(x = predictions, y = residuals)) +
geom_point() +
geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
labs(title = "Residuals vs Fitted",
x = "Fitted values", y = "Residuals") +
theme_minimal()
Il grafico mostra che i residui sono piuttosto centrati, tuttavia la presenza di outlier potrebbe inficiare le performance del modello. Nel prossimo grafico infatti si osservano delle code molto pesanti
# Residuals Histogram
PlotFdist(residuals_df$residuals, main='Residuals')
Per individuare e rimuovere gli outlier in R, possiamo utilizzare diverse tecniche statistiche, tra cui la Cook’s Distance, che misura l’influenza di un singolo punto sui parametri stimati del modello di regressione. Punti con un valore elevato di Cook’s Distance sono considerati outlier influenti.
cooksd <- cooks.distance(model)
# Plot della Cook's Distance
plot(cooksd, pch="*", cex=2, main="Influential Observations by Cook's Distance",
xlab = "Osservazioni", ylab = "Cook's Distance")
# Aggiungi una linea di cutoff (4/n)
abline(h = 4 / length(cooksd), col="red")
# Aggiungi etichette rosse per gli outlier (Cook's distance > 4 * media)
text(x = 1:length(cooksd), y = cooksd,
labels = ifelse(cooksd > 4 * mean(cooksd, na.rm = TRUE), names(cooksd), ""),
col = "red", pos = 3)
# Calcolare la Cook's Distance
cooksd <- cooks.distance(model)
# Identificare gli outlier (valori di Cook's Distance > 4/n)
threshold <- 4 / length(cooksd)
outliers_cooks <- which(cooksd > threshold)
# Rimuovere gli outlier dal dataset
df_clean_cooks <- df_log[-outliers_cooks, ]
# Visualizzare il nuovo modello senza gli outlier
model_clean_cooks <- lm(price ~ sqft_living, data = df_clean_cooks)
plot(model_clean_cooks)
Dall’ interpretazione dei residui emerge che esistono ancora informazioni sistematiche nei dati che non riusciamo a cogliere con la sola variabile ‘sqft_living’. E’ necessario quindi optare per l’inclusione di altre variabili. Vediamo come.
factor_vars = df %>%
select_if(is.factor) %>% names
# Reshape data: Gather all categorical variables into one column
df_long_cat <- df %>%
pivot_longer(cols = all_of(factor_vars), names_to = "Variable", values_to = "Category")
factor_vars
## [1] "bedrooms" "bathrooms" "floors" "waterfront" "view"
## [6] "condition" "grade" "yr_renovated"
# Create the boxplot
ggplot(df_long_cat, aes(x = Category, y = price, fill = Category)) +
geom_boxplot() +
facet_wrap(~ Variable, scales = "free_x") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1), legend.position = "none")
set.seed(1234)
train_index <- createDataPartition(df_log$price, p = 0.8, list = FALSE)
train_data <- df_log[train_index, ]
test_data <- df_log[-train_index, ]
# Apply linear regression model
model <- lm(price ~ ., data = train_data)
summary(model)
##
## Call:
## lm(formula = price ~ ., data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.14229 -0.22389 0.01287 0.21747 1.21595
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.037359 0.308143 26.083 < 2e-16 ***
## bedrooms1 -0.109132 0.266769 -0.409 0.682498
## bedrooms2 -0.064874 0.263408 -0.246 0.805473
## bedrooms3 -0.184584 0.263828 -0.700 0.484196
## bedrooms4 -0.178209 0.264081 -0.675 0.499825
## bedrooms5 -0.176161 0.264766 -0.665 0.505869
## bedrooms6 -0.205714 0.267995 -0.768 0.442770
## bedrooms7 -0.174899 0.310096 -0.564 0.572776
## bathrooms1 0.505113 0.257035 1.965 0.049467 *
## bathrooms2 0.437349 0.257345 1.699 0.089311 .
## bathrooms3 0.467591 0.258002 1.812 0.070007 .
## bathrooms4 0.510172 0.258828 1.971 0.048784 *
## bathrooms5 0.598380 0.278087 2.152 0.031475 *
## bathrooms6 0.619200 0.299285 2.069 0.038617 *
## bathrooms8 1.273781 0.465671 2.735 0.006259 **
## sqft_living 0.208199 0.063869 3.260 0.001124 **
## sqft_lot -0.013964 0.015311 -0.912 0.361818
## floors1.5 0.139751 0.019742 7.079 1.71e-12 ***
## floors2 -0.014521 0.016958 -0.856 0.391880
## floors2.5 0.112018 0.061668 1.816 0.069373 .
## floors3 0.108142 0.035854 3.016 0.002576 **
## floors3.5 -0.067525 0.323631 -0.209 0.834733
## waterfrontY 0.321138 0.074484 4.311 1.66e-05 ***
## view1 0.236261 0.040147 5.885 4.31e-09 ***
## view2 0.120541 0.025644 4.701 2.68e-06 ***
## view3 0.141085 0.035533 3.971 7.30e-05 ***
## view4 0.207869 0.056564 3.675 0.000241 ***
## conditionFair 0.002149 0.062702 0.034 0.972665
## conditionGood 0.083072 0.012417 6.690 2.54e-11 ***
## conditionPoor -0.339369 0.132334 -2.564 0.010370 *
## conditionVery Good 0.185614 0.020965 8.853 < 2e-16 ***
## grade5 -0.218286 0.139149 -1.569 0.116793
## grade6 0.005430 0.130499 0.042 0.966811
## grade7 0.173901 0.130763 1.330 0.183627
## grade8 0.327479 0.131834 2.484 0.013032 *
## grade9 0.539752 0.133347 4.048 5.27e-05 ***
## grade10 0.717422 0.135442 5.297 1.24e-07 ***
## grade11 0.864399 0.140613 6.147 8.66e-10 ***
## grade12 1.146194 0.163070 7.029 2.44e-12 ***
## grade13 1.246129 0.242699 5.134 2.97e-07 ***
## sqft_above 0.150073 0.062646 2.396 0.016641 *
## sqft_basement 0.019884 0.004178 4.759 2.02e-06 ***
## yr_renovated1 0.211197 0.025631 8.240 2.32e-16 ***
## sqft_living15 0.300151 0.026608 11.280 < 2e-16 ***
## sqft_lot15 -0.056303 0.016597 -3.392 0.000700 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.3213 on 3956 degrees of freedom
## Multiple R-squared: 0.6355, Adjusted R-squared: 0.6314
## F-statistic: 156.7 on 44 and 3956 DF, p-value: < 2.2e-16
Il Backward Modelling e il Forward Modelling sono due approcci di selezione automatica delle variabili per costruire modelli predittivi più efficienti. Entrambi i metodi cercano di selezionare le variabili indipendenti più significative, rimuovendo quelle che non contribuiscono in modo rilevante alla previsione del modello.
Backward Modelling (eliminazione progressiva) parte con un modello completo e rimuove le variabili meno significative, una alla volta.
Forward Modelling (selezione progressiva) parte con un modello vuoto e aggiunge le variabili più significative, una alla volta.
Questi metodi si applicano quando vogliamo costruire un modello di regressione con un numero significativo di variabili predittive, ma non siamo sicuri di quali siano le più rilevanti. La selezione automatica delle variabili aiuta a:
Semplificare il modello: rimuovendo variabili irrilevanti, rendendo il modello più interpretabile e facile da comprendere. Prevenire l’overfitting: eliminando variabili che potrebbero far adattare il modello troppo ai dati di addestramento, migliorando così la generalizzazione. Ottimizzare il modello: selezionando solo le variabili che migliorano la performance del modello. Entrambi i metodi sono utili quando abbiamo a disposizione un grande numero di variabili, ma non vogliamo costruire un modello che sia troppo complesso e rischioso.
Backward Modelling (Eliminazione progressiva)
Il processo di Backward Modelling parte da un modello che include tutte le variabili predittive disponibili. Successivamente, il modello esamina ciascuna variabile per determinare se può essere eliminata senza compromettere significativamente la qualità del modello. In genere, la variabile che viene rimossa è quella che ha il valore di p-value più alto, indicante una scarsa significatività statistica.
Il processo continua finché tutte le variabili rimanenti sono significative (ovvero, i loro p-value sono sotto una certa soglia, di solito 0.05).
Forward Modelling (Selezione progressiva)
Il Forward Modelling, al contrario, inizia con un modello vuoto, che include solo l’intercetta. Successivamente, aggiunge le variabili una alla volta, selezionando quella che migliora maggiormente la bontà del modello, solitamente misurata tramite un criterio come l’AIC (Akaike Information Criterion). Il processo continua finché l’aggiunta di nuove variabili non porta a un miglioramento significativo.
# Fit del modello
initial_model <- lm(price ~ ., data = train_data)
# Forward selection (starting with an empty model)
forward_model <- step(lm(price ~ 1, data = train_data),
scope = formula(initial_model),
direction = "forward", trace=0)
# Estrarre la matrice dei coefficienti
coeffs <- summary(model)$coefficients
# Filtrare solo i coefficienti con p-value ≤ 0.05
significant_coeffs <- coeffs[coeffs[, "Pr(>|t|)"] <= 0.05, ]
# Visualizzare i coefficienti significativi
significant_coeffs
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.03735894 0.308142625 26.083243 1.579164e-138
## bathrooms1 0.50511262 0.257035033 1.965151 4.946665e-02
## bathrooms4 0.51017201 0.258828102 1.971084 4.878383e-02
## bathrooms5 0.59838016 0.278086576 2.151776 3.147530e-02
## bathrooms6 0.61920036 0.299285071 2.068932 3.861731e-02
## bathrooms8 1.27378074 0.465671068 2.735366 6.258885e-03
## sqft_living 0.20819918 0.063869151 3.259777 1.124437e-03
## floors1.5 0.13975118 0.019741931 7.078901 1.711284e-12
## floors3 0.10814209 0.035854378 3.016147 2.576365e-03
## waterfrontY 0.32113808 0.074484224 4.311491 1.661075e-05
## view1 0.23626101 0.040147220 5.884866 4.314099e-09
## view2 0.12054131 0.025643655 4.700629 2.681913e-06
## view3 0.14108531 0.035532803 3.970565 7.297636e-05
## view4 0.20786897 0.056564108 3.674927 2.410702e-04
## conditionGood 0.08307224 0.012417177 6.690107 2.542779e-11
## conditionPoor -0.33936889 0.132334409 -2.564480 1.036965e-02
## conditionVery Good 0.18561356 0.020965177 8.853422 1.257327e-18
## grade8 0.32747891 0.131833818 2.484028 1.303164e-02
## grade9 0.53975191 0.133347176 4.047719 5.270815e-05
## grade10 0.71742242 0.135441703 5.296909 1.241896e-07
## grade11 0.86439908 0.140613454 6.147343 8.659022e-10
## grade12 1.14619435 0.163070099 7.028844 2.441717e-12
## grade13 1.24612862 0.242698980 5.134462 2.965685e-07
## sqft_above 0.15007264 0.062645987 2.395567 1.664090e-02
## sqft_basement 0.01988363 0.004178187 4.758915 2.015892e-06
## yr_renovated1 0.21119666 0.025631272 8.239804 2.320206e-16
## sqft_living15 0.30015127 0.026608493 11.280281 4.543028e-29
## sqft_lot15 -0.05630340 0.016596940 -3.392397 6.996429e-04
formula <- price ~ grade + view + condition +
sqft_lot15 + sqft_living15 + yr_renovated + sqft_basement +
waterfront + sqft_above
model <- lm(formula, data=train_data)
summary(model)
##
## Call:
## lm(formula = formula, data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.08325 -0.22961 0.01049 0.22805 1.29368
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 9.115598 0.211472 43.106 < 2e-16 ***
## grade5 -0.209642 0.134910 -1.554 0.1203
## grade6 -0.002556 0.126728 -0.020 0.9839
## grade7 0.127176 0.126881 1.002 0.3162
## grade8 0.281815 0.128042 2.201 0.0278 *
## grade9 0.509216 0.129717 3.926 8.80e-05 ***
## grade10 0.712889 0.131911 5.404 6.89e-08 ***
## grade11 0.908685 0.136881 6.638 3.60e-11 ***
## grade12 1.223063 0.156443 7.818 6.83e-15 ***
## grade13 1.583624 0.212914 7.438 1.25e-13 ***
## view1 0.245519 0.040701 6.032 1.76e-09 ***
## view2 0.130677 0.025862 5.053 4.55e-07 ***
## view3 0.177397 0.035920 4.939 8.19e-07 ***
## view4 0.250348 0.056614 4.422 1.00e-05 ***
## conditionFair 0.029122 0.063259 0.460 0.6453
## conditionGood 0.090398 0.012357 7.315 3.09e-13 ***
## conditionPoor -0.325747 0.134591 -2.420 0.0156 *
## conditionVery Good 0.207789 0.020747 10.015 < 2e-16 ***
## sqft_lot15 -0.075698 0.007283 -10.393 < 2e-16 ***
## sqft_living15 0.270117 0.026281 10.278 < 2e-16 ***
## yr_renovated1 0.228709 0.025901 8.830 < 2e-16 ***
## sqft_basement 0.029177 0.001889 15.449 < 2e-16 ***
## waterfrontY 0.314717 0.075171 4.187 2.89e-05 ***
## sqft_above 0.295641 0.022388 13.205 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.3272 on 3977 degrees of freedom
## Multiple R-squared: 0.6199, Adjusted R-squared: 0.6177
## F-statistic: 282 on 23 and 3977 DF, p-value: < 2.2e-16
plot(model)
# Generiamo le previsioni sui dati originali
predictions <- exp(predict(model, newdata = test_data, type = "response"))
# Evaluate the model using R-squared
actual_values <- exp(test_data$price)
rss <- sum((actual_values - predictions)^2)
tss <- sum((actual_values - mean(actual_values))^2)
rsquared <- 1 - (rss / tss)
print(paste("R2:", round(rsquared, 2) ))
## [1] "R2: 0.65"
# Make a DataFrame
residuals_df <- data.frame(
predictions = predictions,
actual_values = actual_values,
residuals = actual_values - predictions
)
# Creare un data frame in formato long per ggplot
df_long <- data.frame(
value = c(residuals_df$predictions, residuals_df$actual_values),
type = rep(c("Predictions", "Actual Values"), each = length(predictions))
)
# Creare il grafico con ggplot
ggplot(df_long, aes(x = value, fill = type)) +
geom_density(alpha = 0.5) + # Densità con trasparenza
scale_fill_manual(values = c("Residuals" = "green", "Predictions" = "orange", "Actual Values" = "blue")) + # Colori per le densità
labs(title = "Valori Osservati e Predetti",
x = "Valori", y = "Densità") +
theme_minimal() + # Tema minimal
theme(legend.title = element_blank()) # Rimuovere il titolo della legenda
Qualità della casa (grade) è un fattore cruciale per determinare il prezzo. Le case con un rating più alto hanno un prezzo molto più alto.
Le caratteristiche della vista (view) e la vicinanza al waterfront (waterfrontY) sono anche determinanti significativi per aumentare il prezzo.
La superficie abitabile (sqft_living) ha un effetto positivo sul prezzo, e più spazio tende a significare un prezzo più elevato.
Il numero di bagni è un altro importante indicatore: più bagni comportano un prezzo più elevato, con le case con più bagni che hanno un valore significativamente maggiore.
Le condizioni della casa (condition) sono importanti, con case in cattive condizioni che tendono ad avere un prezzo inferiore rispetto a quelle in ottime condizioni.
La presenza di un seminterrato (sqft_basement) ha un effetto positivo ma minore, mentre la superficie del lotto sqft_lot15 sembra avere un effetto meno significativo.