Cílem tohoto dokumentu je sestavení a ověření referenčního modelu zahájení úvěru pro stávající klienty, a to s horizonty 6 měsíců a 12 měsíců. Model s horizontem 6 měsíců je sestavený podle dat 1. 3. – 29. 8. 2018 a validován na datech 30. 8. 2018 – 28. 2. 2019.
Tento dokument vzniká v rámci podobnostního modelování ke grantu TAČR.

Vstupní data

Analýza vychází z dat Equabank za klienty a jejich produkty. Platnost dat je podle poskytovatele od ledna 2015 do konce února 2019, nicméně v datech jsou uvedeny i produkty zahájené i skončené před lednem 2015 (a k nim odpovídající klienti).

Využité tabulky v tomto dokumentu:

  • klienti: id, typ, pohlaví, věk;
  • depositní produkty (běžný účet, spořicí účet, termínovaný vklad): id, typ produktu, stav, datum zahájení a případně ukončení;
  • úvěrové produkty (spotřebitelské čili cash-loan úvěry, hypotéky a kontokorent): id, typ produktu, stav, datum zahájení a případně ukončení;
  • číselník produktů;
  • adresy klientů: rozlišení trvalá/kontaktní adresa, platnost údaje, PSČ, název obce.

Označení typů produktů

Zkratka Význam
RCA běžný účet
RSA spořicí účet
RTS termínovaný vklad
RCL spotřebitelský úvěr
RML hypotéka
ROD kontokorent

Podobně jako v exploratorní analýze budu za úvěrové produkty považovat jen spotřebitelské úvěry a hypotéky. Kontokorent nebude pro účely další analýzy úvěrový (ani depositní) produkt.

V datech provedu následující úpravy:

  • ponechám jen fyzické osoby s uvedeným pohlavím a rokem narození nejvýše 2001;
  • ponechám jen produkty pro fyzické osoby (retailové);
  • u produktů, které vznikly jako navazující na jiný produkt stejného typu, toto vyznačím (navazující produkty se nepočítají jako samostatné produkty);
  • ponechám jen klienty mající aspoň jeden produkt a produkty s aspoň jedním klientem;
  • klientovi zjistím věk k referenčnímu dnu;
  • z tabulky adres kontaktní adresy platné k referenčnímu dnu (není-li u klienta žádná kontaktní, použiju trvalou);
  • rozdělím adresy do kategorií podle první číslice PSČ (jiné číslice než 1–7 spadají do kategorie N/A);
  • podle názvu obce a výstupu veřejné databáze ČSÚ zjistím počet obyvatel v obci;
  • zjistím pro klienta počet produktů podle jednotlivých typů k referenčnímu dnu;
  • podle kombinace produktů k referenčnímu dnu přiřadím klientovi typologickou charakteristiku;
  • zjistím, kolik dnů u každého klienta uplynulo v referenční den od zahájení prvního produktu klienta (“vstupu do banky”);
  • zjistím, zda klient po referenčním dnu zahájil některý úvěrový produkt a případně po kolika dnech.

Používám dva referenční dny (1. 3. 2018 pro model s 12měsíčním horizontem a pro natrénování modelu se 6měsíčním horizontem; 30. 8. 2018 pro ověření modelu se 6měsíčním horizontem).

V datech je celkem 395 055 klientů, kteří mají celkem 919 707 samostatných (a 33 256 navazujících) retailových produktů.

Klienti-ukázka
owner gender vek region obec rca rsa rts rod rcl rml typ doba_vstup do_uveru
1 16144402 Z 25 5 do 10 tis. 1 0 0 0 0 0 Jen běžný účet 1057
2 10063052 Z 47 6 do 10 tis. 1 0 0 0 2+ 0 Víc úvěrů 162 55
3 9914206 M 55 7 nad 200 tis. 1 0 0 0 0 1+ Ostatní 2058
4 21057752 Z 25 4 N/A 1 1 0 0 0 0 Spořič 164
5 15372744 Z 36 3 do 10 tis. 1 0 0 0 1 0 Úvěr 1235
6 14174554 M 48 6 do 10 tis. 1 2+ 0 0 0 0 Spořič plus 1647
7 13744237 Z 48 5 10-40 tis. 2+ 1 0 0 0 0 Spořič 1618
8 21723890 Z 49 7 do 10 tis. 1 1 0 1+ 1 0 Ostatní 73 113
9 14151536 Z 60 7 nad 200 tis. 1 1 0 0 0 0 Spořič 1654
10 15928358 Z 28 1 nad 200 tis. 1 1 0 0 0 0 Spořič 1116
11 19821463 M 45 7 do 10 tis. 1 0 0 0 0 0 Jen běžný účet 405
12 15148043 M 48 5 do 10 tis. 1 1 0 0 2+ 0 Víc úvěrů 2191
13 17967126 Z 24 6 10-40 tis. 1 0 0 0 0 0 Jen běžný účet 825
14 18753996 M 26 7 90-200 tis. 1 1 0 0 0 0 Spořič 640
15 18128953 M 45 2 40-90 tis. 1 0 0 0 2+ 0 Víc úvěrů 781
16 14277410 Z 45 5 do 10 tis. 1 0 0 0 0 0 Jen běžný účet 1612
17 14498938 Z 37 5 do 10 tis. 1 1 0 0 0 0 Spořič 1527
18 20337259 Z 59 4 do 10 tis. 2+ 0 0 0 0 0 Jen běžný účet 290
19 16006908 M 22 6 do 10 tis. 1 0 0 0 0 0 Jen běžný účet 1093
20 20211269 M 26 4 40-90 tis. 1 0 0 0 0 1+ Ostatní 258
Produkty-ukázka
owner acc.id type.id prod.kat prod.type state start end
1 14917396 1969956533 RCL Loan 92 Open 2018-01-23
2 13485100 80112019 RSA Deposit 132 Open 2013-09-26
3 15840767 931669448 RCL Loan 92 Open 2016-09-12
4 14293597 139472523 RCL Loan 92 Open 2014-04-07
5 10318675 56543166 RSA Deposit 131 Open 2013-06-07
6 19806262 1507174231 ROD Loan 130 Open 2017-07-20
7 9843796 82871531 RSA Deposit 132 Open 2013-10-07
8 14940237 268541061 RCL Loan 91 Closed 2015-01-27 2017-05-30
9 10096048 98747498 RTS Deposit 138 Closed 2013-12-04 2016-12-03
10 14687383 372937809 RCL Loan 92 Closed 2015-06-28 2016-07-27
11 18293316 899023403 RSA Deposit 134 Open 2016-08-22
12 14573106 183742065 RCL Loan 92 Open 2014-07-28
13 15103155 263447984 RCA Deposit 86 Open 2015-01-16
14 10414976 81059267 RSA Deposit 131 Open 2013-09-30
15 18165312 848282769 RCA Deposit 86 Open 2016-07-20
16 10229987 51117776 RCA Deposit 86 Open 2013-05-24
17 20152694 1667987710 RCA Deposit 86 Open 2017-10-04
18 13831280 143085649 RSA Deposit 131 Open 2014-04-16
19 10413132 68937625 RCA Deposit 86 Open 2013-08-07
20 18183866 3019064748 RCL Loan 92 Open 2018-12-12

Časové horizonty pro modelování

Vytvořím celkem tři modelovací matice, a to jednu pro model s 12měsíčním horizontem a dvě pro natrénování a ověření modelu se 6měsíčním horizontem. Každá modelovací matice se váže k určitému referenčnímu dnu a budou v ní klienti splňující tyto podmínky:

  • v referenční den uplynulo už nejméně 30 dnů od jejich vstupu do banky;
  • v referenční den ani v předchozích 30 dnech neměli aktivní žádný úvěrový produkt.

K referenčnímu dnu 1. 3. 2018 je v modelovací matici 221 741 klientů, k referenčnímu dnu 30. 8. 2018 je v modelovací matici 244 710 klientů. Target se v modelovací matici nastaví na TRUE, pokud klient od referenčního dne nejpozději do stanoveného časového horizontu (6 nebo 12 měsíců) zahájil nový úvěrový produkt, jinak bude FALSE.

Průměrné podíly pozitivních targetů v datech:

  • 12měsíční modelovací matice k 1. 3. 2018 0.043
  • 6měsíční modelovací matice k 1. 3. 2018 0.024
  • 6měsíční modelovací matice k 30. 8. 2018 0.024

Analýza vztahu targetu a prediktorů

Analýzu jsem provedl jen pro model s 12měsíčním horizontem s referenčním dnem 1. 3. 2018, protože je v ní vyšší podíl pozitivních případů. Analogicky by šla provést pro model se 6měsíčním horizontem.

Modelování

Sestavení modelů

Při sestavení modelu řeším dvě otázky:

  1. Použít počty/kategorie jednotlivých typů produktů, nebo typologii klienta podle charakteristických kombinací produktů?
  2. Použít model s interakcemi, nebo bez nich?

Kombinací různých odpovědí na předchozí dvě otázky dostávám u 12měsíčního i u 6měsíčního horizontu celkem čtyři kandidáty na model. U každého kandidáta sestavím nejprve model logistické regrese v daném rámci co nejbohatší a automaticky nechám tento model redukovat. Nakonec ručně ověřím významnost zahrnutých prediktorů a případně ještě některé vyřadím. Následuje ukázka kódu, který toto provede:

model0 = glm(target ~ gender + vek.kat + zip.region + city.kat +
               doba.od.vstupu.kat + (rca.pocet.pred.kat +
               rsa.pocet.pred.kat + rts.pocet.pred.kat + rod.pocet.pred.kat +
               rcl.pocet.pred.kat + rml.pocet.pred.kat)^2,
             data=d.model, family=binomial())
model1 = step(model0)
drop1(model1, test="Chi")

Redukcí všech čtyř kandidátských modelů dostanu finální modely:

model1 = glm(target ~ gender + vek.kat + zip.region + city.kat +
               doba.od.vstupu.kat + rsa.pocet.pred.kat + rts.pocet.pred.kat + 
               rod.pocet.pred.kat + rcl.pocet.pred.kat + rml.pocet.pred.kat + 
               rsa.pocet.pred.kat:rcl.pocet.pred.kat +
               rts.pocet.pred.kat:rcl.pocet.pred.kat + 
               rts.pocet.pred.kat:rml.pocet.pred.kat +
               rod.pocet.pred.kat:rcl.pocet.pred.kat,
             data=d.model, family=binomial())
model2 = glm(target ~ gender + vek.kat + zip.region + city.kat +
               doba.od.vstupu.kat + 
               rca.pocet.pred.kat + rsa.pocet.pred.kat + rts.pocet.pred.kat + 
               rod.pocet.pred.kat + rcl.pocet.pred.kat + rml.pocet.pred.kat,
             data=d.model, family=binomial())
model3 = glm(target ~ gender + vek.kat + zip.region + city.kat +
               doba.od.vstupu.kat + prod.kombinace,
             data=d.model, family=binomial())
model4 = glm(target ~ gender + vek.kat + zip.region + city.kat +
               doba.od.vstupu.kat +
               prod.kombinace + gender:zip.region + gender:prod.kombinace +
               vek.kat:doba.od.vstupu.kat + vek.kat:prod.kombinace +
               doba.od.vstupu.kat:prod.kombinace,
             data=d.model, family=binomial())

model1.tren = glm(target ~ gender + vek.kat + zip.region + city.kat +
                    doba.od.vstupu.kat + 
                    rca.pocet.pred.kat + rsa.pocet.pred.kat + rts.pocet.pred.kat + 
                    rod.pocet.pred.kat + rcl.pocet.pred.kat + rml.pocet.pred.kat + 
                    rca.pocet.pred.kat:rcl.pocet.pred.kat + 
                    rsa.pocet.pred.kat:rcl.pocet.pred.kat +
                    rts.pocet.pred.kat:rcl.pocet.pred.kat + 
                    rod.pocet.pred.kat:rcl.pocet.pred.kat,
                  data=d.model.tren, family=binomial())
model2.tren = glm(target ~ gender + vek.kat + zip.region + city.kat +
                    doba.od.vstupu.kat + 
                    rsa.pocet.pred.kat + rts.pocet.pred.kat + rod.pocet.pred.kat + 
                    rcl.pocet.pred.kat + rml.pocet.pred.kat,
             data=d.model.tren, family=binomial())
model3.tren = glm(target ~ gender + vek.kat + zip.region + city.kat + doba.od.vstupu.kat +
                    prod.kombinace,
             data=d.model.tren, family=binomial())
model4.tren = glm(target ~ gender + vek.kat + zip.region + city.kat + doba.od.vstupu.kat + 
                    prod.kombinace + gender:zip.region + gender:doba.od.vstupu.kat + 
                    gender:prod.kombinace + vek.kat:doba.od.vstupu.kat +
                    vek.kat:prod.kombinace + 
                    doba.od.vstupu.kat:prod.kombinace,
             data=d.model.tren, family=binomial())

Vyhodnocení modelů – statistické

Ze statistického pohledu je možné modely pro 12měsíční horizont porovnat podle toho, jak se jim podařilo snížit tzv. deviance (\(-2 * log(Lik)\)) a kolik na to spotřebovaly parametrů.

Statistické porovnání modelů – 12m horizont
Snížení deviance Počet parametrů
Model 12m 1 9217 38
Model 12m 2 8927 30
Model 12m 3 8576 29
Model 12m 4 9040 126

Nejvíce snížil deviance Model 1, a to s mnohem menším počtem potřebných parametrů než druhý model v pořadí (Model 4). Nejmenší snížení je u Modelu 3, ale také s nejnižším počtem použitých parametrů. Modely dále můžeme vzájemně porovnat pomocí statistického testu poměru věrohodností, například takto pro Model 2 a Model3:

anova(model2, model3, test="Chi")
## Analysis of Deviance Table
## 
## Model 1: target ~ gender + vek.kat + zip.region + city.kat + doba.od.vstupu.kat + 
##     rca.pocet.pred.kat + rsa.pocet.pred.kat + rts.pocet.pred.kat + 
##     rod.pocet.pred.kat + rcl.pocet.pred.kat + rml.pocet.pred.kat
## Model 2: target ~ gender + vek.kat + zip.region + city.kat + doba.od.vstupu.kat + 
##     prod.kombinace
##   Resid. Df Resid. Dev Df Deviance  Pr(>Chi)    
## 1    221710      69633                          
## 2    221711      69983 -1  -350.78 < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Ze statistického porovnání (tabulka výše a vzájemné porovnání) vychází, že nejsilnější je Model 1, nejslabší Model 3; Model 2 a Model 4 jsou mezi nimi přibližně na stejné úrovni.

Podobně vyhodnotím modely pro 6měsíční horizont.

Statistické porovnání modelů – 6m horizont
Snížení deviance Počet parametrů
Model 6m 1 5704 40
Model 6m 2 5462 29
Model 6m 3 5314 29
Model 6m 4 5629 130

Ze statistického porovnání vychází, že i pro 6měsíční horizont je nejlepší Model 1 a nejhorší Model 3. Model 4 je významně lepší než model 2.

Vyhodnodení modelů – cross-validace

Jak modely s 12měsíčním horizontem, tak model se 6měsíčním horizontem vyhodnotím obvyklou cross-validací s dělením modelovací matice na 10 částí.

## $auc
## [1] 0.7490782
## 
## $lift.01
## [1] 8.455466
## 
## $lift.05
## [1] 5.513809
## 
## $pos.pred
## [1] 0.04292884
## 
## $pos.skut
## [1] 0.04292846

## $auc
## [1] 0.7488786
## 
## $lift.01
## [1] 8.389491
## 
## $lift.05
## [1] 5.408701
## 
## $pos.pred
## [1] 0.04292727
## 
## $pos.skut
## [1] 0.04292846

## $auc
## [1] 0.7460743
## 
## $lift.01
## [1] 6.32545
## 
## $lift.05
## [1] 5.254052
## 
## $pos.pred
## [1] 0.0429339
## 
## $pos.skut
## [1] 0.04292846

## $auc
## [1] 0.7490792
## 
## $lift.01
## [1] 6.763907
## 
## $lift.05
## [1] 5.282458
## 
## $pos.pred
## [1] 0.04292682
## 
## $pos.skut
## [1] 0.04292846

Modely 1, 2 a 4 jsou z pohledu AUC rovnocenné. Pro Model 1 znázorním rozdělení predikovaných pravděpodobností u skutečných pozitivních a skutečných negativních případů.

 

## $auc
## [1] 0.7573665
## 
## $lift.01
## [1] 9.548132
## 
## $lift.05
## [1] 6.012567
## 
## $pos.pred
## [1] 0.02397711
## 
## $pos.skut
## [1] 0.02397843

## $auc
## [1] 0.7566113
## 
## $lift.01
## [1] 9.40069
## 
## $lift.05
## [1] 5.860748
## 
## $pos.pred
## [1] 0.02398182
## 
## $pos.skut
## [1] 0.02397843

## $auc
## [1] 0.7540842
## 
## $lift.01
## [1] 7.148695
## 
## $lift.05
## [1] 5.722219
## 
## $pos.pred
## [1] 0.02397911
## 
## $pos.skut
## [1] 0.02397843

## $auc
## [1] 0.7564593
## 
## $lift.01
## [1] 7.28228
## 
## $lift.05
## [1] 5.752467
## 
## $pos.pred
## [1] 0.02397923
## 
## $pos.skut
## [1] 0.02397843

Nejlepší model je Model 1. Znázorním pro něj rozdělení predikovaných pravděpodobností u skutečných pozitivních a skutečných negativních případů.

Vyhodnocení modelů na 6 měsíců – validační množina

Modely se 6měsíčním horizontem můžeme vyhodnotit také tak, že modely natrénujeme na datech k referenčnímu dnu 1. 3. 2018, nasadíme na pozdější data k referenčnímu dnu 30. 8. 2018 jako na validační množinu a porovnáme predikce se skutečností.

## $auc
## [1] 0.7667282
## 
## $lift.01
## [1] 10.65122
## 
## $lift.05
## [1] 6.397614
## 
## $pos.pred
## [1] 0.02510907
## 
## $pos.skut
## [1] 0.02436762

## $auc
## [1] 0.7665355
## 
## $lift.01
## [1] 10.70777
## 
## $lift.05
## [1] 6.345335
## 
## $pos.pred
## [1] 0.02521519
## 
## $pos.skut
## [1] 0.02436762

## $auc
## [1] 0.7626692
## 
## $lift.01
## [1] 7.793609
## 
## $lift.05
## [1] 5.967572
## 
## $pos.pred
## [1] 0.02489836
## 
## $pos.skut
## [1] 0.02436762

## $auc
## [1] 0.7640154
## 
## $lift.01
## [1] 7.491152
## 
## $lift.05
## [1] 6.034719
## 
## $pos.pred
## [1] 0.02517653
## 
## $pos.skut
## [1] 0.02436762

Z vyhodnocení na validační množině plyne, že všechny modely si vedly dokonce o něco lépe než při cross-validaci. Nejvyšší AUC mají Model 1 a Model 2.

Závěry

  • Jednoduchý referenční model logistické regrese pro predikci, že klient zahájí nový úvěr, má AUC přibližně 0,75. Tento model je založený na poměrně malém počtu prediktorů a má stabilní výkonnost pro 6měsíční i 12měsíční horizont.
  • Modely s interakcemi jsou o něco výkonnější než modely bez interakcí, ale rozdíl je poměrně malý (v tisícinách AUC).
  • Sklon klientů k zahájení nového úvěru se v čase příliš nemění (doba do zahájení úvěru má exponenciální rozdělení). I pro nové klienty dobře funguje model sestavený před několika měsíci.

Export

save(model1, model2, model3, model4, file='propensity-modely.RData')

Technické informace o reportu

print(sessionInfo())
## R version 3.6.0 (2019-04-26)
## Platform: x86_64-redhat-linux-gnu (64-bit)
## Running under: CentOS Linux 7 (Core)
## 
## Matrix products: default
## BLAS/LAPACK: /usr/lib64/R/lib/libRblas.so
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8       
##  [4] LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C              
## [10] LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] ROCR_1.0-7         gplots_3.0.1.1     magrittr_1.5       forcats_0.4.0      stringr_1.4.0     
##  [6] dplyr_0.8.3        glue_1.3.1         RPostgres_1.1.1    RColorBrewer_1.1-2 xtable_1.8-4      
## [11] data.table_1.12.2 
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.2         pillar_1.4.2       compiler_3.6.0     bitops_1.0-6       tools_3.6.0       
##  [6] zeallot_0.1.0      digest_0.6.20      bit_1.1-14         evaluate_0.14      tibble_2.1.3      
## [11] pkgconfig_2.0.2    rlang_0.4.0        DBI_1.0.0          yaml_2.2.0         xfun_0.8          
## [16] knitr_1.24         caTools_1.17.1.2   vctrs_0.2.0        gtools_3.8.1       hms_0.5.0         
## [21] bit64_0.9-7        tidyselect_0.2.5   R6_2.4.0           rmarkdown_1.14     gdata_2.18.0      
## [26] purrr_0.3.2        blob_1.2.0         backports_1.1.4    htmltools_0.3.6    assertthat_0.2.1  
## [31] KernSmooth_2.23-15 stringi_1.4.3      crayon_1.3.4