library(ggplot2)
library(broom)
Założenia modelu dotyczą typu zależności (czy jest to zależność liniowa) oraz tzw. reszt z modelu. Reszty z modelu to różnica między wartością obserwowaną \(y\) oraz wartością oszacowaną z modelu \(\hat{y}\).
\[reszty = y - \hat{y}\]
Przed zastosowaniem modelu do przewidywania, konieczne jest sprawdzenie, czy te założenia są zachowane. Potencjalne problemy obejmują:
brak zależności liniowej między zmiennymi x oraz y
niestała wariancja reszt
występowanie wartości nietypowych:
Założenia modelu mogą być sprawdzone wykorzystując wykresy diagnostyczne, które na kilka sposóbów wizualizują reszty z modelu.
Rysunek pokazuje jak zmieni się przebieg linii regresji oraz wartość współczynnika korelacji liniowej po wprowadzeniu do zbioru danych jednego odstającego punktu.
\(\color{blue}{\text{Kolorem niebieskim}}\) zaznaczono przykładowe wyniki pomiarów.
\(\color{green}{\text{Kolorem zielonym}}\) zaznaczono punkt odstający położony w przebiegu linii regresji.
\(\color{red}{\text{Kolorem czerwonym}}\) zaznaczono punkt odstający położony poza wyznaczoną linią regresji.
Rycina ilustruje zależność między miesięcznymi wartościami opadu na terenie otwartym oraz opadu podkoronowego. \(\color{blue}{\text{Niebieska linia}}\) wyznacza przebieg linii regresji, \(\color{red}{\text{kolorem czerwonym}}\) zaznaczono dodany do wykresu punkt odstający.
Każdy wykres zawiera:
Pierwszy rząd wykresów został wykonany z uwzględnieniem wszystkich punktów pomiarowych. Kolorem czerwonym zaznaczono obserwacje odstające.
Drugi rząd przedstawia równania regresji oraz współczynnik korelacji bez uwzględnienia wartości odstających.
Obserwacje odstające mogą mieć duży wpływ na wartość współczynnika korelacji liniowej oraz na przebieg linii regresji.
Wartości odstające można zidentyfikować wykorzystując wykresy diagnostyczne, a w szczególności wykres Residuals vs. Leverage.
set.seed(123)
<- 1000
n <- runif(n, min = 0, max = 100)
x
#poprawny model
<- 3 + 0.1 * x + rnorm(n, sd = 3)
y1
#zmienna wariancja
<- 3 + 0.2 * x + (1 + x / 25) * rnorm(n, sd = 3)
y2
#wartosci odstajace
#Dla 5 wybranych punktow z poprawnego modelu wartosc y została zmieniona (wymnożona przez 5).
<- y1
y3 #sel <- sample(1:length(y3), 10)
<- sample(1:length(y3), 10)
sel <- y3[sel]*50
y3[sel]
#zaleznosc nieliniowa
<- read.csv("dane/dane_nieliniowe.csv")
df <- df$y
y4 <- 1:length(y4)
x4
= as.data.frame(cbind(x, y1, y2, y3)) dat
Poniższe wykresy przedstawiają 4 zestawy danych:
<- qplot(x, y1, ylab = "y", main = "P1: Poprawny przykład") + stat_smooth(method = "lm") + theme_classic()
p1 <- qplot(x, y2, ylab = "y", main = "P2: Niestała wariancja") + stat_smooth(method = "lm") + theme_classic()
p2 <- qplot(x, y3, ylab = "y", main = "P3: Wartości odstające") + stat_smooth(method = "lm") + theme_classic()
p3 <- qplot(x4, y4, ylab = "y", main = "P4: Nieliniowa zależność") + stat_smooth(method = "lm") + theme_classic()
p4 ::grid.arrange(p1, p2, p3, p4, ncol = 2, nrow = 2) gridExtra
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
library(ggpubr) #pozwala na dodanie współczynnika korelacji liniowej (R) oraz równania regresji.
<- ggscatter(dat, x = "x", y = "y1",
p1 add = "reg.line",
add.params = list(color = "blue", fill = "lightgray"),
title = "P1: Poprawny przykład") +
stat_regline_equation(label.x = 0, label.y = 35) +
stat_cor(label.x=0, label.y=30)
<- ggscatter(dat, x = "x", y = "y2",
p2 add = "reg.line",
add.params = list(color = "blue", fill = "lightgray"),
title = "P2: Niestała wariancja") +
stat_regline_equation(label.x = 0, label.y = 55) +
stat_cor(label.x=0, label.y=45)
<- ggscatter(dat, x = "x", y = "y3",
p3 add = "reg.line",
add.params = list(color = "blue", fill = "lightgray"),
title = "P3: Wartości odstające") +
stat_regline_equation(label.x = 0, label.y = 1000) +
stat_cor(label.x=0, label.y=900)
<- ggscatter(df, x = "x", y = "y",
p4 add = "reg.line",
add.params = list(color = "blue", fill = "lightgray"),
title = "P4: Wartości odstające") +
stat_regline_equation(label.x = 0, label.y = 65) +
stat_cor(label.x=0, label.y=55)
::grid.arrange(p1, p2, p3, p4, ncol = 2, nrow = 2) gridExtra
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
Porównując wykres P1 oraz P3 widzimy, że wprowadzenie 10 punktów odstających w znacznym stopniu obniżyło korelację (z 0,68 do 0,25) Przebieg linii regresji nie zmienił się ze względu na dużą ilość punktów. Przy mmniejszej liczbie punktów, również uległby zmianie przebieg linii regresji.
Wykres P4 cechuje się najwyższym współczynnkiem korelacji (R = 0.9), mimo, że zmienna x i y nie wykazują zależności liniowej (dane mają przebieg cykliczny).
<- lm(y1 ~x, dat)
lm1 <- lm(y2 ~x, dat)
lm2 <- lm(y3 ~x, dat) lm3
W idealnej sytuacji, wartości obserwowane byłyby równe wartością wyliczonym z modelu. W rzeczywistości nie zbudujemy takiego modelu, szukamy zatem modelu, dla którego wartości obserwowane oraz wartości wyliczone z modelu (fitted values) będą jak najbardziej podobne (a zatem reszty z modelu będą jak najbliższe 0).
Gdyby wartości obserowane równe były wartością wyliczonym z modelu to na wykresie rozrzutu punkty układałyby się wzdłuż przekątnej (czerwona linia na wykresach poniżej)
<- qplot(lm1$model$y1, lm1$fitted.values,
p1 xlim = c(-5, 25), ylim = c(-5, 25),
xlab = "Wartości obserowane y", ylab ="Wartości z modelu (fitted)", main = "P1: Poprawny przykład") + geom_abline(color = "red") + theme_classic()
<- qplot(lm2$model$y2, lm2$fitted.values,
p2 xlim = c(-20, 60), ylim = c(-20, 60),
xlab = "Wartości obserowane y", ylab ="Wartości z modelu (fitted)", main = "P2: Niestała wariancja") + geom_abline(color = "red") + theme_classic()
<- qplot(lm3$model$y3, lm3$fitted.values,
p3 xlim = c(-5, 250), ylim = c(-5, 250),
xlab = "Wartości obserowane y", ylab ="Wartości z modelu (fitted)", main = "P3: Wartości odstające") + geom_abline(color = "red") + theme_classic()
::grid.arrange(p1, p2, p3, ncol = 2, nrow = 2) gridExtra
## Warning: Removed 7 rows containing missing values (geom_point).
Uwaga! Fakt, że model spełnia założenia (liniowość, rozkład normalny reszt, stała wariancja) nie oznacza jeszcze, że będzie dobrze przewidywał wartości.
Wykres przedstawia wykres rozrzutu dla wartości x oraz y.
<- ggplot(augment(lm1), aes(x, y1)) +
p1 geom_point() +
geom_segment(aes(xend = x, yend = .fitted), color = "red", size = 0.3) +
stat_smooth(method = lm, se = FALSE) +
labs(title = "P1: Poprawny przykład") +
theme_classic()
<- ggplot(augment(lm2), aes(x, y2)) +
p2 geom_point() +
geom_segment(aes(xend = x, yend = .fitted), color = "red", size = 0.3) +
stat_smooth(method = lm, se = FALSE) +
labs(title = "P2: Niestała wariancja") +
theme_classic()
<- ggplot(augment(lm3), aes(x, y3)) +
p3 geom_point() +
geom_segment(aes(xend = x, yend = .fitted), color = "red", size = 0.3) +
stat_smooth(method = lm, se = FALSE) +
labs(title = "P3: Wartości odstające") +
theme_classic()
::grid.arrange(p1, p2, p3, ncol = 2, nrow = 2) gridExtra
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
## `geom_smooth()` using formula 'y ~ x'
Reszty z modelu to różnica między wartością obserwowaną \(y\) oraz wartością oszacowaną z modelu \(\hat{y}\).
\[reszty = y - \hat{y}\]
model niedoszacowuje wartości
model przeszacowuje wartości
“Dobry model” to taki, który nie będzie regularnie przeszacowywał lub niedoszacowywał przewidywanych wartości. W “dobrym modelu” reszty dodatnie i ujemne będą się równoważyć - średnia reszt będzie zbliżona do 0 (model czasami przewidzi niższą wartość, czasami wyższą, ale w większości przypadków różnice między tym co obserwowane a tym co wyliczone z modelu będą oscylowały koło 0).
Funkcja summary
zastosowana do obiektu modelu wyświetli podstawowe podsumowanie modelu zawierające m.in wartość współczynnika R2 oraz statystyki podstawowe reszt.
summary(lm1)
##
## Call:
## lm(formula = y1 ~ x, data = dat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -8.5293 -2.1022 0.0407 1.9673 10.2217
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.122830 0.189975 16.44 <2e-16 ***
## x 0.098250 0.003308 29.70 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3.006 on 998 degrees of freedom
## Multiple R-squared: 0.4692, Adjusted R-squared: 0.4687
## F-statistic: 882.2 on 1 and 998 DF, p-value: < 2.2e-16
summary(lm2)
##
## Call:
## lm(formula = y2 ~ x, data = dat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -31.154 -5.085 -0.042 5.182 35.520
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.67003 0.59328 6.186 8.99e-10 ***
## x 0.18301 0.01033 17.716 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 9.386 on 998 degrees of freedom
## Multiple R-squared: 0.2392, Adjusted R-squared: 0.2385
## F-statistic: 313.9 on 1 and 998 DF, p-value: < 2.2e-16
summary(lm3)
##
## Call:
## lm(formula = y3 ~ x, data = dat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -12.48 -6.35 -3.90 -1.53 777.30
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.22840 2.74920 1.538 0.12435
## x 0.15557 0.04787 3.250 0.00119 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 43.5 on 998 degrees of freedom
## Multiple R-squared: 0.01047, Adjusted R-squared: 0.009481
## F-statistic: 10.56 on 1 and 998 DF, p-value: 0.001193
<- qplot(lm1$residuals, geom = "histogram", main = "P1: Poprawny przykład", xlab = "Reszty (residuals)") + theme_classic()
p1 <- qplot(lm2$residuals, geom = "histogram", main = "P2: Niestała wariancja", xlab = "Reszty (residuals)") + theme_classic()
p2 <- qplot(lm3$residuals, geom = "histogram", main = "P3: Wartości odstające", xlab = "Reszty (residuals)") + theme_classic()
p3
::grid.arrange(p1, p2, p3, ncol = 2, nrow = 2) gridExtra
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Reszty powinny mieć rozkład normalny. Wprowadzenie kilku odstających punktów (P3) spowodowało, że rozkład reszt zmienił się z normalnego (P1) na rozkład skośny.
Do analizy reszt stosuje się wykresy diagnostyczne. Wykresy diagnostyczne można wyświetlić używając funkcji plot()
lub funkcji autoplot()
z pakietu ggfortify
w celu wyświetlenia wykresów zgodnych ze stylizacją pakietu ggplot2
. Wykresy diagnostyczne to kilka sposóbów wizualizacji reszt, które pozwalają m.in na identyfikację wartości odstających oraz spradzenie rozkładu reszt.
par(mfrow = c(2, 2))
plot(lm1)
library(ggfortify)
autoplot(lm1) + theme_classic()
Przypomnijmy założenia jakie powinien spełniać model przy regresji liniowej:
Poniższy rysunek pokazuje 4 podstawowe wykresy dla “dobrego” modelu (tj. spełniającego założenia) oraz “złego modelu” (nie spełniającego założeń). Przykład pochodzi ze strony https://data.library.virginia.edu/diagnostic-plots/
Residuals vs Fitted (Reszty vs. wartości dopasowane przez model)
Normal Q-Q (wykres kwantylowy dla rozkładu normalnego)
Scale-Location
Residuals vs Leverage
W/w wykresy pokazują także 3 najbardziej odstające punkty w danych (argument id.n pozwala na zwiększenie liczby identyfikowanych punktów)- mają one etykietę wskzującą na numer wiersza w zbiorze danych. Mogą one potencjalnie powodować problemy, dlatego należy się im bliżej przyjrzeć.
Obok 4 podstawowych wykresów diagnostycznych, można wyświetlić jeszcze dodatkowy wykres diagnostyczny (plot(model, which = 4)
) pokazujący wartość odległości Cooka dla każdej obserwacji.
Funkcja broom::augment(obiekt_modelu)
pozwala na utworzenie ramki danych zawierającej kilka wskaźników przydatnych przy ocenie dopasowania modelu. Wskaźniki te są używane do konstrukcji wykresów diagnostycznych.
::augment(lm1) broom
## # A tibble: 1,000 x 8
## y1 x .fitted .resid .hat .sigma .cooksd .std.resid
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 4.07 28.8 5.95 -1.88 0.00153 3.01 0.000300 -0.625
## 2 7.90 78.8 10.9 -2.97 0.00203 3.01 0.000990 -0.988
## 3 10.2 40.9 7.14 3.03 0.00109 3.01 0.000557 1.01
## 4 14.1 88.3 11.8 2.28 0.00280 3.01 0.000814 0.761
## 5 7.88 94.0 12.4 -4.49 0.00338 3.00 0.00379 -1.49
## 6 3.17 4.56 3.57 -0.400 0.00347 3.01 0.0000310 -0.133
## 7 5.59 52.8 8.31 -2.72 0.00101 3.01 0.000415 -0.905
## 8 5.71 89.2 11.9 -6.18 0.00289 3.00 0.00614 -2.06
## 9 8.96 55.1 8.54 0.424 0.00104 3.01 0.0000103 0.141
## 10 7.33 45.7 7.61 -0.281 0.00102 3.01 0.00000445 -0.0934
## # … with 990 more rows
Poniżej przedstawiono wykres diagnostyczne dla 3 przypadków: P1 (Poprawny przykład), P2 (Niestałe wariancje), P3 (Wartości odstające). Czego możemy się dowiedzieć z tych wykresów?
#Parametr which wskazuje, który wykres ma być wyświetlony.
par(mfrow = c(2, 2))
plot(lm1, which=1)
plot(lm2, which=1)
plot(lm3, which=1)
par(mfrow = c(2, 2))
plot(lm1, which=2)
plot(lm2, which=2)
plot(lm3, which=2)
par(mfrow = c(2, 2))
plot(lm1, which=3)
plot(lm2, which=3)
plot(lm3, which=3)
par(mfrow = c(2, 2))
plot(lm1, which=5)
plot(lm2, which=5)
plot(lm3, which=5)
par(mfrow = c(2, 2))
plot(lm1, which=4)
plot(lm2, which=4)
plot(lm3, which=4)