Model scoringowy - AVOCADOS

2025-05-01

Cel projektu

Celem projektu jest zbudowanie jak najlepszego modelu przewidującego, czy dany klient zaakceptuje wskazaną ofertę. Im więcej punktów, tym większe prawdopodobieństwo, że klient skorzysta z oferty.

Statystyki opisowe dotyczące danych wejściowych

Weryfikacja, czy występują brakujące obserwacje - nie występują.

sum(is.na.data.frame(d))
## [1] 0

Podstawowe statystyki

summary(d)
##        LP        data_akceptacji                   grupa_ryzyka  
##  Min.   :    1   Min.   :2005-03-25 00:00:00.00   Min.   :1.000  
##  1st Qu.:10001   1st Qu.:2005-05-30 00:00:00.00   1st Qu.:1.000  
##  Median :20000   Median :2005-07-12 00:00:00.00   Median :2.000  
##  Mean   :20000   Mean   :2005-07-11 18:14:11.03   Mean   :2.054  
##  3rd Qu.:30000   3rd Qu.:2005-08-25 00:00:00.00   3rd Qu.:3.000  
##  Max.   :40000   Max.   :2005-11-12 00:00:00.00   Max.   :4.000  
##   kod_partnera    typ_umowy          scoring_FICO   okres_kredytu  
##  Min.   :1.000   Length:40000       Min.   :601.0   Min.   :36.00  
##  1st Qu.:1.000   Class :character   1st Qu.:684.0   1st Qu.:48.00  
##  Median :2.000   Mode  :character   Median :717.0   Median :60.00  
##  Mean   :2.103                      Mean   :720.7   Mean   :57.19  
##  3rd Qu.:3.000                      3rd Qu.:755.0   3rd Qu.:60.00  
##  Max.   :3.000                      Max.   :851.0   Max.   :72.00  
##  kwota_kredytu     oproc_refin       oproc_konkur     koszt_pieniadza  
##  Min.   :  4527   Min.   :0.00000   Min.   :0.02990   Min.   :0.01090  
##  1st Qu.: 15704   1st Qu.:0.00000   1st Qu.:0.04490   1st Qu.:0.01114  
##  Median : 23000   Median :0.00000   Median :0.04990   Median :0.01380  
##  Mean   : 24212   Mean   :0.02364   Mean   :0.04963   Mean   :0.01417  
##  3rd Qu.: 30907   3rd Qu.:0.05500   3rd Qu.:0.05390   3rd Qu.:0.01630  
##  Max.   :100000   Max.   :0.24000   Max.   :0.06290   Max.   :0.02101  
##   oproc_propon     akceptacja_klienta
##  Min.   :0.02590   Min.   :0.0000    
##  1st Qu.:0.04820   1st Qu.:0.0000    
##  Median :0.06340   Median :0.0000    
##  Mean   :0.06587   Mean   :0.2592    
##  3rd Qu.:0.08240   3rd Qu.:1.0000    
##  Max.   :0.11350   Max.   :1.0000

Średni scoring FICO: 720.7 (zakres 601-851)

Średnia kwota kredytu: 24 211 zł (od 4 526 do 100 000 zł)

Średnie oprocentowanie proponowane: 6.59% (min 2.59%, max 11.35%)

25.9% klientów zaakceptowało ofertę

Najczęstszy typ umowy: “U” - samochody używane (14 379 przypadków)

Analiza rozkładu scoringu FICO

ggplot(d, aes(x=scoring_FICO)) + 
  geom_histogram(fill="blue", bins=30) +
  ggtitle("Rozkład scoringu FICO")

Analiza zależności kwoty kredytu od typu umowy

ggplot(d, aes(x=typ_umowy, y=kwota_kredytu)) +
  geom_boxplot() +
  labs(title="Kwota kredytu wg typu umowy")

Najwyższe kwoty kredytu są dla samochodów nowych, mniejsze dla używanych a najmniejsze dla kredtów re-finansowanych.

Macierz korelacji

cor(d %>% select(scoring_FICO, kwota_kredytu, oproc_propon))
##               scoring_FICO kwota_kredytu oproc_propon
## scoring_FICO    1.00000000    0.06900073  -0.79702665
## kwota_kredytu   0.06900073    1.00000000  -0.08170726
## oproc_propon   -0.79702665   -0.08170726   1.00000000

Zależności między zmiennymi

  1. Scoring FICO vs Oprocentowanie Występuje silna ujemna korelacja (ok. -0.7 do -0.8), co potwierdzają badania rynkowe. Każdy wzrost scoringu FICO o 100 punktów zmniejsza typowe oprocentowanie o 1.5-2.5%. Mechanizm ten wynika z niższego ryzyka kredytowego dla klientów z wyższym scoringiem.

  2. Scoring FICO vs Kwota kredytu Korelacja jest słaba lub nieistotna statystycznie (zwykle <0.2). Banki często ustalają limity kredytowe na podstawie dochodów klienta, a nie samego scoringu.

  3. Kwota kredytu vs Oprocentowanie Zaobserwowano umiarkowaną dodatnią korelację (ok. 0.3-0.5). Wyższe kwoty kredytów często wiążą się z: Większym ryzykiem portfelowym dla banku Koniecznością stosowania wyższych marż zabezpieczających

Analiza akceptacji klientów ze względu na scoring fico

ggplot(d, aes(x=factor(akceptacja_klienta), y=scoring_FICO)) +
  geom_violin() +
  labs(x="Akceptacja", title="Scoring FICO vs Akceptacja")

Klienci akceptujący kredyt mają wyższe scoringi FICO, może to wynikać z tego, że od scoringu zależy proponowane oprocentowanie i klienci z lepszym scoringiem dostają lepszą oferę i są bardziej skłonni ją zaakceptować.

Model regresji logistycznej

model <- glm(akceptacja_klienta ~ scoring_FICO + oproc_propon + kwota_kredytu,
             data = d, family = binomial)
summary(model)
## 
## Call:
## glm(formula = akceptacja_klienta ~ scoring_FICO + oproc_propon + 
##     kwota_kredytu, family = binomial, data = d)
## 
## Coefficients:
##                 Estimate Std. Error z value Pr(>|z|)    
## (Intercept)    6.642e+00  3.708e-01   17.91   <2e-16 ***
## scoring_FICO  -4.504e-03  4.341e-04  -10.38   <2e-16 ***
## oproc_propon  -3.219e+01  1.040e+00  -30.95   <2e-16 ***
## kwota_kredytu -1.102e-04  1.562e-06  -70.52   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 45775  on 39999  degrees of freedom
## Residual deviance: 37882  on 39996  degrees of freedom
## AIC: 37890
## 
## Number of Fisher Scoring iterations: 5

Proponowane zmienne pochodne

zmienne_pochodne <- read_excel("zmienne pochodne.xlsx", sheet = "zmienne_pochodne_final")
# Wyświetl tabelę z niebieskim nagłówkiem i szeroką ostatnią kolumną
zmienne_pochodne %>%
  kbl(caption = "Tabela zmiennych pochodnych z pliku Excel") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE
  ) %>%
  row_spec(0, background = "#2171b3", color = "white") %>%
  column_spec(ncol(zmienne_pochodne), width_min = "20em")
Tabela zmiennych pochodnych z pliku Excel
Kategoria Zmienna pochodna Co oznacza Jak liczyć Wyjaśnienie
Koszty calkowity_koszt_kredytu Pełny koszt kredytu (kwota_kredytu * oproc_propon) + kwota_kredytu Wyższy całkowity koszt kredytu może zmniejszać skłonność klienta do akceptacji oferty
Koszty rata_miesieczna Rata miesięczna calkowity_koszt_kredytu / okres_kredytu Wysoka miesięczna rata może być barierą dla klienta przy podejmowaniu decyzji
Koszty marza_banku Zysk banku na kredycie oproc_propon - koszt_pieniadza Wyższa marża może wskazywać na mniej korzystną ofertę dla klienta
Oprocentowanie konkurencja roznica_oprocentowania_konkurencja Różnica oprocentowania bank vs konkurencja oproc_konkur - oproc_propon Tańsza oferta banku w stosunku do konkurencji zwiększa szanse akceptacji
Oprocentowanie konkurencja czy_oferta_lepsza_od_konkurencji Flaga: czy oferta banku jest lepsza oproc_propon < oproc_konkur Prosta zmienna zero-jedynkowa pokazująca przewagę banku nad konkurencją
Oprocentowanie refinansowanie korzysc_refinansowania Łączna korzyść z refinansowania (oproc_refin - oproc_propon) * okres_kredytu Im większa finansowa korzyść przy refinansowaniu, tym większa szansa akceptacji
Oprocentowanie refinansowanie czy_oprocentowanie_lepsze_refinansowanie Flaga: czy refinansowanie ma lepsze warunki oproc_propon < oproc_refin Prosta flaga pokazująca, czy nowa oferta jest korzystniejsza niż dotychczasowe warunki klienta
Ocena wnioskodawcy stosunek_fico_do_oprocentowania Relacja wiarygodności klienta do warunków scoring_FICO / oproc_propon Wysoki stosunek sugeruje, że dobry klient dostał stosunkowo korzystną ofertę
Ocena wnioskodawcy efektywna_ocena_klienta Skorygowana ocena klienta względem ryzyka scoring_FICO / grupa_ryzyka Pozwala wykryć klientów, którzy mimo wysokiego scoringu należą do ryzykownych grup lub odwrotnie

Stworzenie nowych zmiennych

# Dodaj zmienne pochodne
dane_pochodne <- d %>%
  mutate(
    cal_koszt_k = (kwota_kredytu * oproc_propon) + kwota_kredytu,
    rata_m = cal_koszt_k / okres_kredytu,
    marza = oproc_propon - koszt_pieniadza,
    rozn_opr_konk = oproc_konkur - oproc_propon,
    czy_lepsza = as.integer(oproc_propon < oproc_konkur),
    korzysc_ref = (oproc_refin - oproc_propon) * okres_kredytu,
    oproc_lepsze_ref = as.integer(oproc_propon < oproc_refin),
    fico_v_opr = scoring_FICO / oproc_propon,
    efekt_ocena = scoring_FICO / grupa_ryzyka
  )

Weryfikacja, czy występują brakujące obserwacje - nie występują.

sum(is.na.data.frame(dane_pochodne))
## [1] 0

Macierz korelacji wszystkich zmiennych

# Wybór zmiennych pochodnych
zmienne_pochodne <- dane_pochodne %>% 
  select(cal_koszt_k, rata_m, marza,
         rozn_opr_konk, czy_lepsza,
         korzysc_ref, oproc_lepsze_ref,
         fico_v_opr, efekt_ocena)

# Usuń braki danych z ramki zmienne_pochodne
zmienne_pochodne_bez_brakow <- na.omit(zmienne_pochodne)

# Oblicz macierz korelacji i p-wartości na oczyszczonych danych
cor_matrix <- rcorr(as.matrix(zmienne_pochodne_bez_brakow))

# Zamień NA w macierzy p-wartości na 0 (wymagane przez corrplot)
cor_matrix$P[is.na(cor_matrix$P)] <- 0

# Wizualizacja z poprawionymi macierzami
corrplot(cor_matrix$r, 
         method = "color",
         type = "upper",
         tl.col = "darkblue",
         addCoef.col = "black",
         number.cex = 0.7,
         p.mat = cor_matrix$P,
         sig.level = 0.05,
         insig = "blank")

Kubełkowanie

scorecard::woebin(dane_pochodne, "akceptacja_klienta")
## ✔ Binning on 40000 rows and 21 columns in 00:00:12
## $LP
##    variable           bin count count_distr   neg   pos   posprob          woe
##      <char>        <char> <int>       <num> <int> <int>     <num>        <num>
## 1:       LP   [-Inf,3000)  2999    0.074975  2117   882 0.2940980  0.174697706
## 2:       LP   [3000,8000)  5000    0.125000  3643  1357 0.2714000  0.062729784
## 3:       LP  [8000,20000) 12000    0.300000  9167  2833 0.2360833 -0.124012937
## 4:       LP [20000,32000) 12000    0.300000  8673  3327 0.2772500  0.092117166
## 5:       LP [32000,37000)  5000    0.125000  3700  1300 0.2600000  0.004292366
## 6:       LP  [37000, Inf)  3001    0.075025  2333   668 0.2225925 -0.200361178
##          bin_iv   total_iv breaks is_special_values
##           <num>      <num> <char>            <lgcl>
## 1: 2.382357e-03 0.01282394   3000             FALSE
## 2: 4.992567e-04 0.01282394   8000             FALSE
## 3: 4.474400e-03 0.01282394  20000             FALSE
## 4: 2.601545e-03 0.01282394  32000             FALSE
## 5: 2.305430e-06 0.01282394  37000             FALSE
## 6: 2.864076e-03 0.01282394    Inf             FALSE
## 
## $grupa_ryzyka
##        variable      bin count count_distr   neg   pos   posprob        woe
##          <char>   <char> <int>       <num> <int> <int>     <num>      <num>
## 1: grupa_ryzyka [-Inf,2) 17448    0.436200 11357  6091 0.3490945  0.4272389
## 2: grupa_ryzyka    [2,3)  8265    0.206625  6530  1735 0.2099214 -0.2751386
## 3: grupa_ryzyka [3, Inf) 14287    0.357175 11746  2541 0.1778540 -0.4806941
##        bin_iv  total_iv breaks is_special_values
##         <num>     <num> <char>            <lgcl>
## 1: 0.08727731 0.1745792      2             FALSE
## 2: 0.01458358 0.1745792      3             FALSE
## 3: 0.07271833 0.1745792    Inf             FALSE
## 
## $kod_partnera
##        variable      bin count count_distr   neg   pos    posprob         woe
##          <char>   <char> <int>       <num> <int> <int>      <num>       <num>
## 1: kod_partnera [-Inf,2) 14810    0.370250 10040  4770 0.32207968  0.30603011
## 2: kod_partnera    [2,3)  6243    0.156075  5701   542 0.08681724 -1.30286995
## 3: kod_partnera [3, Inf) 18947    0.473675 13892  5055 0.26679685  0.03932564
##          bin_iv total_iv breaks is_special_values
##           <num>    <num> <char>            <lgcl>
## 1: 0.0371221755 0.220401      2             FALSE
## 2: 0.1825393622 0.220401      3             FALSE
## 3: 0.0007394489 0.220401    Inf             FALSE
## 
## $typ_umowy
##     variable    bin count count_distr   neg   pos   posprob        woe
##       <char> <char> <int>       <num> <int> <int>     <num>      <num>
## 1: typ_umowy      N 14323    0.358075 12625  1698 0.1185506 -0.9559670
## 2: typ_umowy      U 14379    0.359475 10316  4063 0.2825649  0.1184864
## 3: typ_umowy      R 11298    0.282450  6692  4606 0.4076828  0.6767079
##         bin_iv  total_iv breaks is_special_values
##          <num>     <num> <char>            <lgcl>
## 1: 0.250708399 0.4037341      N             FALSE
## 2: 0.005188671 0.4037341      U             FALSE
## 3: 0.147837057 0.4037341      R             FALSE
## 
## $scoring_FICO
##        variable        bin count count_distr   neg   pos   posprob        woe
##          <char>     <char> <int>       <num> <int> <int>     <num>      <num>
## 1: scoring_FICO [-Inf,700) 14390     0.35975 11462  2928 0.2034746 -0.3144567
## 2: scoring_FICO  [700,730)  9282     0.23205  7150  2132 0.2296919 -0.1597909
## 3: scoring_FICO  [730,770)  9402     0.23505  6094  3308 0.3518400  0.4393000
## 4: scoring_FICO [770, Inf)  6926     0.17315  4927  1999 0.2886226  0.1481777
##         bin_iv   total_iv breaks is_special_values
##          <num>      <num> <char>            <lgcl>
## 1: 0.032817913 0.09228101    700             FALSE
## 2: 0.005693751 0.09228101    730             FALSE
## 3: 0.049834331 0.09228101    770             FALSE
## 4: 0.003935013 0.09228101    Inf             FALSE
## 
## $okres_kredytu
##         variable       bin count count_distr   neg   pos   posprob         woe
##           <char>    <char> <int>       <num> <int> <int>     <num>       <num>
## 1: okres_kredytu [-Inf,48)  6109    0.152725  3901  2208 0.3614339  0.48111512
## 2: okres_kredytu   [48,60)  5590    0.139750  3903  1687 0.3017889  0.21146724
## 3: okres_kredytu   [60,72) 20364    0.509100 15919  4445 0.2182774 -0.22547257
## 4: okres_kredytu [72, Inf)  7937    0.198425  5910  2027 0.2553862 -0.01982804
##          bin_iv   total_iv breaks is_special_values
##           <num>      <num> <char>            <lgcl>
## 1: 3.913377e-02 0.07022084     48             FALSE
## 2: 6.558999e-03 0.07022084     60             FALSE
## 3: 2.445043e-02 0.07022084     72             FALSE
## 4: 7.763777e-05 0.07022084    Inf             FALSE
## 
## $kwota_kredytu
##         variable           bin count count_distr   neg   pos    posprob
##           <char>        <char> <int>       <num> <int> <int>      <num>
## 1: kwota_kredytu  [-Inf,10000)  3179    0.079475  1110  2069 0.65083360
## 2: kwota_kredytu [10000,14000)  4156    0.103900  1955  2201 0.52959577
## 3: kwota_kredytu [14000,20000)  8408    0.210200  5538  2870 0.34134158
## 4: kwota_kredytu [20000,30000) 12363    0.309075 10039  2324 0.18798026
## 5: kwota_kredytu  [30000, Inf) 11894    0.297350 10991   903 0.07592063
##           woe     bin_iv  total_iv breaks is_special_values
##         <num>      <num>     <num> <char>            <lgcl>
## 1:  1.6729663 0.27121684 0.9361042  10000             FALSE
## 2:  1.1687825 0.17103325 0.9361042  14000             FALSE
## 3:  0.3929395 0.03534638 0.9361042  20000             FALSE
## 4: -0.4129267 0.04732341 0.9361042  30000             FALSE
## 5: -1.4488486 0.41118431 0.9361042    Inf             FALSE
## 
## $oproc_refin
##       variable          bin count count_distr   neg   pos   posprob        woe
##         <char>       <char> <int>       <num> <int> <int>     <num>      <num>
## 1: oproc_refin [-Inf,0.065) 31871    0.796775 25297  6574 0.2062690 -0.2973024
## 2: oproc_refin  [0.065,0.1)  5480    0.137000  3167  2313 0.4220803  0.7360215
## 3: oproc_refin   [0.1, Inf)  2649    0.066225  1169  1480 0.5587014  1.2861543
##        bin_iv  total_iv breaks is_special_values
##         <num>     <num> <char>            <lgcl>
## 1: 0.06527248 0.2837004  0.065             FALSE
## 2: 0.08555345 0.2837004    0.1             FALSE
## 3: 0.13287443 0.2837004    Inf             FALSE
## 
## $oproc_konkur
##        variable           bin count count_distr   neg   pos   posprob
##          <char>        <char> <int>       <num> <int> <int>     <num>
## 1: oproc_konkur  [-Inf,0.041)  2130    0.053250  1563   567 0.2661972
## 2: oproc_konkur [0.041,0.046) 10901    0.272525  9479  1422 0.1304467
## 3: oproc_konkur [0.046,0.058) 24427    0.610675 17086  7341 0.3005281
## 4: oproc_konkur  [0.058, Inf)  2542    0.063550  1505  1037 0.4079465
##            woe       bin_iv  total_iv breaks is_special_values
##          <num>        <num>     <num> <char>            <lgcl>
## 1:  0.03625789 7.061315e-05 0.2151851  0.041             FALSE
## 2: -0.84675357 1.547136e-01 0.2151851  0.046             FALSE
## 3:  0.20547658 2.702538e-02 0.2151851  0.058             FALSE
## 4:  0.67779995 3.337552e-02 0.2151851    Inf             FALSE
## 
## $koszt_pieniadza
##           variable             bin count count_distr   neg   pos   posprob
##             <char>          <char> <int>       <num> <int> <int>     <num>
## 1: koszt_pieniadza   [-Inf,0.0114) 10849    0.271225  7912  2937 0.2707162
## 2: koszt_pieniadza [0.0114,0.0138)  9046    0.226150  6933  2113 0.2335839
## 3: koszt_pieniadza [0.0138,0.0146)  3525    0.088125  2610   915 0.2595745
## 4: koszt_pieniadza [0.0146,0.0168)  8659    0.216475  6199  2460 0.2840975
## 5: koszt_pieniadza [0.0168,0.0176)  2332    0.058300  1755   577 0.2474271
## 6: koszt_pieniadza [0.0176,0.0184)  2097    0.052425  1529   568 0.2708631
## 7: koszt_pieniadza   [0.0184, Inf)  3492    0.087300  2695   797 0.2282360
##             woe       bin_iv   total_iv breaks is_special_values
##           <num>        <num>      <num> <char>            <lgcl>
## 1:  0.059268979 9.662716e-04 0.01144237 0.0114             FALSE
## 2: -0.137922960 4.157319e-03 0.01144237 0.0138             FALSE
## 3:  0.002079486 3.812663e-07 0.01144237 0.0146             FALSE
## 4:  0.126034282 3.541431e-03 0.01144237 0.0168             FALSE
## 5: -0.062120949 2.215940e-04 0.01144237 0.0176             FALSE
## 6:  0.060013134 1.915232e-04 0.01144237 0.0184             FALSE
## 7: -0.168037884 2.363847e-03 0.01144237    Inf             FALSE
## 
## $oproc_propon
##        variable           bin count count_distr   neg   pos   posprob
##          <char>        <char> <int>       <num> <int> <int>     <num>
## 1: oproc_propon  [-Inf,0.046)  7667    0.191675  5871  1796 0.2342507
## 2: oproc_propon [0.046,0.062) 11544    0.288600  6923  4621 0.4002945
## 3: oproc_propon [0.062,0.078)  9747    0.243675  7563  2184 0.2240689
## 4: oproc_propon  [0.078, Inf) 11042    0.276050  9276  1766 0.1599348
##           woe      bin_iv  total_iv breaks is_special_values
##         <num>       <num>     <num> <char>            <lgcl>
## 1: -0.1342021 0.003339175 0.2357337  0.046             FALSE
## 2:  0.6460229 0.137032183 0.2357337  0.062             FALSE
## 3: -0.1918490 0.008547591 0.2357337  0.078             FALSE
## 4: -0.6084524 0.086814701 0.2357337    Inf             FALSE
## 
## $cal_koszt_k
##       variable           bin count count_distr   neg   pos    posprob
##         <char>        <char> <int>       <num> <int> <int>      <num>
## 1: cal_koszt_k  [-Inf,14000)  6352    0.158800  2534  3818 0.60107053
## 2: cal_koszt_k [14000,20000)  7726    0.193150  4873  2853 0.36927259
## 3: cal_koszt_k [20000,26000)  7344    0.183600  5558  1786 0.24319172
## 4: cal_koszt_k [26000,30000)  5203    0.130075  4410   793 0.15241207
## 5: cal_koszt_k  [30000, Inf) 13375    0.334375 12258  1117 0.08351402
##            woe      bin_iv  total_iv breaks is_special_values
##          <num>       <num>     <num> <char>            <lgcl>
## 1:  1.46018856 0.412899280 0.9309045  14000             FALSE
## 2:  0.51492223 0.057030268 0.9309045  20000             FALSE
## 3: -0.08499893 0.001299102 0.9309045  26000             FALSE
## 4: -0.66554583 0.048137502 0.9309045  30000             FALSE
## 5: -1.34527134 0.411538299 0.9309045    Inf             FALSE
## 
## $rata_m
##    variable        bin count count_distr   neg   pos    posprob        woe
##      <char>     <char> <int>       <num> <int> <int>      <num>      <num>
## 1:   rata_m [-Inf,260)  6286    0.157150  2604  3682 0.58574610  1.3966683
## 2:   rata_m  [260,420) 12767    0.319175  8449  4318 0.33821571  0.3790052
## 3:   rata_m  [420,600) 12500    0.312500 10713  1787 0.14296000 -0.7406588
## 4:   rata_m [600, Inf)  8447    0.211175  7867   580 0.06866343 -1.5571430
##        bin_iv  total_iv breaks is_special_values
##         <num>     <num> <char>            <lgcl>
## 1: 0.37331606 0.8894841    260             FALSE
## 2: 0.04979848 0.8894841    420             FALSE
## 3: 0.14009468 0.8894841    600             FALSE
## 4: 0.32627487 0.8894841    Inf             FALSE
## 
## $marza
##    variable           bin count count_distr   neg   pos   posprob          woe
##      <char>        <char> <int>       <num> <int> <int>     <num>        <num>
## 1:    marza  [-Inf,0.032)  7730    0.193250  5733  1997 0.2583441 -0.004331979
## 2:    marza [0.032,0.044)  9703    0.242575  5816  3887 0.4005978  0.647285832
## 3:    marza [0.044,0.052)  5468    0.136700  4151  1317 0.2408559 -0.097731925
## 4:    marza [0.052,0.058)  2571    0.064275  1796   775 0.3014391  0.209806701
## 5:    marza  [0.058, Inf) 14528    0.363200 12137  2391 0.1645787 -0.574286029
##          bin_iv  total_iv breaks is_special_values
##           <num>     <num> <char>            <lgcl>
## 1: 3.622752e-06 0.2226622  0.032             FALSE
## 2: 1.156519e-01 0.2226622  0.044             FALSE
## 3: 1.274678e-03 0.2226622  0.052             FALSE
## 4: 2.968415e-03 0.2226622  0.058             FALSE
## 5: 1.027636e-01 0.2226622    Inf             FALSE
## 
## $rozn_opr_konk
##         variable             bin count count_distr   neg   pos   posprob
##           <char>          <char> <int>       <num> <int> <int>     <num>
## 1: rozn_opr_konk   [-Inf,-0.018) 16033    0.400825 13522  2511 0.1566145
## 2: rozn_opr_konk [-0.018,-0.012)  4090    0.102250  3044  1046 0.2557457
## 3: rozn_opr_konk   [-0.012, Inf) 19877    0.496925 13067  6810 0.3426070
##            woe       bin_iv  total_iv breaks is_special_values
##          <num>        <num>     <num> <char>            <lgcl>
## 1: -0.63337599 1.356088e-01 0.2217037 -0.018             FALSE
## 2: -0.01793815 3.275934e-05 0.2217037 -0.012             FALSE
## 3:  0.39856307 8.606211e-02 0.2217037    Inf             FALSE
## 
## $czy_lepsza
##      variable      bin count count_distr   neg   pos   posprob        woe
##        <char>   <char> <int>       <num> <int> <int>     <num>      <num>
## 1: czy_lepsza [-Inf,1) 34113    0.852825 25931  8182 0.2398499 -0.1032416
## 2: czy_lepsza [1, Inf)  5887    0.147175  3702  2185 0.3711568  0.5230035
##         bin_iv   total_iv breaks is_special_values
##          <num>      <num> <char>            <lgcl>
## 1: 0.008861914 0.05375478      1             FALSE
## 2: 0.044892865 0.05375478    Inf             FALSE
## 
## $korzysc_ref
##       variable         bin count count_distr   neg   pos   posprob        woe
##         <char>      <char> <int>       <num> <int> <int>     <num>      <num>
## 1: korzysc_ref [-Inf,-4.5)  9232    0.230800  8021  1211 0.1311742 -0.8403557
## 2: korzysc_ref   [-4.5,-2) 17625    0.440625 13957  3668 0.2081135 -0.2860737
## 3: korzysc_ref    [-2,0.5)  5177    0.129425  3621  1556 0.3005602  0.2056291
## 4: korzysc_ref   [0.5,1.5)  5314    0.132850  3077  2237 0.4209635  0.7314415
## 5: korzysc_ref  [1.5, Inf)  2652    0.066300   957  1695 0.6391403  1.6218955
##         bin_iv  total_iv breaks is_special_values
##          <num>     <num> <char>            <lgcl>
## 1: 0.129301329 0.4632403   -4.5             FALSE
## 2: 0.033522169 0.4632403     -2             FALSE
## 3: 0.005736392 0.4632403    0.5             FALSE
## 4: 0.081880418 0.4632403    1.5             FALSE
## 5: 0.212799978 0.4632403    Inf             FALSE
## 
## $oproc_lepsze_ref
##            variable      bin count count_distr   neg   pos   posprob        woe
##              <char>   <char> <int>       <num> <int> <int>     <num>      <num>
## 1: oproc_lepsze_ref [-Inf,1) 30476      0.7619 24528  5948 0.1951700 -0.3664994
## 2: oproc_lepsze_ref [1, Inf)  9524      0.2381  5105  4419 0.4639857  0.9059539
##        bin_iv  total_iv breaks is_special_values
##         <num>     <num> <char>            <lgcl>
## 1: 0.09308433 0.3231805      1             FALSE
## 2: 0.23009620 0.3231805    Inf             FALSE
## 
## $fico_v_opr
##      variable           bin count count_distr   neg   pos   posprob         woe
##        <char>        <char> <int>       <num> <int> <int>     <num>       <num>
## 1: fico_v_opr   [-Inf,8000)  7695    0.192375  6363  1332 0.1730994 -0.51355747
## 2: fico_v_opr   [8000,8500)  2531    0.063275  2236   295 0.1165547 -0.97520756
## 3: fico_v_opr  [8500,12000) 11277    0.281925  8743  2534 0.2247052 -0.18819338
## 4: fico_v_opr [12000,16500) 11118    0.277950  6742  4376 0.3935960  0.61803937
## 5: fico_v_opr  [16500, Inf)  7379    0.184475  5549  1830 0.2480011 -0.05904084
##          bin_iv  total_iv breaks is_special_values
##           <num>     <num> <char>            <lgcl>
## 1: 0.0442903314 0.2205503   8000             FALSE
## 2: 0.0458354770 0.2205503   8500             FALSE
## 3: 0.0095250783 0.2205503  12000             FALSE
## 4: 0.1202655131 0.2205503  16500             FALSE
## 5: 0.0006338503 0.2205503    Inf             FALSE
## 
## $efekt_ocena
##       variable        bin count count_distr   neg   pos   posprob        woe
##         <char>     <char> <int>       <num> <int> <int>     <num>      <num>
## 1: efekt_ocena [-Inf,380) 22534    0.563350 18263  4271 0.1895358 -0.4027682
## 2: efekt_ocena  [380,760)  9043    0.226075  5555  3488 0.3857127  0.5848910
## 3: efekt_ocena [760, Inf)  8423    0.210575  5815  2608 0.3096284  0.2484038
##        bin_iv  total_iv breaks is_special_values
##         <num>     <num> <char>            <lgcl>
## 1: 0.08229595 0.1831853    380             FALSE
## 2: 0.08714424 0.1831853    760             FALSE
## 3: 0.01374506 0.1831853    Inf             FALSE
df <- woebin_ply(dane_pochodne,   woebin(dane_pochodne, "akceptacja_klienta"), to="bin")
## ✔ Binning on 40000 rows and 21 columns in 00:00:12
## ✔ Woe transformating on 40000 rows and 20 columns in 00:00:22
iv(df, "akceptacja_klienta")
##                 variable info_value
##                   <char>      <num>
##  1:    kwota_kredytu_bin 0.93610419
##  2:      cal_koszt_k_bin 0.93090445
##  3:           rata_m_bin 0.88948410
##  4:      korzysc_ref_bin 0.46324029
##  5:        typ_umowy_bin 0.40373413
##  6: oproc_lepsze_ref_bin 0.32318053
##  7:      oproc_refin_bin 0.28370037
##  8:     oproc_propon_bin 0.23573365
##  9:            marza_bin 0.22266219
## 10:    rozn_opr_konk_bin 0.22170367
## 11:       fico_v_opr_bin 0.22055025
## 12:     kod_partnera_bin 0.22040099
## 13:     oproc_konkur_bin 0.21518513
## 14:      efekt_ocena_bin 0.18318526
## 15:     grupa_ryzyka_bin 0.17457922
## 16:     scoring_FICO_bin 0.09228101
## 17:    okres_kredytu_bin 0.07022084
## 18:       czy_lepsza_bin 0.05375478
## 19:      data_akceptacji 0.03879611
## 20:               LP_bin 0.01282394
## 21:  koszt_pieniadza_bin 0.01144237
##                 variable info_value

Boxplot - rozkład kosztów wg akceptacji

ggplot(dane_pochodne, aes(x = factor(akceptacja_klienta, labels = c("Nie", "Tak")), 
                          y = cal_koszt_k)) +
  geom_boxplot(fill = "#2171b3", alpha = 0.7) +
  labs(title = "Rozkład całkowitego kosztu kredytu wg akceptacji",
       x = "Akceptacja oferty",
       y = "Całkowity koszt kredytu (zł)") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

Im wyższy czałkowity koszt kredytu, tym bardziej spada akceptacja klientów.

Boxplot - rozkład akceptacji względem raty miesięcznej

ggplot(dane_pochodne, aes(x = factor(akceptacja_klienta, labels = c("Nie", "Tak")), 
                          y = rata_m)) +
  geom_boxplot(fill = "#2171b3", alpha = 0.7) +
  labs(title = "Rozkład akceptacji względem raty miesięcznej",
       x = "Akceptacja oferty",
       y = "Wartość miesięcznej raty (zł)") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

Występuje również wyraźny trend akceptacji oferty w zależności od wysokości miesięcznej raty, im mniejsza, tym większe pradopodobieństwo akceptacji.

df_procenty <- dane_pochodne %>%
  group_by(kod_partnera, akceptacja_klienta) %>%
  summarise(liczba = n(), .groups = "drop") %>%
  group_by(kod_partnera) %>%
  mutate(procent = 100 * liczba / sum(liczba)) %>%
  mutate(akceptacja_klienta = factor(akceptacja_klienta, labels = c("Niezaakceptowane", "Zaakceptowane"))) 

ggplot(df_procenty, aes(x = factor(kod_partnera), y = procent, fill = akceptacja_klienta)) +
  geom_bar(stat = "identity", position = "dodge") +
  geom_text(aes(label = sprintf("%.0f%%", procent)),
            position = position_dodge(width = 0.9),
            vjust = -0.2, size = 5) +
  scale_fill_manual(values = c("#d73027", "#1a9850")) +
  labs(
    title = "Procentowy udział zaakceptowanych i niezaakceptowanych umów względem kodu partnera",
    x = "Kod partnera",
    y = "Procent umów [%]",
    fill = "Akceptacja klienta"
  ) +
  theme_minimal()