dane <- read.csv("Hipoteczny.csv", header = TRUE)
dane[dane == ""] <- NA
dane <- as.data.frame(dane)
kable(head(dane, 10), caption = "Dane") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
scroll_box(width = "100%", height = "auto")
| Loan_ID | Gender | Married | Dependents | Education | Self_Employed | ApplicantIncome | CoapplicantIncome | LoanAmount | Loan_Amount_Term | Credit_History | Property_Area | Loan_Status |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LP001002 | Male | No | 0 | Graduate | No | 5849 | 0 | NA | 360 | 1 | Urban | Y |
| LP001003 | Male | Yes | 1 | Graduate | No | 4583 | 1508 | 128 | 360 | 1 | Rural | N |
| LP001005 | Male | Yes | 0 | Graduate | Yes | 3000 | 0 | 66 | 360 | 1 | Urban | Y |
| LP001006 | Male | Yes | 0 | Not Graduate | No | 2583 | 2358 | 120 | 360 | 1 | Urban | Y |
| LP001008 | Male | No | 0 | Graduate | No | 6000 | 0 | 141 | 360 | 1 | Urban | Y |
| LP001011 | Male | Yes | 2 | Graduate | Yes | 5417 | 4196 | 267 | 360 | 1 | Urban | Y |
| LP001013 | Male | Yes | 0 | Not Graduate | No | 2333 | 1516 | 95 | 360 | 1 | Urban | Y |
| LP001014 | Male | Yes | 3+ | Graduate | No | 3036 | 2504 | 158 | 360 | 0 | Semiurban | N |
| LP001018 | Male | Yes | 2 | Graduate | No | 4006 | 1526 | 168 | 360 | 1 | Urban | Y |
| LP001020 | Male | Yes | 1 | Graduate | No | 12841 | 10968 | 349 | 360 | 1 | Semiurban | N |
| Zmienna w tabeli | Opis zmiennej |
|---|---|
| Loan_ID | ID aplikanta |
| Gender | Płeć |
| Married | Stan cywilny |
| Dependents | Liczba osób zależnych finansowo |
| Education | Poziom edukacji |
| Self_Employed | Samozatrudnienie |
| ApplicantIncome | Dochody aplikanta |
| CoapplicantIncome | Dochody współaplikanta |
| LoanAmount | Kwota kredytu |
| Loan_Amount_Term | Okres kredytowania |
| Credit_History | Historia kredytowa |
| Property_Area | Położenie obiektu hipoteki |
| LoanStatus | Status kredytu |
| TotalIncome | Dochód całkowity |
| DebtToIncomeRatio | Wskaźnik zadłużenia w stosunku do dochodów |
Autor: Dominika Szymczak
Niniejszy raport jest projektem zaliczeniowym przedmiotu Analiza Danych dla kierunku Analityka Gospodarcza II na Politechnice Gdańskiej. Autorami są: Julia Sowińska, Dominika Szymczak oraz Mikołaj Zalewski.
Celem projektu jest identyfikacja kluczowych czynników wpływających na zatwierdzenie kredytu mieszkaniowego, analiza procesu jego zatwierdzania oraz opracowanie modelu predykcyjnego wspierającego automatyczne podejmowanie decyzji w oparciu o dane klienta.
Otrzymane dane obejmują cechy wnioskodawców, takie jak płeć, poziom edukacji, dochody, historia kredytowa, parametry kredytu oraz inne. Analiza obejmuje eksplorację danych oraz ich wyczyszczenie i przygotowanie do analizy, identyfikację kluczowych zależności i segmentację klientów. Na tej podstawie zostanie zbudowany model predykcyjny usprawniający proces przyznawania kredytów, który minimalizuje ryzyko ich udzielania klientom o niskiej zdolności kredytowej.
Autor: Dominika Szymczak
miss_summary <- tibble(
Metryka = c("Liczba braków", "Liczba pełnych wartości", "Procent braków"),
Wartość = c(n_miss(dane), n_complete(dane), pct_miss(dane))
)
kable(miss_summary, col.names = c("Metryka", "Wartość"), caption = "Podsumowanie brakujących wratości") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Metryka | Wartość |
|---|---|
| Liczba braków | 149.0000 |
| Liczba pełnych wartości | 7833.0000 |
| Procent braków | 1.8667 |
| variable | n_miss | pct_miss |
|---|---|---|
| Credit_History | 50 | 8.14 |
| Self_Employed | 32 | 5.21 |
| LoanAmount | 22 | 3.58 |
| Dependents | 15 | 2.44 |
| Loan_Amount_Term | 14 | 2.28 |
| Gender | 13 | 2.12 |
| Married | 3 | 0.489 |
| Loan_ID | 0 | 0 |
| Education | 0 | 0 |
| ApplicantIncome | 0 | 0 |
| CoapplicantIncome | 0 | 0 |
| Property_Area | 0 | 0 |
| Loan_Status | 0 | 0 |
W tabeli jest 149 pustych rekordów, co stanowi 1,87% wszytskich rekordów. Występują one w kolumnach Historia kredytowa (50), Samozatrudnienie (32), Kwota kredytu (22), Liczba osób zależnych finansowo 15), Czas trwania kredytu (14), Płeć (13) i Stan cywilny (3).
kable(miss_case_table(dane), caption = "Podsumowanie liczby brakujących wratości w rekordach") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| n_miss_in_case | n_cases | pct_cases |
|---|---|---|
| 0 | 480 | 78.1758958 |
| 1 | 121 | 19.7068404 |
| 2 | 11 | 1.7915309 |
| 3 | 2 | 0.3257329 |
480 obserwacji (z 614) jest w pełni wypełnionych (brak pustych rekordów). Stanowi to 78,18% wszystkich obserwacji.
vis_miss(dane, cluster = TRUE, sort_miss = TRUE) +
labs(title = "Analiza brakujących danych")
wykres_gr <- scale_fill_gradientn(colors = c("#42cec2", "#306591", "#002185", "#0f225f", "#142c45"))
gg_miss_fct(dane, fct = Self_Employed) +
labs(title = "Braki danych względem samozatrudnienia",
x = "Samozatrudnienie",
y = "zmienne") +
wykres_gr +
theme_minimal()
Braki w Samozatrudnieniu mogą być efektem niepodania informacji przez aplikantów lub nieposiadania formalnego zatrudnienia.
W kwocie kredytu może brakować danych z powodu problemów z wyceną wnioskowanej kwoty w momencie wypełniania wniosku internetowego.
Kolumna Historia kredytowa ma największy odsetek braków w kategorii NA w Samozatrudnieniu. To znaczy, że ten brak danych jest często powiązany z brakiem historii kredytowej.
Autor: Julia Sowińska
gg_miss_upset(dane, nsets = 7,
sets.bar.color = "#42cec2",
main.bar.color = "#0f225f")
Wykres potwierdza poprzednie wyniki o dominacji pojedynczych zbiorach braków.
Najwięcej braków danych jest w kolumnie Historia kredytowa i są to braki pojedyncze, to znaczy, że z pośród wszystkich kolumn w 43 wierszach tylko kolumna Historia kredytowa ma NA.
kable(data.frame(
zmienna = c("Credit_History", "Self_Employment"),
No = c(89, 500),
Yes = c(475, 82)),
caption = "Tabela Historia kredytowa i Samozatrudnienie") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| zmienna | No | Yes |
|---|---|---|
| Credit_History | 89 | 475 |
| Self_Employment | 500 | 82 |
Patrząc na rozkład wartości w kolumnie Historia kredytowa oraz na liczbę brakujących wartości, nasuwa się założenie, że wartości brakujące mogą reprezentować kredytobiorców, którzy nie chcieli przyznawać się do braku historii kredytowej lub dla których bank napotkał problemy z pozyskaiem danych.
Podobnie w przypadku braków w kolumnie Samozatrudnienie - mogą one reprezentować kredytobiorców, którzy nie chcieli przyznawać się do samozatrudnienia lub uznali, że nie muszą oni wypełniać tej kolumny.
Tym samym, braki w tych dwóch zmiennych uznane zostają za MNAR (Missing Not at Random).
Braki w kolumnie Kwota kredytu mogą reprezentować klientów, który złożyli wniosek kredytowy bez konkretnej kwoty, zakładając, że kwota zostanie ustalona podczas analizy. Co ciekawe, spośród wierszy charakteryzujących się wartością NA w kolumnie Kwota kredytów równo połowa ma Status kredytu równy Y i połowa równy N.
Braki w kolumnie Czas trwania kredytu sytuacja może wyglądać podobnie - mogą to być klienci, którzy nie wypełnili wartości w kolumnie, zakładając domyślne ustawienia banku. Dlatego braki w kolumnach Kwota kredytu i Czas trwania kredytu również zostają uznane za potencjalne MNAR.
Braki w kolumnie Płeć mogą reprezentować osoby, które nie chciały podawać tej informacji, uznając, że płeć nie powinna mieć wpływu na decyzje kredytową. Braki w kolumnie Liczba osób zależnych finansowo mogą oznaczać świadome pominięcie pytania w obawie przed negatywnym wpływem odpowiedzi na zdolność kredytową lub po prostu z braku obowiązku. Dlatego braki zmiennej Stan cywilny oraz braki zmiennej Płeć zostają uznane za MNAR.
Wracając do wykresu przecięć wartości - kombinacje z małą liczbą braków mogą być przypadkowe i niekoniecznie oznaczają zależności.
Kombinacja między Samozatrudnienie i Historia kredytowa również występuje niewiele razy - 5. Jednak, jako że jest to najczęściej występująca kombinacja, zostanie ona rozważona jako potencjalny związek. Może on być związany z obawą o negatywną ocenę zdolności kredytowej (jako że samozatrudnienie jest bardziej ryzykowne) i tym samym obawą o niższej kwocie kredytu lub wyższym oprocentowaniu. A także z trudnościami w uzyskaniu kredytów w przeszłości, co prowadzi do niekorzystnych danych w historii kredytowej. W takim wypadku, kredytobiorcy celowo nie podawaliby statusu samozatrudnienia i składaliby prośbę o wyższe kwoty kredytu, w nadziei, że bank uzna ich za zatrudnionych na pełen etat bez historii kredytowej.
ggplot(data = dane, aes(x = Credit_History, y = LoanAmount)) +
geom_point() +
geom_miss_point() +
scale_color_manual(values = c("#42cec2","#002185")) +
theme_minimal() +
labs(x = "Historia kredytowa", y = "Kwota kredytu") +
facet_wrap(~Self_Employed, scales = "free")
Można zauważyć, że z pośród kredytobiorców z wartością NA w kolumnie Samozatrudnienie oraz w kolumnie Historia kredytowa, niemalże wszyscy (poza jednym przypadkiem z brakiem danych również w kolumnie Kwota kredytu) mają wartości w kolumnie Kwota kredytu powyżej 150, czyli większe niż w innych grupach.
To może być argumentem za przyjęciem tezy, że osoby, które nie odpowiedziały na pytanie o samozatrudnienie, są samozatrudnione.
Autor: Mikołaj Zalewski
Obseracje z brakiem danych w kolumnie Historia kredytowa zastąpimy wartością 0 zgodnie z naszymi wcześniejszymi wnioskami. Obserwacje z brakiem danych w kolumnach Płeć i Stan cywilny zostaną zastąpione wartością “undefined”, czyli po polsku “nieokreślone”. Każdy wniosek o kredyt jest ważny, więc usuwanie obserwacji nie jest dobrym rozwiązaniem. Obserwacje z brakiem danych w kolumnie Liczba osób zależnych finansowo zostaną zastąpione wartością 0. Dla obserwacji z brakiem danych w kolumnie Czas trwania kredytu można przyjąć strategię inputacji wartością, która występuje w znaczącej większości obserwacji, czyli najpopularniejszym czasem, na jaki bierze się kredyt (czyli 360 dni). Obserwacje z brakiem danych w kolumnie Samozatrudnienie zgodnie z naszą wcześniej opisaną tezą zamieniamy na wartość “Yes”, czyli potwierdzającą samozatrudnienie.
Obserwacje z brakiem danych w kolumnie Kwota kredytu uzupełnione będą za pomocą techniki Hot Deck, w której brakująca wartość zastępowana będzie wartością od klienta o najbardziej podobnych cechach.
dane$Credit_History[is.na(dane$Credit_History)] <- 0
dane$Gender[is.na(dane$Gender)] <- "Undefined"
dane$Married[is.na(dane$Married)] <- "Undefined"
dane$Dependents[is.na(dane$Dependents)] <- 0
dane$Loan_Amount_Term[is.na(dane$Loan_Amount_Term)] <- 360
dane$Self_Employed[is.na(dane$Self_Employed)] <- "Yes"
dane <- hotdeck(dane, variable = "LoanAmount")
dane <- dane %>% select(-LoanAmount_imp)
n_miss(dane)
## [1] 0
W zbiorze danych nie występują już żadne puste wartości.
Autor: Dominika Szymczak i Julia Sowińska
Na tym etapie sprawdzić należy, czy nasz zbiór danych zawiera wartości logiczne. Wprowadzone zostają ograniczenia dla zmiennych:
- Dochód aplikanta powinna być większa lub równa 0
- Dochód współaplikanta powinna być większa lub równa 0
- Kwota kredytu powinna być większa od 0
- Okres kredytowania powinna być większa od 0
- Historia kredytowa powinna być 0 lub 1.
ograniczenia <- editset(c("0 <= ApplicantIncome",
"0 <= CoapplicantIncome",
"0 < LoanAmount",
"0 < Loan_Amount_Term"))
dane$Credit_History <- factor(dane$Credit_History,
levels = c(0, 1),
labels = c("Not existing", "Existing"))
summary(violatedEdits(ograniczenia, dane))
## No violations detected, 0 checks evaluated to NA
## NULL
Dla danych numerycznych wprowadzone zostały ograniczenia:
- dla zmiennej Dochód aplikanta wartości nie mogą być mniejsze niż 0
- dla zmiennej Dochód współaplikanta wartości nie mogą być mniejsze niż 0
- dla zmiennej Wartość kredytu wartości nie mogą być mniejsze lub równe 0
- dla zmiennej Okres kredytowania wartości nie mogą być mniejsze niż 0
Dla rekordów, których wartości nie spełniały ograniczeń przypisane powinny zostać wartości NA. Jednak w tym przypadku, wszystkie wartości zmiennych spełniały założone ograniczenia i nie ma potrzeby przeprowadzenia dalszego przekształacania tych danych.
dane <- dane %>% mutate(
Gender = factor(dane$Gender,
levels = c("Male", "Female", "Undefined"),
labels = c("Male", "Female", "Undefined")),
Married = factor(dane$Married,
levels = c("No", "Yes", "Undefined"),
labels = c("No", "Yes", "Undefined")),
Dependents = factor(dane$Dependents,
levels = c("0", "1", "2", "3+"),
labels = c("0", "1", "2", "3+")),
Education = factor(dane$Education,
levels = c("Not Graduate", "Graduate"),
labels = c("Not Graduate", "Graduate")),
Self_Employed = factor(dane$Self_Employed,
levels = c("No", "Yes"),
labels = c("No", "Yes")),
Loan_Amount_Term = factor(dane$Loan_Amount_Term,
levels = c("12", "36", "60", "84", "120", "180", "240", "300", "360", "480"),
labels = c("1", "3", "5", "7", "10", "15", "20", "25", "30", "40")),
Property_Area = factor(dane$Property_Area,
levels = c("Rural", "Semiurban", "Urban"),
labels = c("Rural", "Semiurban", "Urban")),
Loan_Status = factor(dane$Loan_Status,
levels = c("N", "Y"),
labels = c("No", "Yes")))
kable(table(dane$Gender), caption = "Tabela częstości płci", col.names = c("Kategoria", "Częstość")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Kategoria | Częstość |
|---|---|
| Male | 489 |
| Female | 112 |
| Undefined | 13 |
kable(table(dane$Married), caption = "Tabela częstości stanu cywilnego", col.names = c("Kategoria", "Częstość")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Kategoria | Częstość |
|---|---|
| No | 213 |
| Yes | 398 |
| Undefined | 3 |
kable(table(dane$Dependents), caption = "Tabela częstości liczby osób zależnych finansowo", col.names = c("Kategoria", "Częstość")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Kategoria | Częstość |
|---|---|
| 0 | 360 |
| 1 | 102 |
| 2 | 101 |
| 3+ | 51 |
kable(table(dane$Education), caption = "Tabela częstości poziomu edukacji", col.names = c("Kategoria", "Częstość")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Kategoria | Częstość |
|---|---|
| Not Graduate | 134 |
| Graduate | 480 |
kable(table(dane$Self_Employed), caption = "Tabela częstości samozatrudnienia", col.names = c("Kategoria", "Częstość")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Kategoria | Częstość |
|---|---|
| No | 500 |
| Yes | 114 |
kable(table(dane$Loan_Amount_Term), caption = "Tabela częstości okresu kredytowania", col.names = c("Kategoria", "Częstość")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Kategoria | Częstość |
|---|---|
| 1 | 1 |
| 3 | 2 |
| 5 | 2 |
| 7 | 4 |
| 10 | 3 |
| 15 | 44 |
| 20 | 4 |
| 25 | 13 |
| 30 | 526 |
| 40 | 15 |
kable(table(dane$Property_Area), caption = "Tabela częstości położenia obiektu hipoteki", col.names = c("Kategoria", "Częstość")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Kategoria | Częstość |
|---|---|
| Rural | 179 |
| Semiurban | 233 |
| Urban | 202 |
kable(table(dane$Loan_Status), caption = "Tabela częstości statusu kredytu", col.names = c("Kategoria", "Częstość")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Kategoria | Częstość |
|---|---|
| No | 192 |
| Yes | 422 |
Dla danych tekstowych, tak jak dla danych numerycznych nie znaleziono żadnych odstających od założeń wartości i nie ma potrzeby przeprowadzenia dalszego przekształacania tych danych.
plot_variables <- list(
"Gender" = "Rozkład Gender",
"Married" = "Rozkład Married",
"Dependents" = "Rozkład Dependents",
"Education" = "Rozkład Education",
"Self_Employed" = "Rozkład Self_Employed",
"Loan_Amount_Term" = "Rozkład Loan_Amount_Term",
"Credit_History" = "Rozkład Credit_History",
"Property_Area" = "Rozkład Property_Area",
"Loan_Status" = "Rozkład Loan_Status"
)
plot_list <- lapply(names(plot_variables), function(var) {
ggplot(dane, aes_string(x = var)) +
geom_bar(fill = "#306591") +
labs(title = plot_variables[[var]], x = var, y = "Liczność")
})
num_plot_vars <- c("ApplicantIncome", "CoapplicantIncome", "LoanAmount")
num_plot_list <- lapply(num_plot_vars, function(var) {
ggplot(dane, aes_string(x = var)) +
geom_histogram(fill = "#306591", color = "#0f225f", bins = 30) +
labs(title = paste("Rozkład", var), x = var, y = "Częstotliwość")
})
combined_plots <- c(plot_list, num_plot_list) %>%
do.call(cowplot::plot_grid, .)
plot_grid(
ggdraw() + draw_label("Rozkłady zmiennych", fontface = "bold", size = 14, hjust = 0.5),
combined_plots,
ncol = 1,
rel_heights = c(0.1, 1))
W zmiennej Płeć dominującą kategorią są mężczyźni (489 przypadków), natomiast kobiet jest 112, a w 13 przypadkach płeć nie została określona. W odniesieniu do zmiennej Stan cywilny, większość osób to osoby w związku małżeńskim (398), podczas gdy niezamężnych jest 213, a 3 przypadki pozostają niezdefiniowane.
Zmienna Liczba osób zależnych finansowo wskazuje, że najwięcej respondentów (360) nie posiada osób na utrzymaniu, 102 osoby deklarują jedną osobę na utrzymaniu, 101 osób dwie, a 51 osób trzy lub więcej. W odniesieniu do zmiennej Poziom edukacji, większość osób posiada wykształcenie wyższe (480), a 134 osoby mają niższy poziom wykształcenia.
W przypadku zmiennej Samozatrudneinie, 500 osób zadeklarowało, że nie prowadzi działalności gospodarczej, a 114 osób to osoby samozatrudnione. Zmienna Dochód aplikanta, opisująca dochód głównego wnioskodawcy, wskazuje na wartości od 150 do 81 000, przy czym mediana wynosi 3812, a średnia 5403, co wskazuje na obecność wartości odstających. Dochód współaplikanta jest w wielu przypadkach równy 0 (25. percentyl to 0), co oznacza, że wiele osób nie posiada współwnioskodawcy. Mediana wynosi 1188, średnia to 1621, a maksymalna wartość wynosi 41 667.
Zmienna Kwota kredytu, określająca kwotę pożyczki, ma wartości od 9 do 700, przy medianie 128 i średniej 145,8, co również sugeruje obecność wartości odstających. Okres kredytowania, opisujący czas spłaty pożyczki w miesiącach, waha się od 12 do 480 miesięcy, z medianą 360 miesięcy (30 lat).
Historia kredytowa wskazuje, że większość wnioskodawców (około 77,4%) posiada pozytywną historię kredytową (wartość 1). Rozkład zmiennej Położenie obiektu hipoteki pokazuje, że 179 obiektów znajduje się na terenach wiejskich, 233 w obszarach półmiejskich, a 202 w miastach. Zmienna Status kredytu, opisująca status wniosku o pożyczkę, wskazuje, że większość wniosków (422) została zatwierdzona, a 192 odrzucono.
z_score <- function(x) {
(x - mean(x, na.rm = TRUE)) / sd(x, na.rm = TRUE)
}
dane_outliers <- dane %>%
mutate(
z_score_ApplicantIncome = z_score(ApplicantIncome),
z_score_CoapplicantIncome = z_score(CoapplicantIncome),
z_score_LoanAmount = z_score(LoanAmount),
)
z_outliers_ApplicantIncome <- dane_outliers[dane_outliers$z_score_ApplicantIncome > 3 | dane_outliers$z_score_ApplicantIncome < -3, ]
z_outliers_CoapplicantIncome <- dane_outliers[dane_outliers$z_score_CoapplicantIncome > 3 | dane_outliers$z_score_CoapplicantIncome < -3, ]
z_outliers_LoanAmount <- dane_outliers[dane_outliers$z_score_LoanAmount > 3 | dane_outliers$z_score_LoanAmount < -3, ]
outliers <- function(df, col) {
Q1 <- quantile(df[[col]], 0.25, na.rm = TRUE)
Q3 <- quantile(df[[col]], 0.75, na.rm = TRUE)
IQR <- Q3 - Q1
bottom <- Q1 - 1.5 * IQR
top <- Q3 + 1.5 * IQR
df2 <- df %>%
filter(df[[col]] < bottom | df[[col]] > top)
return(df2)
}
iqr_outliers_ApplicantIncome <- outliers(dane_outliers, "ApplicantIncome")
iqr_outliers_CoapplicantIncome <- outliers(dane_outliers, "CoapplicantIncome")
iqr_outliers_LoanAmount <- outliers(dane_outliers, "LoanAmount")
common_outliers_ApplicantIncome <- inner_join(
z_outliers_ApplicantIncome, iqr_outliers_ApplicantIncome)
common_outliers_CoapplicantIncome <- inner_join(
z_outliers_CoapplicantIncome, iqr_outliers_CoapplicantIncome)
common_outliers_LoanAmount <- inner_join(
z_outliers_LoanAmount, iqr_outliers_LoanAmount)
kable(common_outliers_ApplicantIncome, caption = "Wartości odstające dochodów aplikantów") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
scroll_box(width = "100%", height = "auto")
| Loan_ID | Gender | Married | Dependents | Education | Self_Employed | ApplicantIncome | CoapplicantIncome | LoanAmount | Loan_Amount_Term | Credit_History | Property_Area | Loan_Status | z_score_ApplicantIncome | z_score_CoapplicantIncome | z_score_LoanAmount |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LP001448 | Undefined | Yes | 3+ | Graduate | No | 23803 | 0 | 370 | 30 | Existing | Rural | Yes | 3.011854 | -0.5540356 | 2.5972058 |
| LP001536 | Male | Yes | 3+ | Graduate | No | 39999 | 0 | 600 | 15 | Not existing | Semiurban | Yes | 5.663006 | -0.5540356 | 5.2690109 |
| LP001585 | Undefined | Yes | 3+ | Graduate | No | 51763 | 0 | 700 | 25 | Existing | Urban | Yes | 7.588677 | -0.5540356 | 6.4306654 |
| LP001637 | Male | Yes | 1 | Graduate | No | 33846 | 0 | 260 | 30 | Existing | Semiurban | No | 4.655811 | -0.5540356 | 1.3193859 |
| LP001640 | Male | Yes | 0 | Graduate | Yes | 39147 | 4750 | 120 | 30 | Existing | Semiurban | Yes | 5.523541 | 1.0692032 | -0.3069303 |
| LP002101 | Male | Yes | 0 | Graduate | Yes | 63337 | 0 | 490 | 15 | Existing | Urban | Yes | 9.483245 | -0.5540356 | 3.9911911 |
| LP002317 | Male | Yes | 3+ | Graduate | No | 81000 | 0 | 360 | 30 | Not existing | Rural | No | 12.374534 | -0.5540356 | 2.4810403 |
| LP002422 | Male | No | 1 | Graduate | No | 37719 | 0 | 152 | 30 | Existing | Semiurban | Yes | 5.289789 | -0.5540356 | 0.0647991 |
kable(common_outliers_CoapplicantIncome, caption = "Wartości odstające dochodów współaplikantów") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
scroll_box(width = "100%", height = "auto")
| Loan_ID | Gender | Married | Dependents | Education | Self_Employed | ApplicantIncome | CoapplicantIncome | LoanAmount | Loan_Amount_Term | Credit_History | Property_Area | Loan_Status | z_score_ApplicantIncome | z_score_CoapplicantIncome | z_score_LoanAmount |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LP001020 | Male | Yes | 1 | Graduate | No | 12841 | 10968 | 349 | 30 | Existing | Semiurban | No | 1.2174644 | 3.194108 | 2.3532583 |
| LP001610 | Male | Yes | 3+ | Graduate | No | 5516 | 11300 | 495 | 30 | Not existing | Semiurban | No | 0.0184220 | 3.307564 | 4.0492738 |
| LP002297 | Male | No | 0 | Graduate | No | 2500 | 20000 | 103 | 30 | Existing | Semiurban | Yes | -0.4752725 | 6.280654 | -0.5044115 |
| LP002342 | Male | Yes | 2 | Graduate | Yes | 1600 | 20000 | 239 | 30 | Existing | Urban | No | -0.6225951 | 6.280654 | 1.0754385 |
| LP002893 | Male | No | 0 | Graduate | No | 1836 | 33837 | 90 | 30 | Existing | Urban | No | -0.5839638 | 11.009234 | -0.6554266 |
| LP002949 | Female | No | 3+ | Graduate | Yes | 416 | 41667 | 350 | 15 | Not existing | Urban | No | -0.8164062 | 13.685016 | 2.3648749 |
kable(common_outliers_LoanAmount, caption = "Wartości odstające kwot kredytów") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
scroll_box(width = "100%", height = "auto")
| Loan_ID | Gender | Married | Dependents | Education | Self_Employed | ApplicantIncome | CoapplicantIncome | LoanAmount | Loan_Amount_Term | Credit_History | Property_Area | Loan_Status | z_score_ApplicantIncome | z_score_CoapplicantIncome | z_score_LoanAmount |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LP001449 | Male | No | 0 | Graduate | No | 3865 | 1640 | 490 | 30 | Existing | Rural | Yes | -0.2518332 | 0.0064090 | 3.991191 |
| LP001469 | Male | No | 0 | Graduate | Yes | 20166 | 0 | 650 | 40 | Not existing | Urban | Yes | 2.4165068 | -0.5540356 | 5.849838 |
| LP001536 | Male | Yes | 3+ | Graduate | No | 39999 | 0 | 600 | 15 | Not existing | Semiurban | Yes | 5.6630062 | -0.5540356 | 5.269011 |
| LP001585 | Undefined | Yes | 3+ | Graduate | No | 51763 | 0 | 700 | 25 | Existing | Urban | Yes | 7.5886765 | -0.5540356 | 6.430665 |
| LP001610 | Male | Yes | 3+ | Graduate | No | 5516 | 11300 | 495 | 30 | Not existing | Semiurban | No | 0.0184220 | 3.3075642 | 4.049274 |
| LP001907 | Male | Yes | 0 | Graduate | No | 14583 | 0 | 436 | 30 | Existing | Semiurban | Yes | 1.5026155 | -0.5540356 | 3.363898 |
| LP001996 | Male | No | 0 | Graduate | No | 20233 | 0 | 480 | 30 | Existing | Rural | No | 2.4274741 | -0.5540356 | 3.875026 |
| LP002101 | Male | Yes | 0 | Graduate | Yes | 63337 | 0 | 490 | 15 | Existing | Urban | Yes | 9.4832453 | -0.5540356 | 3.991191 |
| LP002191 | Male | Yes | 0 | Graduate | No | 19730 | 5266 | 570 | 30 | Existing | Rural | No | 2.3451372 | 1.2455382 | 4.920515 |
| LP002386 | Male | No | 0 | Graduate | Yes | 12876 | 0 | 405 | 30 | Existing | Semiurban | Yes | 1.2231936 | -0.5540356 | 3.003785 |
| LP002547 | Male | Yes | 1 | Graduate | No | 18333 | 0 | 500 | 30 | Existing | Urban | No | 2.1164597 | -0.5540356 | 4.107356 |
| LP002624 | Male | Yes | 0 | Graduate | No | 20833 | 6667 | 480 | 30 | Not existing | Urban | Yes | 2.5256892 | 1.7243082 | 3.875026 |
| LP002693 | Male | Yes | 2 | Graduate | Yes | 7948 | 7166 | 480 | 30 | Existing | Rural | Yes | 0.4165204 | 1.8948338 | 3.875026 |
| LP002813 | Female | Yes | 1 | Graduate | Yes | 19484 | 0 | 600 | 30 | Existing | Semiurban | Yes | 2.3048690 | -0.5540356 | 5.269011 |
| LP002959 | Female | Yes | 1 | Graduate | No | 12000 | 0 | 496 | 30 | Existing | Semiurban | Yes | 1.0797996 | -0.5540356 | 4.060890 |
W celu wykrycia wartości odstających posłużono się kombinacją dwóch metod - metody Z-score (gdzie wartość jest odstająca, jeśli jej odległość od średniej w jednostkach odchylenia standardowego jest większa niż 3 lub mniejsza niż -3) oraz metoda IQR (gdzie wartość jest odstająca, jeśli znajduje się poniżej dolnej granicY Q1−1.5×IQR lub powyżej górnej granicy Q3+1.5×IQR). Aby porównać wyniki obu metod, wybraliśmy te wiersze, które zostały uznane za wartości odstające zarówno przez metodę Z-score, jak i przez metodę IQR.
W ten sposób doszliśmy do wniosków:
- zmienna Dochód aplikanta ma 8 wartości odstających, które jednak reprezentują sobą osoby o bardzo wysokich dochodach (które mogłyby być wartościowymi kredytobiorcami) - dlatego postanowiliśmy pozostawić te wartości bez zmian;
- zmienna Dochód współaplikanta ma 6 wartości odstających, które reprezentują sobą osoby, których współkredytobiorca ma wysokie dochody (dochody te jednak mieszczą się w większości w średniej wartości zmiennej Dochód aplikanta) - dlatego te wartości też postanowiliśmy pozostawić bez zmian;
- zmienna Kwota kredytu ma 15 wartości odstających, które jednak reprezentują sobą osoby składające wnioski o najwyższe kwoty kredytu (które różnież mogłyby być wartościowymi klientami firmy) - dlatego te wartości także postanowiliśmy pozostawić bez zmian.
dane <- dane %>%
mutate(
log_ApplicantIncome = log1p(ApplicantIncome),
log_CoapplicantIncome = log1p(CoapplicantIncome),
log_LoanAmount = log1p(LoanAmount),
)
log_plot_vars <- c("log_ApplicantIncome", "log_CoapplicantIncome", "log_LoanAmount")
log_plot_list <- lapply(log_plot_vars, function(var) {
ggplot(dane, aes_string(x = var)) +
geom_histogram(fill = "#306591", color = "#0f225f", bins = 30) +
labs(title = paste("Rozkład", var), x = var, y = "Częstotliwość")
})
combined_plots <- log_plot_list %>%
do.call(cowplot::plot_grid, .)
combined_plots
Ze względu na dużą skośność w rozkładach zmiennych Dochód aplikanta, Dochód współaplikanta i Kwota kredytu postanowiono wprowadzić także zmienne reprezentujące ich log-transformację. Ze względu na możliwe zera w tych kolumnach, zdecydowaliśmy się na funkcję log1p() zamiast log() (log(0) jest niezdefiniowane). Na wykresach przedstawiających rozkłady tych zlogarytmowanych zmiennych, można zauważyć, że po transformacji rozkłady te zbliżyły się zdecydowanie do rozkładu normalnego. Jedynie w przypadku zmiennej log_CoapplicantIncome (zlogarytmowany Dochód współaplikanta) można nadal zauważyć dość dużą skośność, spowodowaną dużą liczbą ludzi składających wniosek o kredyt samodzielnie, lub wraz z współkredytobiorcą bez dochodów.
Autor: Mikołaj Zalewski
Stworzenie zmiennej łączny przychód gospodarstwa domowego ubiegającego się o kredyt
dane$TotalIncome <- dane$ApplicantIncome + dane$CoapplicantIncome
kable(head(dane), caption = "Nowostworzona zmienna dochodu całkowitego") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
scroll_box(width = "100%", height = "auto")
| Loan_ID | Gender | Married | Dependents | Education | Self_Employed | ApplicantIncome | CoapplicantIncome | LoanAmount | Loan_Amount_Term | Credit_History | Property_Area | Loan_Status | log_ApplicantIncome | log_CoapplicantIncome | log_LoanAmount | TotalIncome |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LP001002 | Male | No | 0 | Graduate | No | 5849 | 0 | 108 | 30 | Existing | Urban | Yes | 8.674197 | 0.000000 | 4.691348 | 5849 |
| LP001003 | Male | Yes | 1 | Graduate | No | 4583 | 1508 | 128 | 30 | Existing | Rural | No | 8.430327 | 7.319203 | 4.859812 | 6091 |
| LP001005 | Male | Yes | 0 | Graduate | Yes | 3000 | 0 | 66 | 30 | Existing | Urban | Yes | 8.006701 | 0.000000 | 4.204693 | 3000 |
| LP001006 | Male | Yes | 0 | Not Graduate | No | 2583 | 2358 | 120 | 30 | Existing | Urban | Yes | 7.857094 | 7.765993 | 4.795790 | 4941 |
| LP001008 | Male | No | 0 | Graduate | No | 6000 | 0 | 141 | 30 | Existing | Urban | Yes | 8.699681 | 0.000000 | 4.955827 | 6000 |
| LP001011 | Male | Yes | 2 | Graduate | Yes | 5417 | 4196 | 267 | 30 | Existing | Urban | Yes | 8.597482 | 8.342125 | 5.590987 | 9613 |
Stworzenie zmiennej stosunek długu do łącznych przychdów gospodarstwa domowego
dane$DebtToIncomeRatio <-dane$LoanAmount / dane$TotalIncome
kable(head(dane), caption = "Nowostworzona zmienna wskaźnika zadłużenia w stosunku do dochodu całkowitego") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
scroll_box(width = "100%", height = "auto")
| Loan_ID | Gender | Married | Dependents | Education | Self_Employed | ApplicantIncome | CoapplicantIncome | LoanAmount | Loan_Amount_Term | Credit_History | Property_Area | Loan_Status | log_ApplicantIncome | log_CoapplicantIncome | log_LoanAmount | TotalIncome | DebtToIncomeRatio |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LP001002 | Male | No | 0 | Graduate | No | 5849 | 0 | 108 | 30 | Existing | Urban | Yes | 8.674197 | 0.000000 | 4.691348 | 5849 | 0.0184647 |
| LP001003 | Male | Yes | 1 | Graduate | No | 4583 | 1508 | 128 | 30 | Existing | Rural | No | 8.430327 | 7.319203 | 4.859812 | 6091 | 0.0210146 |
| LP001005 | Male | Yes | 0 | Graduate | Yes | 3000 | 0 | 66 | 30 | Existing | Urban | Yes | 8.006701 | 0.000000 | 4.204693 | 3000 | 0.0220000 |
| LP001006 | Male | Yes | 0 | Not Graduate | No | 2583 | 2358 | 120 | 30 | Existing | Urban | Yes | 7.857094 | 7.765993 | 4.795790 | 4941 | 0.0242866 |
| LP001008 | Male | No | 0 | Graduate | No | 6000 | 0 | 141 | 30 | Existing | Urban | Yes | 8.699681 | 0.000000 | 4.955827 | 6000 | 0.0235000 |
| LP001011 | Male | Yes | 2 | Graduate | Yes | 5417 | 4196 | 267 | 30 | Existing | Urban | Yes | 8.597482 | 8.342125 | 5.590987 | 9613 | 0.0277749 |
z_score <- function(x) {
(x - mean(x, na.rm = TRUE)) / sd(x, na.rm = TRUE)
}
dane_outliers <- dane %>%
mutate(
z_score_TotalIncome = z_score(TotalIncome),
z_score_DebtToIncomeRatio = z_score(DebtToIncomeRatio),
)
z_outliers_TotalIncome <- dane_outliers[dane_outliers$z_score_TotalIncome > 3 | dane_outliers$z_score_TotalIncome < -3, ]
z_outliers_DebtToIncomeRatio <- dane_outliers[dane_outliers$z_score_DebtToIncomeRatio > 3 | dane_outliers$z_score_DebtToIncomeRatio < -3, ]
outliers <- function(df, col) {
Q1 <- quantile(df[[col]], 0.25, na.rm = TRUE)
Q3 <- quantile(df[[col]], 0.75, na.rm = TRUE)
IQR <- Q3 - Q1
bottom <- Q1 - 1.5 * IQR
top <- Q3 + 1.5 * IQR
df2 <- df %>%
filter(df[[col]] < bottom | df[[col]] > top)
return(df2)
}
iqr_outliers_TotalIncome <- outliers(dane_outliers, "TotalIncome")
iqr_outliers_DebtToIncomeRatio <- outliers(dane_outliers, "DebtToIncomeRatio")
common_outliers_TotalIncome <- intersect(
z_outliers_TotalIncome, iqr_outliers_TotalIncome)
common_outliers_DebtToIncomeRatio <- intersect(
z_outliers_DebtToIncomeRatio, iqr_outliers_DebtToIncomeRatio)
kable(common_outliers_TotalIncome, caption = "Wartości odstające dochodu całkowitego") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
scroll_box(width = "100%", height = "auto")
| Loan_ID | Gender | Married | Dependents | Education | Self_Employed | ApplicantIncome | CoapplicantIncome | LoanAmount | Loan_Amount_Term | Credit_History | Property_Area | Loan_Status | log_ApplicantIncome | log_CoapplicantIncome | log_LoanAmount | TotalIncome | DebtToIncomeRatio | z_score_TotalIncome | z_score_DebtToIncomeRatio |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LP001536 | Male | Yes | 3+ | Graduate | No | 39999 | 0 | 600 | 15 | Not existing | Semiurban | Yes | 10.596635 | 0.000000 | 6.398595 | 39999 | 0.0150004 | 5.105436 | -0.9899162 |
| LP001585 | Undefined | Yes | 3+ | Graduate | No | 51763 | 0 | 700 | 25 | Existing | Urban | Yes | 10.854450 | 0.000000 | 6.552508 | 51763 | 0.0135232 | 6.926865 | -1.1536874 |
| LP001637 | Male | Yes | 1 | Graduate | No | 33846 | 0 | 260 | 30 | Existing | Semiurban | No | 10.429606 | 0.000000 | 5.564520 | 33846 | 0.0076819 | 4.152762 | -1.8012896 |
| LP001640 | Male | Yes | 0 | Graduate | Yes | 39147 | 4750 | 120 | 30 | Existing | Semiurban | Yes | 10.575105 | 8.466110 | 4.795790 | 43897 | 0.0027337 | 5.708966 | -2.3498734 |
| LP002101 | Male | Yes | 0 | Graduate | Yes | 63337 | 0 | 490 | 15 | Existing | Urban | Yes | 11.056241 | 0.000000 | 6.196444 | 63337 | 0.0077364 | 8.718877 | -1.7952429 |
| LP002317 | Male | Yes | 3+ | Graduate | No | 81000 | 0 | 360 | 30 | Not existing | Rural | No | 11.302217 | 0.000000 | 5.888878 | 81000 | 0.0044444 | 11.453653 | -2.1602073 |
| LP002422 | Male | No | 1 | Graduate | No | 37719 | 0 | 152 | 30 | Existing | Semiurban | Yes | 10.537946 | 0.000000 | 5.030438 | 37719 | 0.0040298 | 4.752422 | -2.2061773 |
| LP002624 | Male | Yes | 0 | Graduate | No | 20833 | 6667 | 480 | 30 | Not existing | Urban | Yes | 9.944342 | 8.805075 | 6.175867 | 27500 | 0.0174545 | 3.170206 | -0.7178328 |
| LP002893 | Male | No | 0 | Graduate | No | 1836 | 33837 | 90 | 30 | Existing | Urban | No | 7.515889 | 10.429340 | 4.510859 | 35673 | 0.0025229 | 4.435638 | -2.3732390 |
| LP002949 | Female | No | 3+ | Graduate | Yes | 416 | 41667 | 350 | 15 | Not existing | Urban | No | 6.033086 | 10.637489 | 5.860786 | 42083 | 0.0083169 | 5.428103 | -1.7308850 |
kable(common_outliers_DebtToIncomeRatio, caption = "Wartości odstające wskaźnika zadłużenia w stosunku do dochodu") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
scroll_box(width = "100%", height = "auto")
| Loan_ID | Gender | Married | Dependents | Education | Self_Employed | ApplicantIncome | CoapplicantIncome | LoanAmount | Loan_Amount_Term | Credit_History | Property_Area | Loan_Status | log_ApplicantIncome | log_CoapplicantIncome | log_LoanAmount | TotalIncome | DebtToIncomeRatio | z_score_TotalIncome | z_score_DebtToIncomeRatio |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LP001267 | Female | Yes | 2 | Graduate | No | 1378 | 1881 | 167 | 30 | Existing | Urban | No | 7.229114 | 7.540090 | 5.123964 | 3259 | 0.0512427 | -0.5830471 | 3.028118 |
| LP001449 | Male | No | 0 | Graduate | No | 3865 | 1640 | 490 | 30 | Existing | Rural | Yes | 8.259976 | 7.403061 | 6.196444 | 5505 | 0.0890100 | -0.2352971 | 7.215215 |
| LP001722 | Male | Yes | 0 | Graduate | No | 150 | 1800 | 135 | 30 | Existing | Rural | No | 5.017280 | 7.496097 | 4.912655 | 1950 | 0.0692308 | -0.7857206 | 5.022377 |
| LP001751 | Male | Yes | 0 | Graduate | No | 3250 | 0 | 170 | 30 | Existing | Rural | No | 8.086718 | 0.000000 | 5.141664 | 3250 | 0.0523077 | -0.5844406 | 3.146187 |
| LP001846 | Female | No | 3+ | Graduate | No | 3083 | 0 | 255 | 30 | Existing | Rural | Yes | 8.033983 | 0.000000 | 5.545177 | 3083 | 0.0827116 | -0.6102973 | 6.516944 |
| LP001990 | Male | No | 0 | Not Graduate | No | 2000 | 0 | 128 | 30 | Existing | Urban | No | 7.601402 | 0.000000 | 4.859812 | 2000 | 0.0640000 | -0.7779790 | 4.442464 |
| LP002341 | Female | No | 1 | Graduate | No | 2600 | 0 | 160 | 30 | Existing | Urban | No | 7.863651 | 0.000000 | 5.081404 | 2600 | 0.0615385 | -0.6850806 | 4.169563 |
| LP002778 | Male | Yes | 2 | Graduate | Yes | 6633 | 0 | 350 | 30 | Not existing | Rural | No | 8.799963 | 0.000000 | 5.860786 | 6633 | 0.0527665 | -0.0606480 | 3.197050 |
Zmienna Dochód całkowity ma 10 wartości odstających, jednakże tak samo jak w przypadku zmiennych Dochód aplikanta oraz Dochód współaplikanta, są to osoby z wysokimi zarobkami więc postanwoiliśmy zostawić je bez zmian.
Zmienna Wskaźnik zadłużenia w stosunku do dochodu ma 8 wartości odstających, które jednak także zdecydowano pozostawić bez zmian ze względu na obawę utraty cennych informacji dotyczących podejmowania decyzji o przyznaniu kredytu.
dane <- dane %>%
mutate(
log_TotalIncome = log1p(TotalIncome),
log_DebtToIncomeRatio = log1p(DebtToIncomeRatio),
)
log_plot_vars <- c("TotalIncome", "DebtToIncomeRatio")
log_plot_list <- lapply(log_plot_vars, function(var) {
ggplot(dane, aes_string(x = var)) +
geom_histogram(fill = "#306591", color = "#0f225f", bins = 30) +
labs(title = paste("Rozkład", var), x = var, y = "Częstotliwość")
})
combined_plots <- log_plot_list %>%
do.call(cowplot::plot_grid, .)
combined_plots
write.csv(dane, "DanePoprawione.csv", row.names = FALSE)
kable(head(dane, 10), caption = "Dane") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
scroll_box(width = "100%", height = "auto")
| Loan_ID | Gender | Married | Dependents | Education | Self_Employed | ApplicantIncome | CoapplicantIncome | LoanAmount | Loan_Amount_Term | Credit_History | Property_Area | Loan_Status | log_ApplicantIncome | log_CoapplicantIncome | log_LoanAmount | TotalIncome | DebtToIncomeRatio | log_TotalIncome | log_DebtToIncomeRatio |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LP001002 | Male | No | 0 | Graduate | No | 5849 | 0 | 108 | 30 | Existing | Urban | Yes | 8.674197 | 0.000000 | 4.691348 | 5849 | 0.0184647 | 8.674197 | 0.0182963 |
| LP001003 | Male | Yes | 1 | Graduate | No | 4583 | 1508 | 128 | 30 | Existing | Rural | No | 8.430327 | 7.319203 | 4.859812 | 6091 | 0.0210146 | 8.714732 | 0.0207969 |
| LP001005 | Male | Yes | 0 | Graduate | Yes | 3000 | 0 | 66 | 30 | Existing | Urban | Yes | 8.006701 | 0.000000 | 4.204693 | 3000 | 0.0220000 | 8.006701 | 0.0217615 |
| LP001006 | Male | Yes | 0 | Not Graduate | No | 2583 | 2358 | 120 | 30 | Existing | Urban | Yes | 7.857094 | 7.765993 | 4.795790 | 4941 | 0.0242866 | 8.505525 | 0.0239964 |
| LP001008 | Male | No | 0 | Graduate | No | 6000 | 0 | 141 | 30 | Existing | Urban | Yes | 8.699681 | 0.000000 | 4.955827 | 6000 | 0.0235000 | 8.699681 | 0.0232281 |
| LP001011 | Male | Yes | 2 | Graduate | Yes | 5417 | 4196 | 267 | 30 | Existing | Urban | Yes | 8.597482 | 8.342125 | 5.590987 | 9613 | 0.0277749 | 9.170976 | 0.0273962 |
| LP001013 | Male | Yes | 0 | Not Graduate | No | 2333 | 1516 | 95 | 30 | Existing | Urban | Yes | 7.755339 | 7.324490 | 4.564348 | 3849 | 0.0246817 | 8.255828 | 0.0243821 |
| LP001014 | Male | Yes | 3+ | Graduate | No | 3036 | 2504 | 158 | 30 | Not existing | Semiurban | No | 8.018626 | 7.826044 | 5.068904 | 5540 | 0.0285199 | 8.619930 | 0.0281207 |
| LP001018 | Male | Yes | 2 | Graduate | No | 4006 | 1526 | 168 | 30 | Existing | Urban | Yes | 8.295798 | 7.331060 | 5.129899 | 5532 | 0.0303688 | 8.618485 | 0.0299168 |
| LP001020 | Male | Yes | 1 | Graduate | No | 12841 | 10968 | 349 | 30 | Existing | Semiurban | No | 9.460476 | 9.302828 | 5.857933 | 23809 | 0.0146583 | 10.077861 | 0.0145519 |
Autor: Mikołaj Zalewski
num_vars <- c("ApplicantIncome", "CoapplicantIncome", "LoanAmount", "TotalIncome", "DebtToIncomeRatio")
num_dane_long <- dane %>%
select(all_of(num_vars)) %>%
pivot_longer(cols = everything(), names_to = "Zmienne", values_to = "Wartość")
cat_vars <- c("Gender", "Married", "Dependents", "Education", "Self_Employed", "Loan_Amount_Term", "Credit_History", "Property_Area", "Loan_Status")
dane_cat_long <- dane %>%
select(all_of(cat_vars)) %>%
pivot_longer(cols = everything(), names_to = "Zmienna", values_to = "Kategoria")
colors <- c("#42cec2", "#306591", "#002185", "#0f225f", "#142c45")
colors2 <- rep(colors, times = 5)
ggplot(num_dane_long, aes(x = Wartość, fill = Zmienne)) +
geom_histogram(bins = 30, alpha = 0.7, color = "black") +
facet_wrap(~Zmienne, scales = "free") +
scale_fill_manual(values = colors) +
theme_minimal() +
theme(legend.position = "none") +
labs(title = "Histogramy zmiennych numerycznych", y = "Liczność")
ggplot(num_dane_long, aes(x = Zmienne, y = Wartość, fill = Zmienne)) +
geom_boxplot() +
facet_wrap(~Zmienne, scales = "free", ncol = 1) +
coord_flip() +
scale_fill_manual(values = colors) +
theme_minimal() +
theme(legend.position = "none") +
labs(title = "Boxploty zmiennych numerycznych")
summary_table <- sapply(dane[num_vars], summary)
summary_table <- as.data.frame(t(summary_table))
kable(summary_table, caption = "Statystyki opisowe zmiennych numerycznych") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Min. | 1st Qu. | Median | Mean | 3rd Qu. | Max. | |
|---|---|---|---|---|---|---|
| ApplicantIncome | 1.5000e+02 | 2.87750e+03 | 3.81250e+03 | 5403.4592834 | 5.79500e+03 | 8.1000e+04 |
| CoapplicantIncome | 0.0000e+00 | 0.00000e+00 | 1.18850e+03 | 1621.2457980 | 2.29725e+03 | 4.1667e+04 |
| LoanAmount | 9.0000e+00 | 1.00000e+02 | 1.27500e+02 | 146.4218241 | 1.68000e+02 | 7.0000e+02 |
| TotalIncome | 1.4420e+03 | 4.16600e+03 | 5.41650e+03 | 7024.7050814 | 7.52175e+03 | 8.1000e+04 |
| DebtToIncomeRatio | 2.5229e-03 | 1.90966e-02 | 2.41743e-02 | 0.0239293 | 2.84717e-02 | 8.9010e-02 |
Dochód wnioskodawcy pokazuje silną asymetrię prawostronną – większość dochodów jest stosunkowo niska, ale istnieje kilka bardzo wysokich wartości. Potwierdza to także średnia, która jest znacznie większa niż mediana. Znaczna część wartości dochodów współwnioskodawcy to zero (co oznacza, że wiele osób składało wniosek o kredyt samodzielnie lub współwnioskodawca nie ma żadnego dochodu). Kwota kredytu oraz całkowity dochód mają rozkłady podobne do dochodu wnioskodawcy – większość wartości jest stosunkowo niska, ale występują duże różnice. Wskaźnik zadłużenia do dochodu wskazuje na mocno skupione wartości, sugerując, że większość osób ma podobny stosunek zadłużenia do dochodu.
ggplot(dane_cat_long, aes(x = Kategoria, fill = Kategoria)) +
geom_bar() +
facet_wrap(~Zmienna, scales = "free") +
scale_fill_manual(values = colors2) +
theme_minimal() +
theme(legend.position = "none") +
labs(title = "Wykresy częstości dla zmiennych kategorycznych",
x = "Kategoria",
y = "Liczność")
Większość wnioskodawców to mężczyźni z wykształceniem wyższym w związku małżeńskim bez osób na utrzymaniu. Wnioskodawcy są dość równomiernie podzieleni między obszary: wiejski (Rural), pół-miejski (Semiurban) i miejski (Urban). Zdecydowana większość osób to pracownicy etatowi, a osoby samozatrudnione stanowią niewielki procent. Większość osób ma istniejącą historię kredytową i wybiera okres spłaty równy 360 miesięcy (30 lat). Większości osób kredyt został przyznany.
Autor: Dominika Szymczak
tabela <- table(dane$Loan_Status, dane$Gender)
df_table <- as.data.frame.matrix(tabela)
kable(df_table, caption = "Tabela krzyżowa: Status kredytu vs Płeć") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Male | Female | Undefined | |
|---|---|---|---|
| No | 150 | 37 | 5 |
| Yes | 339 | 75 | 8 |
mosaicplot(tabela, shade = TRUE, main = "Wykres Mozaikowy: Status kredytu vs Płeć")
ggplot(as.data.frame(tabela), aes(Var1, Var2, fill = Freq)) +
geom_tile() +
theme_minimal() +
labs(title = "Wykres Ilościowy: Status kredytu vs Płeć",
x = "Status kredytu", y = "Płeć", fill = "Liczność") +
wykres_gr
Wykres ilościowy przedstawia liczbę osób w poszczególnych kategoriach płci w podziale na status kredytu (No, Yes). Kolorystyka wskazuje liczność poszczególnych grup – im ciemniejszy kolor, tym większa liczba obserwacji. Najwięcej aplikacji kredytowych pochodzi od mężczyzn, co sugeruje, że są oni dominującą grupą w badanej próbie. Nie ma widocznych znaczących różnic między kategoriami Male i Female pod względem proporcji decyzji kredytowych – obie płcie wydają się być traktowane podobnie przez instytucję kredytową.
Wykres mozaikowy przedstawia proporcje między płcią a statusem kredytu. Każdy prostokąt odpowiada konkretnej kombinacji wartości (Male-Yes, Female-No itd.), a jego wielkość odzwierciedla liczność danej grupy. Wartości standaryzowanych reszt nie wskazują na istotne odchylenia od wartości oczekiwanych, co oznacza, że płeć prawdopodobnie nie ma istotnego wpływu na decyzję kredytową.
tabela <- table(dane$Loan_Status, dane$Married)
df_table <- as.data.frame.matrix(tabela)
kable(df_table, caption = "Tabela krzyżowa: Status kredytu vs Stan cywilny") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| No | Yes | Undefined | |
|---|---|---|---|
| No | 79 | 113 | 0 |
| Yes | 134 | 285 | 3 |
mosaicplot(tabela, shade = TRUE, main = "Wykres Mozaikowy: Status kredytu vs Stan cywilny")
ggplot(as.data.frame(tabela), aes(Var1, Var2, fill = Freq)) +
geom_tile() +
theme_minimal() +
labs(title = "Wykres Ilościowy: Status kredytu vs Stan cywilny",
x = "Status kredytu", y = "Stan cywilny", fill = "Liczność") +
wykres_gr
Wykres ilościowy przedstawia liczbę osób w poszczególnych kategoriach stanu cywilnego w podziale na status kredytu (No, Yes). Najwięcej aplikacji kredytowych pochodzi od ludzi w związach małżeńskim, co sugeruje, że są oni dominującą grupą w badanej próbie. Nie ma widocznych znaczących różnic między kategoriami stanu cywilnego pod względem proporcji decyzji kredytowych.
Wykres mozaikowy przedstawia proporcje między stanem cywilnym a statusem kredytu. Wartości standaryzowanych reszt nie wskazują na istotne odchylenia od wartości oczekiwanych, co oznacza, że stan cywilny prawdopodobnie nie ma istotnego wpływu na decyzję kredytową.
tabela <- table(dane$Loan_Status, dane$Dependents)
df_table <- as.data.frame.matrix(tabela)
kable(df_table, caption = "Tabela krzyżowa: Status kredytu vs Liczba osób zależnych finansowo") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| 0 | 1 | 2 | 3+ | |
|---|---|---|---|---|
| No | 113 | 36 | 25 | 18 |
| Yes | 247 | 66 | 76 | 33 |
mosaicplot(tabela, shade = TRUE, main = "Wykres Mozaikowy: Status kredytu vs Liczba osób zależnych finansowo")
ggplot(as.data.frame(tabela), aes(Var1, Var2, fill = Freq)) +
geom_tile() +
theme_minimal() +
labs(title = "Wykres Ilościowy: Status kredytu vs Liczba osób zależnych finansowo",
x = "Status kredytu", y = "Liczba osób zależnych finansowo", fill = "Liczność") +
wykres_gr
Wykres ilościowy przedstawia liczbę osób z określoną liczbą osób zależnych finansowo w podziale na status kredytu (No, Yes). Najwięcej aplikacji kredytowych pochodzi od osób bez osób zależnych finansowo, co sugeruje, że są oni dominującą grupą w badanej próbie.
Wykres mozaikowy przedstawia proporcje między liczbą osób zależnych finansowo a statusem kredytu. Wartości standaryzowanych reszt nie wskazują na istotne odchylenia od wartości oczekiwanych, co oznacza, że liczba osób zależnych finansowo prawdopodobnie nie ma istotnego wpływu na decyzję kredytową.
tabela <- table(dane$Loan_Status, dane$Education)
df_table <- as.data.frame.matrix(tabela)
kable(df_table, caption = "Tabela krzyżowa: Status kredytu vs Poziom edukacji") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Not Graduate | Graduate | |
|---|---|---|
| No | 52 | 140 |
| Yes | 82 | 340 |
mosaicplot(tabela, shade = TRUE, main = "Wykres Mozaikowy: Status kredytu vs Poziom edukacji")
ggplot(as.data.frame(tabela), aes(Var1, Var2, fill = Freq)) +
geom_tile() +
theme_minimal() +
labs(title = "Wykres Ilościowy: Status kredytu vs Poziom edukacji",
x = "Status kredytu", y = "Poziom edukacji", fill = "Liczność") +
wykres_gr
Wykres ilościowy przedstawia liczbę osób w poszczególnych kategoriach poziomu edukacji w podziale na status kredytu. Najwięcej aplikacji kredytowych pochodzi od osób z wykształceniem wyższym, co sugeruje, że są oni dominującą grupą w badanej próbie. Nie ma widocznych znaczących różnic między kategoriami pod względem proporcji decyzji kredytowych.
Wykres mozaikowy przedstawia proporcje między poziomem edukacji a statusem kredytu. Wartości standaryzowanych reszt nie wskazują na istotne odchylenia od wartości oczekiwanych, co oznacza, że poziom edukacji prawdopodobnie nie ma istotnego wpływu na decyzję kredytową.
tabela <- table(dane$Loan_Status, dane$Self_Employed)
df_table <- as.data.frame.matrix(tabela)
kable(df_table, caption = "Tabela krzyżowa: Status kredytu vs Samozatrudnienie") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| No | Yes | |
|---|---|---|
| No | 157 | 35 |
| Yes | 343 | 79 |
mosaicplot(tabela, shade = TRUE, main = "Wykres Mozaikowy: Status kredytu vs Samozatrudnienie")
ggplot(as.data.frame(tabela), aes(Var1, Var2, fill = Freq)) +
geom_tile() +
theme_minimal() +
labs(title = "Wykres Ilościowy: Status kredytu vs Samozatrudnienie",
x = "Status kredytu", y = "Samozatrudnienie", fill = "Liczność") +
wykres_gr
Wykres ilościowy przedstawia liczbę osób samozatrudnionych i nie w podziale na status kredytu. Najwięcej aplikacji kredytowych pochodzi od osób nie będących samozatrudnionymi, co sugeruje, że są oni dominującą grupą w badanej próbie. Nie ma widocznych znaczących różnic między kategoriami pod względem proporcji decyzji kredytowych.
Wykres mozaikowy przedstawia proporcje między byciem samozatrudnionym a statusem kredytu. Wartości standaryzowanych reszt nie wskazują na istotne odchylenia od wartości oczekiwanych, co oznacza, że samozatrudnienie prawdopodobnie nie ma istotnego wpływu na decyzję kredytową.
tabela <- table(dane$Loan_Status, dane$Loan_Amount_Term)
df_table <- as.data.frame.matrix(tabela)
kable(df_table, caption = "Tabela krzyżowa: Status kredytu vs Okres kredytowania") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| 1 | 3 | 5 | 7 | 10 | 15 | 20 | 25 | 30 | 40 | |
|---|---|---|---|---|---|---|---|---|---|---|
| No | 0 | 2 | 0 | 1 | 0 | 15 | 1 | 5 | 159 | 9 |
| Yes | 1 | 0 | 2 | 3 | 3 | 29 | 3 | 8 | 367 | 6 |
mosaicplot(tabela, shade = TRUE, main = "Wykres Mozaikowy: Status kredytu vs Okres kredytowania")
ggplot(as.data.frame(tabela), aes(Var1, Var2, fill = Freq)) +
geom_tile() +
theme_minimal() +
labs(title = "Wykres Ilościowy: Status kredytu vs Okres kredytowania",
x = "Status kredytu", y = "Okres kredytowania", fill = "Liczność") +
wykres_gr
Wykres ilościowy przedstawia liczbę osób w poszczególnych kategoriach okresu kredytowania w podziale na status kredytu. Najwięcej aplikacji kredytowych dotyczy okresu 30 lat, co sugeruje, że jest to dominujący okres kredytowania w badanej próbie.
Wykres mozaikowy przedstawia proporcje między okresem kredytowania a statusem kredytu. Wartości standaryzowanych reszt nie wskazują na istotne odchylenia od wartości oczekiwanych, co oznacza, że okres kredytowania prawdopodobnie nie ma istotnego wpływu na decyzję kredytową, jednak ze względu na dużą liczbę kategorii oraz małe częstości poszczególnych kategorii, wykres może wprowadzać w błąd.
tabela <- table(dane$Loan_Status, dane$Credit_History)
df_table <- as.data.frame.matrix(tabela)
kable(df_table, caption = "Tabela krzyżowa: Status kredytu vs Historia kredytowa") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Not existing | Existing | |
|---|---|---|
| No | 95 | 97 |
| Yes | 44 | 378 |
mosaicplot(tabela, shade = TRUE, main = "Wykres Mozaikowy: Status kredytu vs historia kredytowa")
ggplot(as.data.frame(tabela), aes(Var1, Var2, fill = Freq)) +
geom_tile() +
theme_minimal() +
labs(title = "Wykres Ilościowy: Status kredytu vs Historia kredytowa",
x = "Status kredytu", y = "Historia kredytowa", fill = "Liczność") +
wykres_gr
Wykres ilościowy przedstawia liczebność przypadków dla osób posiadających historię kredytową i nie oraz pokazuje, że są znaczące różnice między tymi kategoriami pod względem proporcji decyzji kredytowych.
Wykres mozaikowy przedstawia reszty standaryzowane (standardized residuals), które pokazują różnice między obserwowaną a oczekiwaną liczebnością w poszczególnych kategoriach. Kolor niebieski wskazuje, że w tych kategoriach liczba obserwacji jest większa, a kolor czerwony, że liczba obserwacji jest mniejsza niż oczekiwana. Wykres ten sugeruje więc, że historia kredytowa może mieć istotny wpływ na decyzję kredytową.
tabela <- table(dane$Loan_Status, dane$Property_Area)
df_table <- as.data.frame.matrix(tabela)
kable(df_table, caption = "Tabela krzyżowa: Status kredytu vs Położenie obiektu hipoteki") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Rural | Semiurban | Urban | |
|---|---|---|---|
| No | 69 | 54 | 69 |
| Yes | 110 | 179 | 133 |
mosaicplot(tabela, shade = TRUE, main = "Wykres Mozaikowy: Status kredytu vs Położenie obiektu hipoteki")
ggplot(as.data.frame(tabela), aes(Var1, Var2, fill = Freq)) +
geom_tile() +
theme_minimal() +
labs(title = "Wykres Ilościowy: Status kredytu vs Położenie obiektu hipoteki",
x = "Status kredytu", y = "Położenie obiektu hipoteki", fill = "Liczność") +
wykres_gr
Wykres ilościowy przedstawia liczebność przypadków dla różnych kategorii położenia obiektu hipoteki i pokazuje, że występują różnice między tymi kategoriami pod względem proporcji decyzji kredytowych.
Wykres mozaikowy przedstawia reszty standaryzowane (standardized residuals), które pokazują różnice między obserwowaną a oczekiwaną liczebnością w poszczególnych kategoriach. Kolor czerwony wskazuje, że liczba obserwacji jest mniejsza niż oczekiwana. Wykres ten sugeruje więc, że położenie obiektu hipoteki kredytowa może mieć statystycznie istotny wpływ na decyzję kredytową.
wykres1 <- ggplot(dane, aes(x = Loan_Status, y = log_ApplicantIncome, fill = Loan_Status)) +
geom_boxplot(alpha = 0.7) +
scale_fill_manual(values = c("No" = "#42cec2", "Yes" = "#002185")) +
labs(title = "Klasyczny wykres pudełkowy", x = "Status kredytu", y = "Dochody aplikanta") +
theme_minimal()
wykres2 <- ggplot(dane, aes(x = Loan_Status, y = log_ApplicantIncome, fill = Loan_Status)) +
geom_jitter(aes(color = Loan_Status), width = 0.2, height = 0, alpha = 0.6) +
geom_boxplot(alpha = 0.5, outlier.shape = NA) +
scale_fill_manual(values = c("No" = "#42cec2", "Yes" = "#002185")) +
scale_color_manual(values = c("No" = "#002246", "Yes" = "#002246")) +
labs(title = "Boxplot z rzeczywistymi danymi",
x = "Status kredytu",
y = "Dochody aplikanta") +
theme_minimal()
wykres1 + wykres2 + plot_layout(ncol = 2)
Na klasycznym wykresie pudełkowym można zauważyć, że dochody osób, którym przyznano kredyt, są podobne do dochodów osób, którym go odmówiono – nie ma wyraźnej różnicy w medianie i rozstępie kwartylowym.
Boxplot z rzeczywistymi danymi jest klasycznym wykresem pudełkowym wzbogaconym o rzeczywiste dane w postaci kropek, dzięki czemu można zobaczyć rzeczywisty rozkład dochodów, a nie tylko statystyki opisowe. Widać, że rozkład dochodów jest zbliżony dla obu grup, co potwierdza brak wyraźnego związku między wysokością dochodów a przyznaniem kredytu. W obu grupach występują wartości odstające, ale ich liczba i zakres są podobne.
wykres1 <- ggplot(dane, aes(x = Loan_Status, y = log_LoanAmount, fill = Loan_Status)) +
geom_boxplot(alpha = 0.7) +
scale_fill_manual(values = c("No" = "#42cec2", "Yes" = "#002185")) +
labs(title = "Klasyczny wykres pudełkowy", x = "Status kredytu", y = "Kwota kredytu") +
theme_minimal()
wykres2 <- ggplot(dane, aes(x = Loan_Status, y = log_LoanAmount, fill = Loan_Status)) +
geom_jitter(aes(color = Loan_Status), width = 0.2, height = 0, alpha = 0.6) +
geom_boxplot(alpha = 0.5, outlier.shape = NA) +
scale_fill_manual(values = c("No" = "#42cec2", "Yes" = "#002185")) +
scale_color_manual(values = c("No" = "#002246", "Yes" = "#002246")) +
labs(title = "Boxplot z rzeczywistymi danymi",
x = "Status kredytu",
y = "Kwota kredytu") +
theme_minimal()
wykres1 + wykres2 + plot_layout(ncol = 2)
Na klasycznym wykresie pudełkowym można zauważyć, że kwoty kredytów, które zostały przyznane, są podobne do kwot kredytów, które nie zostały przyznane – nie ma wyraźnej różnicy w medianie i rozstępie kwartylowym.
Boxplot z rzeczywistymi danymi pokazuje, że rozkład kwot kredytów jest zbliżony dla obu grup, co potwierdza brak wyraźnego związku między kwotą kredytu a przyznaniem kredytu.
wykres1 <- ggplot(dane, aes(x = Loan_Status, y = log_TotalIncome, fill = Loan_Status)) +
geom_boxplot(alpha = 0.7) +
scale_fill_manual(values = c("No" = "#42cec2", "Yes" = "#002185")) +
labs(title = "Klasyczny wykres pudełkowy", x = "Status kredytu", y = "Dochód całkowity") +
theme_minimal()
wykres2 <- ggplot(dane, aes(x = Loan_Status, y = log_TotalIncome, fill = Loan_Status)) +
geom_jitter(aes(color = Loan_Status), width = 0.2, height = 0, alpha = 0.6) +
geom_boxplot(alpha = 0.5, outlier.shape = NA) +
scale_fill_manual(values = c("No" = "#42cec2", "Yes" = "#002185")) +
scale_color_manual(values = c("No" = "#002246", "Yes" = "#002246")) +
labs(title = "Boxplot z rzeczywistymi danymi",
x = "Status kredytu",
y = "Dochód całkowity") +
theme_minimal()
wykres1 + wykres2 + plot_layout(ncol = 2)
Na klasycznym wykresie pudełkowym można zauważyć, że dochody całkowite osób, którym przyznano kredyt, są podobne do dochodów całkowitych osób, którym zostały on odmówiony – nie ma wyraźnej różnicy w medianie i rozstępie kwartylowym.
Boxplot z rzeczywistymi danymi pokazuje, że rozkład dochodów całkowitych jest zbliżony dla obu grup, co potwierdza brak wyraźnego związku między wysokością dochodów a przyznaniem kredytu. Logika jednak podpowiada, że zależność taka powinna występować.
wykres1 <- ggplot(dane, aes(x = Loan_Status, y = log_DebtToIncomeRatio, fill = Loan_Status)) +
geom_boxplot(alpha = 0.7) +
scale_fill_manual(values = c("No" = "#42cec2", "Yes" = "#002185")) +
labs(title = "Klasyczny wykres pudełkowy", x = "Status kredytu", y = "Wskaźnik zadłużenia w stosunku do dochodu") +
theme_minimal()
wykres2 <- ggplot(dane, aes(x = Loan_Status, y = log_DebtToIncomeRatio, fill = Loan_Status)) +
geom_jitter(aes(color = Loan_Status), width = 0.2, height = 0, alpha = 0.6) +
geom_boxplot(alpha = 0.5, outlier.shape = NA) +
scale_fill_manual(values = c("No" = "#42cec2", "Yes" = "#002185")) +
scale_color_manual(values = c("No" = "#002246", "Yes" = "#002246")) +
labs(title = "Boxplot z rzeczywistymi danymi",
x = "Status kredytu",
y = "Wskaźnik zadłużenia w stosunku do dochodu") +
theme_minimal()
wykres1 + wykres2 + plot_layout(ncol = 2)
Na klasycznym wykresie pudełkowym można zauważyć, że wskaźnik zadłużenia w stosunku do dochodów osób, którym przyznano kredyt, są podobne do takiego wskaźnika osób, którym zostały on odmówiony – nie ma wyraźnej różnicy w medianie i rozstępie kwartylowym.
Boxplot z rzeczywistymi danymi pokazuje, że rozkład wskaźników zadłużenia w stosunku do dochodów jest zbliżony dla obu grup, co potwierdza brak wyraźnego związku między tą zmienną a przyznaniem kredytu. Logika jednak podpowiada, że zależność taka powinna występować.
Autor: Julia Sowińska
Dla wszystkich postawionych hipotez, przyjmuje się poziom istotności alpha w wysokości 0,05 (5%).
H₀: Prawdopodobieństwo przyznania kredytu (Loan_Status) jest niezależne od posiadania historii kredytowej (Credit_History).
H₁: Prawdopodobieństwo przyznania kredytu różni się w zależności od posiadania historii kredytowej.
h <- table(dane$Loan_Status, dane$Credit_History)
kable(as.data.frame.matrix(h), caption = "Tabela krzyżowa: Status kredytu vs Historia kredytowa") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Not existing | Existing | |
|---|---|---|
| No | 95 | 97 |
| Yes | 44 | 378 |
Założenie o minimalnej liczbie 5 obserwacji w każdej komórce tabeli kontyngencji (założenie testu chi-kwadrat), jest spełnione, dlatego zostanie wykorzystany test Chi-kwadrat.
chi_kwadrat <- chisq.test(h)
print(chi_kwadrat)
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: h
## X-squared = 112.7, df = 1, p-value < 2.2e-16
P-value jest mniejsze niż przyjęty poziom istotności, co pozwala odrzucić hipotezę zerową i przyjąć hipotezę alternatywną o istnieniu zależności między statusem kredytu a historią kredytowania.
n <- sum(h)
phi_cramer <- sqrt(chi_kwadrat$statistic / (n * (min(dim(h)) - 1)))
names(phi_cramer) <- "Cramer's V"
print(phi_cramer)
## Cramer's V
## 0.4284189
Współczynnik Cramera przyjmuje wartość w przybliżeniu 0,428, co świadczy o umiarkowanym związku między zmiennymi Loan_Status i Credit_History.
ggbarstats(data = dane, x = Credit_History, y = Loan_Status, xlab = "Status kredytu", legend.title = "Historia kredytowa", package = "Redmonder", palette = "qMSOBu")
Wykres przedstawia zależność między posiadaniem historii kredytowej a przyznaniem kredytu. Posiadanie historii kredytowej znacznie zwiększa szanse na uzyskanie kredytu, co sugeruje, że instytucje finansowe silnie uwzględniają ten czynnik w ocenie ryzyka kredytowego.
H₀: Okres kredytowania (Loan_Amount_Term) nie wpływa na decyzję o przyznaniu kredytu.
H₁: Okres kredytowania wpływa na decyzję o przyznaniu kredytu.
h <- table(dane$Loan_Status, dane$Loan_Amount_Term)
kable(as.data.frame.matrix(h), caption = "Tabela krzyżowa: Status kredytu vs Okres kredytowania") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| 1 | 3 | 5 | 7 | 10 | 15 | 20 | 25 | 30 | 40 | |
|---|---|---|---|---|---|---|---|---|---|---|
| No | 0 | 2 | 0 | 1 | 0 | 15 | 1 | 5 | 159 | 9 |
| Yes | 1 | 0 | 2 | 3 | 3 | 29 | 3 | 8 | 367 | 6 |
Założenie o minimalnej liczbie 5 oczekiwanych obserwacji w każdej komórce tabeli kontyngencji (założenie testu chi-kwadrat), nie jest spełnione, więc wykorzystany zostanie test Fishera.
fisher_test <- fisher.test(h)
print(fisher_test)
##
## Fisher's Exact Test for Count Data
##
## data: h
## p-value = 0.1446
## alternative hypothesis: two.sided
P-value jest większe niż przyjęty poziom istotności, co oznacza brak podstaw do odrzucenia hipotezy zerowej o braku zależności między statusem a czasem trwania kredytu.
ggbarstats(data = dane, x = Loan_Amount_Term, y = Loan_Status, test = "fisher", xlab = "Status kredytu", legend.title = "Okres kredytowania", package = "Redmonder", palette = "qMSOBu")
## Number of labels is greater than default palette color count.
## • Select another color `palette` (and/or `package`).
Wykres przedstawia brak zależności między wybranym okresem kredytowania a przyznaniem kredytu.
H₀: Położenie obiektu hipoteki (Property_Area) nie wpływa na decyzję o przyznaniu kredytu.
H₁: Położenie obiektu hipoteki wpływa na decyzję o przyznaniu kredytu.
h <- table(dane$Loan_Status, dane$Property_Area)
kable(as.data.frame.matrix(h), caption = "Tabela krzyżowa: Status kredytu vs Położenie obiektu hipoteki") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Rural | Semiurban | Urban | |
|---|---|---|---|
| No | 69 | 54 | 69 |
| Yes | 110 | 179 | 133 |
Założenie o minimalnej liczbie 5 oczekiwanych obserwacji w każdej komórce tabeli kontyngencji (założenie testu chi-kwadrat), jest spełnione, dlatego zostanie wykorzystany test Chi-kwadrat.
chi_kwadrat <- chisq.test(h)
print(chi_kwadrat)
##
## Pearson's Chi-squared test
##
## data: h
## X-squared = 12.298, df = 2, p-value = 0.002136
P-value jest mniejsze niż przyjęty poziom istotności, co pozwala odrzucić hipotezę zerową i przyjąć hipotezę alternatywną o istnieniu zależności między statusem kredytu a położeniem obiektu hipoteki.
n <- sum(h)
phi_cramer <- sqrt(chi_kwadrat$statistic / (n * (min(dim(h)) - 1)))
names(phi_cramer) <- "Cramer's V"
print(phi_cramer)
## Cramer's V
## 0.1415228
Współczynnik Cramera przyjmuje wartość w przybliżeniu 0,142, co świadczy o słabym związku między statusem kredytu a położeniem obiektu hipoteki.
ggbarstats(data = dane, x = Property_Area, y = Loan_Status, xlab = "Status kredytu", legend.title = "Położenie obiektu hipoteki", package = "Redmonder", palette = "qMSOBu")
Wykres przedstawia zależność między położeniem obiektu hipoteki a przyznaniem kredytu. Położenie obiektu hipoteki w obszarze pół-miejskim znacznie zwiększa szanse na uzyskanie kredytu.
H₀: Średni wskaźnik zadłużenia w stosunku do dochodu (DebtToIncomeRatio) nie różni się między grupami, którym przyznano i nie przyznano kredytu.
H₁: Średni wskaźnik zadłużenia w stosunku do dochodu różni się między grupami, którym przyznano i nie przyznano kredytu.
group_yes <- dane$log_DebtToIncomeRatio[dane$Loan_Status == "Yes"]
group_no <- dane$log_DebtToIncomeRatio[dane$Loan_Status == "No"]
shapiro_yes <- shapiro.test(group_yes)
shapiro_no <- shapiro.test(group_no)
cat("Grupa, której przyznano kredyt: W =", shapiro_yes$statistic, ", p =", shapiro_yes$p.value, "\n")
## Grupa, której przyznano kredyt: W = 0.8784788 , p = 1.056006e-17
cat("Grupa, której nie przyznano kredytu: W =", shapiro_no$statistic, ", p =", shapiro_no$p.value, "\n")
## Grupa, której nie przyznano kredytu: W = 0.931256 , p = 7.070887e-08
bartlett_test <- bartlett.test(DebtToIncomeRatio ~ Loan_Status, data = dane)
print(bartlett_test)
##
## Bartlett test of homogeneity of variances
##
## data: DebtToIncomeRatio by Loan_Status
## Bartlett's K-squared = 11.996, df = 1, p-value = 0.0005331
Zarówno założenie o normalności rozkładu zmiennej reprezentującej wskaźnik zadłużenia w stosunku do dochodu w każdej z grup statusu kredytu (Yes/No), jak i założenie o jednorodności wariancji nie zostały spełnione, dlatego zamiast testu t-Studenta, stosowany będzie test U Manna-Whitneya.
mannwhitney <- wilcox.test(log_DebtToIncomeRatio ~ Loan_Status, data = dane)
print(mannwhitney)
##
## Wilcoxon rank sum test with continuity correction
##
## data: log_DebtToIncomeRatio by Loan_Status
## W = 42182, p-value = 0.4126
## alternative hypothesis: true location shift is not equal to 0
P-value jest większe niż przyjęty poziom istotności, co oznacza brak podstaw do odrzucenia hipotezy zerowej o braku zależności między statusem kredytu a Wskaźnikiem zadłużenia w stosunku do dochodu.
H₀: Średni całkowity dochód (TotalIncome) nie różni się między grupami, którym przyznano i nie przyznano kredytu.
H₁: Średni całkowity dochód różni się między grupami, którym przyznano i nie przyznano kredytu.
group_yes <- dane$log_TotalIncome[dane$Loan_Status == "Yes"]
group_no <- dane$log_TotalIncome[dane$Loan_Status == "No"]
shapiro_yes <- shapiro.test(group_yes)
shapiro_no <- shapiro.test(group_no)
cat("Grupa, której przyznano kredyt: W =", shapiro_yes$statistic, ", p =", shapiro_yes$p.value, "\n")
## Grupa, której przyznano kredyt: W = 0.9379443 , p = 2.902198e-12
cat("Grupa, której nie przyznano kredytu: W =", shapiro_no$statistic, ", p =", shapiro_no$p.value, "\n")
## Grupa, której nie przyznano kredytu: W = 0.9505776 , p = 3.307429e-06
bartlett_test <- bartlett.test(log_TotalIncome ~ Loan_Status, data = dane)
print(bartlett_test)
##
## Bartlett test of homogeneity of variances
##
## data: log_TotalIncome by Loan_Status
## Bartlett's K-squared = 8.2715, df = 1, p-value = 0.004027
Zarówno założenie o normalności rozkładu całkowitego dochodu w każdej z grup Loan_Status (Yes/No), jak i założenie o jednorodności wariancji nie zostały spełnione, dlatego zamiast testu t-Studenta, stosowany będzie test U Manna-Whitneya.
mannwhitney <- wilcox.test(log_TotalIncome ~ Loan_Status, data = dane)
print(mannwhitney)
##
## Wilcoxon rank sum test with continuity correction
##
## data: log_TotalIncome by Loan_Status
## W = 39762, p-value = 0.7128
## alternative hypothesis: true location shift is not equal to 0
P-value jest większe niż przyjęty poziom istotności, co oznacza brak podstaw do odrzucenia hipotezy zerowej o braku zależności między statusem kredytu a Dochodem całkowitym.
Zależność zmiennych dotyczących posiadania Historii kredytowej oraz Położenia obiektu hipoteki ze zmienną dotyczącą Przyznania kredytu zostały uznane za istotne.
Autor: Mikołaj Zalewski
dane$Group <- paste(dane$Property_Area, dane$Credit_History, sep = "_")
dane$Group <- factor(dane$Group,
levels = c("Urban_Existing", "Semiurban_Existing", "Rural_Existing", "Urban_Not existing", "Semiurban_Not existing", "Rural_Not existing"),
labels = c("Urban_Existing", "Semiurban_Existing", "Rural_Existing", "Urban_Not existing", "Semiurban_Not existing", "Rural_Not existing"))
statystyki <- dane %>%
group_by(Group) %>%
summarise(
Liczba_osob = n(),
Procent_mezczyzn = (sum(Gender == "Male", na.rm = TRUE) / Liczba_osob) * 100,
Procent_married = (sum(Married == "Yes", na.rm = TRUE) / Liczba_osob) * 100,
Procent_Graduate = (sum(Education == "Graduate", na.rm = TRUE) / Liczba_osob) * 100,
Srednia_TotalIncome = mean(TotalIncome, na.rm = TRUE)
)
kable(statystyki, caption = "Porównanie grup aplikantów") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Group | Liczba_osob | Procent_mezczyzn | Procent_married | Procent_Graduate | Srednia_TotalIncome |
|---|---|---|---|---|---|
| Urban_Existing | 151 | 84.10596 | 65.56291 | 83.44371 | 7024.568 |
| Semiurban_Existing | 187 | 75.40107 | 64.70588 | 81.81818 | 6874.668 |
| Rural_Existing | 137 | 83.21168 | 62.04380 | 73.72263 | 6987.198 |
| Urban_Not existing | 51 | 76.47059 | 62.74510 | 70.58824 | 7381.157 |
| Semiurban_Not existing | 46 | 67.39130 | 65.21739 | 73.91304 | 6559.239 |
| Rural_Not existing | 42 | 88.09524 | 73.80952 | 71.42857 | 7892.524 |
Tabela pokazuje, jak podobne pod względem innych zmiennych są poszczególne grupy.
proporcje_loan_status <- dane %>%
group_by(Group, Loan_Status) %>%
summarise(Liczba = n(), .groups = "drop") %>%
group_by(Group) %>%
mutate(Proporcja = Liczba / sum(Liczba) * 100)
ggplot(proporcje_loan_status, aes(x = "", y = Proporcja, fill = Loan_Status)) +
geom_bar(stat = "identity", width = 1) +
coord_polar(theta = "y") +
facet_wrap(~ Group) +
theme_void() +
labs(title = "Proporcja osób, które otrzymały kredyt w każdej grupie") +
scale_fill_manual(values = c("#42cec2", "#306591")) +
geom_text(aes(label = paste0(round(Proporcja, 1), "%")), position = position_stack(vjust = 0.5), color = "#142c45")
Autor: Julia Sowińska
dane$Loan_Status_Binary <- ifelse(dane$Loan_Status == "Yes", 1, 0)
set.seed(123)
train_idx <- sample(1:nrow(dane), 0.7 * nrow(dane))
train <- dane[train_idx, ]
test <- dane[-train_idx, ]
Dane zostały podzielona na dwa zbiory - treningowy i testowy, by uniknąć przeuczenia (overfittingu) oraz zapewnić rzetelną ocenę modelu poprzez testowanie modelu na danych, których nie widział podczas treningu. Zdecydowano się na podział: 70% danych do treningu i 30% danych do testu.
model <- glm(Loan_Status_Binary ~ Credit_History + Property_Area, data = train, family = "binomial")
summary(model)
##
## Call:
## glm(formula = Loan_Status_Binary ~ Credit_History + Property_Area,
## family = "binomial", data = train)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.2094 0.2883 -4.194 2.74e-05 ***
## Credit_HistoryExisting 2.2742 0.2628 8.654 < 2e-16 ***
## Property_AreaSemiurban 0.6164 0.2873 2.146 0.0319 *
## Property_AreaUrban 0.2834 0.2873 0.986 0.3241
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 537.43 on 428 degrees of freedom
## Residual deviance: 448.08 on 425 degrees of freedom
## AIC: 456.08
##
## Number of Fisher Scoring iterations: 4
Zbudowany został model regresji logistycznej (logit), który był naturalnym wyborem dla problemu klasyfikacji binarnej, jakim było przyznanie bądź nieprzyznanie kredytu. Model ten został wybrany ze względu na jego prostotę, szybkość i efektywność, a także ze względu na łatwiejszą interpretację. Jest to model predykcyjny, zatem zdecydowano się na pozostawienie w nim wszystkich zmiennych bez względu na istotność statystyczną.
predictions <- predict(model, newdata = test, type = "response")
predicted_classes <- ifelse(predictions > 0.5, "Yes", "No")
confusion_matrix <- table(Predicted = predicted_classes, Actual = test$Loan_Status)
confusion_matrix_df <- as.data.frame(confusion_matrix)
ggplot(confusion_matrix_df, aes(Actual, Predicted, fill = Freq)) +
geom_tile() +
theme_minimal() +
labs(x = "Rzeczywista klasa", y = "Przewidywana klasa", fill = "Liczba") +
wykres_gr
Wykres przedstawia tablicę kontyngencji i pokazuję, że prognozy dotyczące przyznania kredytu (rzeczywisty Credit_Status == “Yes) były dużo bardziej trafne, niż te dotyczące nie przyznania kredytu, co może sugerować, że model powinien obejmować jeszcze inne zmienne.
accuracy <- sum(diag(confusion_matrix)) / sum(confusion_matrix)
cat("Dokładność:", accuracy, "\n")
## Dokładność: 0.7567568
precision <- confusion_matrix["Yes", "Yes"] / (confusion_matrix["Yes", "Yes"] + confusion_matrix["No", "Yes"])
cat("Precyzja:", precision, "\n")
## Precyzja: 0.8846154
recall <- confusion_matrix["Yes", "Yes"] / (confusion_matrix["Yes", "Yes"] + confusion_matrix["Yes", "No"])
cat("Czułość:", recall, "\n")
## Czułość: 0.7931034
f1_score <- 2 * (precision * recall) / (precision + recall)
cat("F1-score:", f1_score, "\n")
## F1-score: 0.8363636
Model prawidłowo klasyfikuje około 75,68% przypadków. Około 88,46% przewidywań przyznania kredytu jest prawidłowe i około 79,31% rzeczywistych przyznań kredytu zostało poprawnie wykrytych. F1-score wynosi około 0,84, co oznacza, że model jest dobrze wyważony między precyzją a czułością.
roc_curve <- roc(test$Loan_Status, predictions)
## Setting levels: control = No, case = Yes
## Setting direction: controls < cases
plot(roc_curve, col = "#002185")
auc(roc_curve)
## Area under the curve: 0.7614
AUC przyjmuje wartość 0,7614, co oznacza, że model jest przyzwoity.
Autor: Julia Sowińska
Analiza danych kredytowych ujawniła kilka istotnych wzorców dotyczących decyzji kredytowych oraz czynników mogących wpływać na ich przyznawanie. Najważniejszym czynnikiem wpływającym na decyzję kredytową jest posiadanie historii kredytowej, co sugeruje, że instytucje finansowe w dużym stopniu opierają się na wcześniejszych zobowiązaniach klienta przy ocenie jego wiarygodności. Położenie obiektu hipoteki może również wpływać na decyzję, ale w mniejszym stopniu. Pozostałe zmienne, takie jak dochody, wskaźnik zadłużenia czy poziom edukacji, nie wykazują istotnych zależności. Wyniki analizy dostarczają istotnych informacji dla instytucji kredytowych, które mogą pozwolić na automatyzację procesu podejmowania decyzji o przyznaniu lub nieprzyznaniu kredytu hipotecznego.