Skip to content

Commit cedb4e8

Browse files
authored
Merge pull request #3 from mini-pw/main
AS
2 parents a2604c5 + 4ac7a17 commit cedb4e8

File tree

18 files changed

+36473
-0
lines changed

18 files changed

+36473
-0
lines changed

Materialy/Lab8/Lab8.ipynb

+338
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
---
2+
title: "PD3 Chylak Maciej"
3+
output:
4+
html_document:
5+
df_print: paged
6+
7+
---
8+
9+
```{r setup, include=FALSE}
10+
knitr::opts_chunk$set(echo = TRUE)
11+
library(dplyr)
12+
library(ggplot2)
13+
library(gridExtra)
14+
library(DALEX)
15+
library(DALEXtra)
16+
library(data.table)
17+
library(OpenML)
18+
library(ceterisParibus)
19+
20+
set.seed(seed = 123)
21+
```
22+
23+
##### Wczytanie zbioru danych
24+
25+
```{r message=FALSE}
26+
df <- OpenML::getOMLDataSet(data.id = 42225)
27+
df <- df$data
28+
29+
```
30+
31+
32+
##### Dane:
33+
34+
35+
36+
##### Przygotowanie naszego zbioru danych do dalszej analizy. Zamienienie kolumny cut na wartosci numeryczne, skala oceny ciecia
37+
38+
```{r}
39+
df <- df[, c(1, 2, 3, 4, 5, 6, 8, 9, 10, 7)]
40+
41+
df$cut <- ifelse(df$cut=="Fair", 0, ifelse(df$cut=="Good", 1,
42+
ifelse(df$cut=="Very Good", 2,
43+
ifelse(df$cut=="Premium", 4, 5))))
44+
colnames(df) <- c(colnames(df[1:6]), "x_mes", "y_mes", "z_mes", "price")
45+
df
46+
```
47+
48+
49+
##### Podzielenie naszego zbioru danych na zbiór treninigowy i walidacyjny
50+
51+
```{r essage=FALSE}
52+
dt <- sort(sample(nrow(df), nrow(df)*.7))
53+
Train <- df[dt, ]
54+
Valid <- df[-dt, ]
55+
```
56+
57+
##### Stworzenie modelu na zbiorze treningowym
58+
59+
```{r essage=FALSE}
60+
model <- ranger::ranger(price~., data=Train)
61+
model
62+
63+
```
64+
65+
##### Stworzenie explainera, który posluzy nam pozniej do wyjasnienia modelu
66+
67+
```{r essage=FALSE}
68+
explainer <- explain(model = model,
69+
data = Train[, -10],
70+
y = Train$price)
71+
```
72+
73+
```{r}
74+
model_type.dalex_explainer <- DALEXtra::model_type.dalex_explainer
75+
predict_model.dalex_explainer <- DALEXtra::predict_model.dalex_explainer
76+
```
77+
78+
79+
##### Obliczenie korelacji, a nastepnie zaprezentowanie ich na wykresie
80+
81+
```{r}
82+
library(corrplot)
83+
84+
res <- cor(df[, c(1, 2, 5, 6, 7, 8, 9)])
85+
round(res, 2)
86+
```
87+
88+
##### Jak mozemy zauwazyc, szczegolnie zmienne wymiarow diamentu sa z soba silne skorelowane, moze to zaburzyc nieco nasze ostateczne wyniki, gdyz ten model dekompozycji jest szczegolnie wrazliwy na skorelowane zmienne.
89+
90+
91+
##### Wyjasnienie przy pomocy metody ceteris paribus
92+
93+
##### Skupimy sie wokol zmiennej cut oznaczajacej jakos ciecia (1-najgorsze, 5-najlepsze), gdyz jest ona najmniej skorelowana z pozostalymi zmiennymi
94+
95+
96+
```{r}
97+
cp_1 <- ceteris_paribus(explainer, observation = Valid[50, -10], variables = "cut")
98+
plot(cp_1) + ggtitle("Ceteris paribus 1")
99+
```
100+
101+
Na pierwszym wykresie mozemy zauwazyc spodziewany wynik, wartosc diamentow rosnie wraz z jakoscia ciecia. Podobnego rozkladu powinnismy sie spodziewac takze przy pozostalych zmiennych
102+
103+
104+
105+
```{r}
106+
cp_2 <- ceteris_paribus(explainer, observation = Valid[200, -10], variables = "cut")
107+
plot(cp_2) + ggtitle("Ceteris paribus 2")
108+
109+
```
110+
111+
```{r}
112+
Valid[200, ]
113+
```
114+
115+
W tym przypadku mozemy zauwazyc dosyc nieoczywista zaleznosc. Wartosc diamentu osiaga swoje maksimum w przypadku gdy jego jakos wynosi 2, natomiast swoje minimum osiaga w punkcie, w ktorym jakos diamentu wynosi 4. Skad wynika taka zaleznosc? Ciezko dokladnie powiedziec, najprawdopodobniej jest ona spowodowana specyfika naszych danych lub z niedokladnosci naszej metody. Na pewno nie powinnismy sugerowac doborem cen w przypadku cech rownych pozostalym cecha naszej wybranej obserwacji, gdyz w dosc nieintuicyjny sposob oszacowalibysmy cene.
116+
117+
Jednak chcialbym rowniez zaznaczyc, ze w wiekszosc przypadkow model zachowal sie w sposob przewidywalny, zanim znalazlem te obserwacje sprawdzilem okolo 20-30 innych i w kazdej z nich wykres wygladal podobnie jak wykres nr 1.

PraceDomowe/PracaDomowa3/Chylak_Maciej/PD3_chylak_maciej.html

+1,879
Large diffs are not rendered by default.

PraceDomowe/PracaDomowa3/Chylak_Maciej/PD3_chylak_maciej_files/MathJax.js.download

+19
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
title: "Praca Domowa 3"
3+
author: "Klaudia Gruszkowska"
4+
output: html_document
5+
---
6+
7+
```{r setup, include=FALSE}
8+
knitr::opts_chunk$set(echo = TRUE)
9+
```
10+
11+
## Model
12+
13+
### Wczytanie przygotowanych danych i podział na zbiór testowy i treningowy
14+
```{r,message=FALSE}
15+
library('randomForest')
16+
17+
cleaned_housing <- read.csv("cleaned_housing.csv")
18+
head(cleaned_housing)
19+
cleaned_housing$NEAR.BAY = as.factor(cleaned_housing$NEAR.BAY)
20+
cleaned_housing$X.1H.OCEAN = as.factor(cleaned_housing$X.1H.OCEAN)
21+
cleaned_housing$INLAND = as.factor(cleaned_housing$INLAND)
22+
cleaned_housing$ISLAND = as.factor(cleaned_housing$ISLAND)
23+
cleaned_housing$NEAR.OCEAN = as.factor(cleaned_housing$NEAR.OCEAN)
24+
25+
set.seed(1738)
26+
27+
sample = sample.int(n = nrow(cleaned_housing), size = floor(.8*nrow(cleaned_housing)), replace = F)
28+
train = cleaned_housing[sample, ]
29+
test = cleaned_housing[-sample, ]
30+
31+
train_y = train[,'median_house_value']
32+
train_x = train[, names(train) !='median_house_value']
33+
```
34+
35+
### Model lasu losowego
36+
```{r,message=FALSE}
37+
38+
rf_model = randomForest(train_x, y = train_y , ntree = 500, importance = TRUE)
39+
40+
```
41+
42+
## Predykcja modelu
43+
44+
Wybieram obserwację pierwszą i sprawdzę jaką predykcję wylicza zaproponowany model lasu losowego:
45+
46+
```{r}
47+
y_pred = predict(rf_model, newdata = cleaned_housing[1,])
48+
y_pred
49+
```
50+
51+
Rzeczywista wartość dla tej obserwacji:
52+
53+
```{r}
54+
cleaned_housing[1,'median_house_value']
55+
```
56+
57+
## Dekompozycja predykcji modelu Ceteris Paribus
58+
59+
Do dekompozycji predykcji modelu użyję profili Ceteris Paribus:
60+
61+
```{r,message=FALSE}
62+
library(DALEX)
63+
library(DALEXtra)
64+
65+
66+
explainer <- DALEX::explain(model = rf_model,
67+
data = cleaned_housing[, -14],
68+
y = cleaned_housing[, 14],
69+
colorize=FALSE,
70+
label = "Random Forest")
71+
```
72+
73+
```{r}
74+
75+
cp_california_rf <- predict_profile(explainer = explainer,
76+
new_observation = cleaned_housing[1,])
77+
```
78+
79+
```{r,message=FALSE}
80+
library("ggplot2")
81+
plot(cp_california_rf) +
82+
ggtitle("Ceteris-paribus profile", "")
83+
```
84+
85+
Najbardziej zróżnicowany wykres otrzymujemy dla zmiennej median_income czyli mediany wynagrodzenia na gospodarstwo domowe, co pokrywa się z EDA, wcześniejszymi analizami (Break Down, SHAP, lime), które wskazywały tą zmienną jako tą z największym wpływem na predykcję oraz wydaje się to logiczne ze względu na to, że może wskazywać na "bogatą" lub "biedną" dzielnicę. Przy reszcie zmiennych widzimy tylko niewielkie różnice w wartościach predykcji dla zmien tych zmiennych.Co może wydawać się dziwne ale przy wzroście mean_bedrooms i mean_rooms nie widać wzrostu predykcji. A taki wzrost byłby zgodny z logiką, że im większa liczba pokoi tym większy dom a im większa średnia ilość pokoi w dzielnicy tym
86+
ta dzielnica jest bogatsza (większe domy np wille). Jednak takie zachowanie może być związane obcięciem naszej zmiennej celu (z EDA wiemy, że median_house_value została obcięta do wartości 500001). Dodatkowo innym wytłumaczeniem może być to, że nasza zmienna mean_bedrooms jest mocno skorelowana z mean_rooms co prowadzi do dziwnych i nierealnych sytuacji gdy przy dość niskiej wartości mean_bedrooms sprawdzamy wysokie mean_rooms.
87+
88+
```{r}
89+
90+
cp_california_bedrooms <- predict_profile(explainer = explainer,
91+
new_observation = cleaned_housing[1,], variables = "mean_rooms")
92+
93+
plot(cp_california_bedrooms,variables = "mean_rooms") +
94+
ggtitle("Ceteris-paribus profile", "")
95+
96+
```
97+
98+
```{r}
99+
plot(cp_california_rf, variable_type = "categorical", categorical_type = "bars") +
100+
ggtitle("Ceteris-paribus profile", "")
101+
```
102+
103+
Dla tych powyższych zmiennych, które oznaczają odległość od oceanu zmiany tych zmiennych oznaczają coś co nie jest w stanie zaistnieć w rzeczywistości, dla zmiennej NEAR.BAY = 1 oznaczającej bycie blisko zatoki rozważanie np wartości INLAND = 1 jest nielogiczne. Nie może być dom położony nad zatoką i równocześnie w głębi lądu.
104+
105+
```{r}
106+
107+
cp_california_2 <- predict_profile(explainer = explainer,
108+
new_observation = cleaned_housing[2000,])
109+
110+
plot(cp_california_2) +
111+
ggtitle("Ceteris-paribus profile", "")
112+
113+
```
114+
115+
```{r}
116+
117+
cp_california_2 <- predict_profile(explainer = explainer,
118+
new_observation = cleaned_housing[2000,], variables = "mean_rooms")
119+
120+
plot(cp_california_2,variables = "mean_rooms") +
121+
ggtitle("Ceteris-paribus profile", "")
122+
123+
```
124+
125+
Porównując obserwację pierwszą z obserwacją przedstawioną powyżej możemy zauważyć, że kilka wykresów zmiennych wygląda inaczej np langitude lub longitude. Przyjżyjmy się jednak zmiennej mean_rooms . W tym przypadku widać, że przy lekkim zmniejszeniu tej zmniejszej otrzymamy większe wartości predykcji. Przy obserwacji pierwszej nie ma takiej anomalii. Wykres zmiennej mean_bedrooms też ma taki wzrost. W tym wypadku może to mieć również związek z np. sytuacją gdy wartości zmiennej określającej ilość pokoi byłaby mniejsza od wartości ilości sypialni. Jest to niezbyt realna sytuacja, może to prowadzi do błędu predykcji.
126+
127+
## Wnioski
128+
129+
Niestety w tym przypadku profile Ceteris Paribus nie sprawdzają się dobrze ponieważ mamy do czynienia ze zmiennymi zależnymi (wiemy to z EDA), a w takim przypadku dochodzimy do dziwnych, nierealnych sytuacji gdy np. dany dom położony jest i blisko oceanu i w głębi lądu albo ma niską średnią liczbę pokoi a wysoką średnią liczbę sypialni. Przez to nie wszystkie anomalie jesteśmy w stanie wytłumaczyć na podstawie danych.

PraceDomowe/PracaDomowa3/Gruszkowska_Klaudia/PD3.html

+522
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)