GitHub

La Regressione Lineare

Introduzione

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.

Ipotesi Classiche del Modello di Regressione Lineare

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.

1. Linearità

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.


2. Indipendenza degli Errori (Assenza di Autocorrelazione)

Gli errori (\(\varepsilon\)) devono essere indipendenti tra loro. In altre parole, non devono esserci correlazioni sistematiche tra gli errori associati a diverse osservazioni.

  • Se gli errori sono correlati (ad esempio in dati temporali o spaziali), si parla di autocorrelazione, che può portare a stime distorte della significatività dei coefficienti.

3. Normalità degli Errori

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.

  • Se questa ipotesi non è rispettata, il test \(t\) e il test \(F\) potrebbero non essere validi.
  • Si può verificare con un QQ-plot o un test di normalità come il test di Shapiro-Wilk.

4. Omogeneità della Varianza degli Errori (Omoschedasticità)

La varianza degli errori deve essere costante lungo tutti i valori della variabile indipendente:

\[ Var(\varepsilon_i) = \sigma^2, \quad \forall i \]

  • Se la varianza cambia con i valori di \(x\) (fenomeno chiamato eteroschedasticità), le stime dei coefficienti saranno ancora corrette, ma i loro errori standard saranno distorti, rendendo i test di significatività inaffidabili.
  • L’eteroschedasticità si può rilevare con un grafico dei residui.

5. Assenza di Collinearità Perfetta (per Modelli Multivariati)

Nella regressione multipla, le variabili indipendenti non devono essere fortemente correlate tra loro (multicollinearità).

  • Se due o più variabili sono altamente correlate, i coefficienti di regressione possono diventare instabili e difficili da interpretare.
  • Per rilevare la collinearità, si può usare il Variance Inflation Factor (VIF).

Conclusioni

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:

Dati

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.

Descrizione delle Variabili

Dettagli del Prezzo

  • price: Prezzo di vendita della casa.

Caratteristiche della Proprietà

  • bedrooms: Numero di camere da letto.
  • bathrooms: Numero di bagni.
  • sqft_living: Superficie abitabile in piedi quadrati.
  • sqft_lot: Dimensione del lotto in piedi quadrati.
  • floors: Numero di piani.
  • waterfront: Indica se la proprietà ha una vista sul lungomare.
  • view: Valutazione della qualità della vista.
  • condition: Condizione generale della casa.
  • grade: Grado di costruzione e design (scala da 1 a 13).

Metriche Aggiuntive

  • sqft_above: Superficie della proprietà sopra il livello del suolo.
  • sqft_basement: Superficie del seminterrato in piedi quadrati.
  • yr_built: Anno di costruzione della proprietà.
  • yr_renovated: Anno dell’ultima ristrutturazione.

Confronti con le Proprietà Vicine

  • sqft_living15: Superficie abitabile media delle 15 proprietà più vicine.
  • sqft_lot15: Dimensione media del lotto delle 15 proprietà più vicine.

Data Exploration

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:

  • Alcune variabili (es. bedrooms e bathrooms) per quanto numeriche non possono essere considerate tali, vanno quindi trasformate, rendendole categoriche
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()

  • Il risultato del Pair Plot mostra che la correlazione più forte esiste tra Price e sqft_living, nel seguente grafico si mostra un dettaglio della relazione lineare esistente tra le due variabili
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")

Regressione Lineare Semplice

Model Training

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, ]
  1. Stimare il modello sul train set
# 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

Interpretazione dell’Intercetta e Trasformazione della Variabile Price

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à.

Perché otteniamo un’intercetta negativa?

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.

Problema della Distribuzione di 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à

Soluzione: Trasformazione Logaritmica o Traslazione

Per migliorare l’adattamento del modello, possiamo applicare una trasformazione a Price, ad esempio:

  1. Trasformazione logaritmica
    • Usare il logaritmo naturale può ridurre l’asimmetria e rendere la relazione più lineare:
    • \[ Price' = \log(Price + 1) \]
    • Aggiungiamo 1 per evitare problemi con i valori pari a zero.
  2. Traslazione e trasformazione simmetrica
    • Possiamo trasformare Price sottraendo la media e dividendo per la deviazione standard (standardizzazione):
    • \[ Price' = \frac{Price - \text{media}(Price)}{\text{deviazione standard}(Price)} \]
    • Questo rende 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

Vantaggi della Trasformazione

  • Migliora l’adattamento del modello ai dati.
  • Rende più interpretabili i coefficienti della regressione.
  • Evita problemi legati all’interpretazione dell’intercetta.

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"

Residual Analysis

# Make a DataFrame
residuals_df <- data.frame(
  predictions = predictions,
  actual_values = actual_values,
  residuals = actual_values - predictions
)

Plot Residual vs Fitted Scatterplot

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')

Outlier’s Detection

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)

Conclusioni

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.

Regressione Lineare Multipla

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

Introduzione al Concetto di Backward e Forward Modelling in R

1. Cos’è il Backward e Forward Modelling?

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.

2. Quando si applica e perché

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.

3. Come funziona

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

Conclusioni

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.