Risk Analitiği: tidycreditrisk Paketi

Corona günlerinden herkese merhaba,
Bu yazımda, risk analitiği kapsamında temerrüt verisi üzerinde yapılabilecek istatistiksel analizler hakkında bilgiler vereceğim. Analizleri, Tunç Oygur ve Arda Keskin ile beraber R programlama dilini kullanarak yazdığımız “tidycreditrisk” paketi ile yapacağız. 

 

Bir olayın gerçekleşmesi belirsizlik veya zarar meydana getiriyor ise, o olayın gerçekleşmesi olasığı risk ile tanımlanır. Risk analitiği ise, bu olayın gerçekleşmesi olasılığını çeşitli istatistiksel ve matematiksel yöntemler ile tanımlamak ve modellemek için veriden yararlanan bir çalışma alanıdır. Bankacılık faaliyetlerinde, birçok kaynaktan veri toplanabileceği için risk üzerine yapılan çalışmalar çok çeşitli alanlarda yapılabilmektedir. Kredi riski hesaplamaları, ulusal (regulatörler ve yasa koyucularının düzenlemeleri) veya uluslararası (International Financial Reporting Standards) standartlar ile düzenlenmektedir. 

Temerrüt, yukarıda belirtilen standartlara bağlı olarak, bir kredinin taahhüt edilen süreler içerisinde ödenmemesi durumudur. Dolayısıyla bankaların, geçmiş kredilerindeki temerrüt durumlarının modellenmesi, risk faaliyetlerinin önemli bir parçasıdır.

Bu yazıda, R’da bulunan GermanCredit hazır veri setini kullanarak;

  • Veriyi eğitim-test seti olarak ayırma
  • Gradient Boosting Method modeli ile modelleme
  • Tahmin yapma
  • Yapılan tahminleri kategorize etme
  • Elde edilen veri seti üzerinde tidycreditrisk paketi ile analizler yapma işlemleri uygulanmıştır.

 

1- Kullanılan Kütüphaneler

library(tidyverse)
library(magrittr)
library(caret)
library(gbm)
library(rpart)
library(devtools)

install_github("toygur/tidycreditrisk")
library(tidycreditrisk)

2- Veri Hazırlamala İşlemleri 

GermanCredit verisi 1000 gözlem, 62 değişkenden oluşmaktadır. Bu çalışma için;

  • Kişinin temerrüde düşüp düşmediğini gösteren Class değişkeni,
  • Kredinin süregelen zamanını ay bazında gösteren Amount değişkeni,
  • Kredi sahibin toplam kaç kredisinin olduğunu gösteren NumberExistingCredits değişkeni,
  • Telefon bilgisinin olup olmadığını gösteren Telephone değişkeni,
  • Kredi sahibinin yabancı çalışan olup olmadığını gösteren  ForeignWorker değişkeni kullanılmıştır.
data("GermanCredit")
df <- GermanCredit %>% select(default = Class,
                              duration = Duration,
                              amount = Amount,
                              existingCredits = NumberExistingCredits,
                              telephone = Telephone,
                              foreignWorker = ForeignWorker) %>% 
  mutate(default = ifelse(default == "Good", 0, 1) %>% as.factor,
         telephone = telephone %>% as.factor,
         foreignWorker = foreignWorker %>% as.factor) %>% as.tibble

Tibble formatında oluşturulan veri seti aşağıdaki gibidir. Zamandan ve işlem hızından kazanç sağlamak için tidyr ve purrr paketlerinde yer alan fonksiyonlar, tibble formatındaki veriler üzerinde kullanılabilir.

3- Veriyi Eğitim-Test Olarak Ayırmak 

Bu bölümde, modelin tahmin performansını ölçmek amacıyla veriyi eğitim-test olarak ayırma işlemi yapılmıştır.  createDataPartition() fonksiyonu ile eğitim verisi için %80, test verisi için %20lik dilimler ayrılmıştır. 

partition_index <- createDataPartition(df$default, times=1, p=0.20, list = FALSE)
data_train <- df %>% slice(-partition_index)
data_test <-  df %>% slice(partition_index)

 

4- Gradient Boosting Method (GBM) 

Temerrüt değişkeni 0 ve 1 değerlerinden oluşan faktör değişkeni olduğu için sınıflandırma algoritmalarından bir tanesi olan GBM modeli kullanılmıştır. default değişkenindeki 0 değeri temerrüt olmama durumunu gösterirken, 1 değeri temerrüt olma durumunu temsil etmektedir. 

model_gbm <- gbm(                # gbm modeli          
  formula = default ~ .,         # default bağımlı değişkeni        
  data = data_train,             # eğitim verisi data_train
  distribution = "multinomial",  # bağımlı değişkenin dağılımı 
  n.trees = 3000,                # 3000 ağaç ile model kurulumu
  interaction.depth = 1,         # derinlik parametresi
  shrinkage = 0.001,             # daraltma adım boyu
  n.cores = NULL, 
  verbose = FALSE
)

5- Tahmin 

Eğitim ve test verisi için ayrı ayrı tahminleme işlemi yapılmıştır. GBM modeli çıktı olarak 0 ve 1 değerlerinin gerçekleşmesi olasılıklarını vermektedir. Çalışmada temerrüt olma durumunu incelediğimiz için, hesaplanan olasılık değerlerinin 1 değerini aldığı DR_OBS (eğitim seti için) ve DR_EST (test seti için) kolonları kullanılmaktadır. DR (default rate) terimi temerrüt oranını ifade etmektedir. 

data_train %<>% 
  bind_cols(predict(object = model_gbm, 
                    data_train[-c(names(data_train) == "default")], 
                    n.trees = model_gbm$n.trees, 
                    type = "response") %>% 
              as_tibble %>% `colnames<-`(c("non_DR_OBS", "DR_OBS"))) %>% 
  select(-non_DR_OBS)
data_test %<>% 
  bind_cols(predict(object = model_gbm, 
                    data_test[-c(names(data_test) == "default")], 
                    n.trees = model_gbm$n.trees, 
                    type = "response") %>% 
              as_tibble %>% `colnames<-`(c("non_DR_EST", "DR_EST"))) %>% 
  select(-non_DR_EST)

6- Risk Verisi Oluşturma

6.1- Kategorizasyon 

Eğitim ve test seti için yapılan tahminlerin veri tipleri süreklidir. İki sürekli değişkeni karşılaştırmak için Mean Square Error (MSE) ve türevleri metrikler kullanmak mümkündür ancak karşılaştırmaları daha anlamlı yapmak için tahminleri kategorize etmek bu veri seti için daha mantıklı olacaktır. Eğitim ve test seti için yapılan tahminleri 5 risk grubana ayrılmıştır. 

data_train %<>% 
  mutate(dr_pool = case_when(DR_OBS >= 0 & DR_OBS < .20 ~ 1,
                             DR_OBS >= .20 & DR_OBS < .40 ~ 2,
                             DR_OBS >= .40 & DR_OBS < .60 ~ 3, 
                             DR_OBS >= .60 & DR_OBS < .80 ~ 4, 
                             TRUE ~ 5))
data_test %<>% 
  mutate(dr_pool = case_when(DR_EST >= 0 & DR_EST < .20 ~ 1,
                             DR_EST >= .20 & DR_EST < .40 ~ 2,
                             DR_EST >= .40 & DR_EST < .60 ~ 3, 
                             DR_EST >= .60 & DR_EST < .80 ~ 4, 
                             TRUE ~ 5))

Eğitim setinde DR_OBS değişkenin ait kategorizasyon işlemi sonrası oluşan veri seti aşağıdaki gibidir. dr_pool değişkeni DR_OBS değişkenindeki tahmin değerlerinin risk gruplarını temsil etmektedir. Yukarıda bahsettiğim tahmin performansı karşılaştırma işlemlerini karegorik verilere uygulama işlemi, pd_pool değişkenleri üzerinden yapılacaktır. 

6.2- Risk Grubu Bazında Birleştirme

Bu bölümde eğitim-test setleri için oluşturulan risk gruplarını birleştirme işlemi yapılmıştır. 

pooled_data_train <- data_train %>% 
  group_by(dr_pool) %>% 
  summarise(DR_OBS = mean(DR_OBS),
            COUNT_OBSERVED = n()) %>% mutate(Data = "TRAIN") %>% 
  select(Data, everything())

pooled_data_test <- data_test %>% 
  group_by(dr_pool) %>% 
  summarise(DR_EST = mean(DR_EST),
            COUNT_ESTIMATED = n()) %>% mutate(Data = "TEST") %>% 
  select(Data, everything()) 

risk_data <- left_join(pooled_data_train, 
                       pooled_data_test, 
                       by = "dr_pool") %>% 
  select(-c(Data.x, Data.y))

Aşağıda elde edilen risk veri setinde gözlenen ve beklenen değerler, tidyriskcredit paketi yardımı ile hem oransal olarak ve hem de risk grubu bazında karşılaştırılabilir. 

7- tidycreditrisk Paketi 

7.1- Anchor Point Testi

Merkezi eğilim değerinin hesaplanan kabul aralıklarının içerisinde olup olmadığını araştırır. 

pooled_data_train %>% 
  anchor_point(df = ., total_observations = "COUNT_OBSERVED", 
               dr_estimate = "DR_OBS", 
               central_tendency = .30)
pooled_data_test %>% 
  anchor_point(df = ., total_observations = "COUNT_ESTIMATED", 
               dr_estimate = "DR_EST", 
               central_tendency = .30)

Yukarıdaki çıktı tablosuna göre, eğitim ve test setlerinde hesaplanan ortalama değerleri, hesaplanan kabul aralığı sınırlarının içerisine düştüğü gözlemlenmiştir. 

7.2- Binom Testi 

Binom testi, tahmin değerleri ile elde edilen güven aralığını gerçek değerler ile karşılaştırır. Sonuç, aşağıdaki karar mekanizmasına göre belirlenmektedir.

Bad Observation > Test Estimation Upper => Target Value Underestimated
Bad Observation < Test Estimation Lower => Target Value Overestimated
Bad Observation values fall within the range obtained => Target Value Correct

risk_data %>% 
binomial_test(df = ., total_observations = "COUNT_OBSERVED", dr_estimate = "DR_EST", dr_observation = "DR_OBS", confidence_level = 0.95)

Her bir risk grubu için tahmin edilen değerler ile gerçek değerler arasında istatistiksel olarak fark olmadığı gözlemlenmiştir. 

7.3- Ayrışım Gücü Testleri

Ayrışım gücü, iki serinin birbirleri ile istatistiksel olarak ayrışıp ayrışmadığını derecelendirerek test etmektedir. Bu bölümde, Kolmogorov-Smirnov ve GINI katsayısına göre ayrışım gücü analizi yapılmıştır.

Kolmogorov-Smirnov;
H0: iki seri aynı dağılıma sahiptir.
H1: İki serinin dağılımı farklıdır

GINI farkın şiddetini ifade etmektedir. Sonuç, aşağıdaki karar mekanizmasına göre belirlenmektedir.  

  • KS < 0.35 => Reject H0, KS ≥ 0.35 => Do not reject H0
  • GINI < 0.40 => Weak, GINI < 0.60 => Medium, GINI < 0.80 => Good, GINI ≥0.80 => Very Good
risk_data %>% discriminatory_tests(df = .,
                                    total_observations = "COUNT_OBSERVED", 
                                    dr_observation = "DR_OBS",
                                    simplfy = F) 

Kolmogorov-Smirnov testine göre iki serinin farklı dağılımlardan geldiği ve GINI değerine göre aralarında zayıf bir ilişki olduğu sonucuna varılmıştır. 

7.4- Herfindahl-Hirschman Endeksi (HHI)

HHI, verideki çeşitliğin yoğunluğunun bir ölçüsüdür. Sonuç, aşağıdaki karar mekanizmasına göre belirlenmektedir.  

  • HHI < 0.20 => There is no concentration.
  • HHI ≤ 0.30 => There is minor concentration.
  • HHI > 0.30 => There is high concentration.
pooled_data_train %>% herfindahl_hirschman_index(df = ., 
                           total_observations = "COUNT_OBSERVED",
                           trace = F)
pooled_data_test %>% herfindahl_hirschman_index(df = ., 
                           total_observations = "COUNT_ESTIMATED",
                           trace = F)

 

Şekilde görüldüğü üzere, eğitim ve test verisindeki dr_pool bazındaki çeşitliliğin ölçümleri yapılmıştır. Eğitim ve test verisinde 2 numaralı risk grubunda %50’nin üzerinde yoğunlaşma olduğu gözlemlenmiştir. Bu sonuçtan hareketle veri setinde dengesizlik olabileceği göz önünde bulundurulmalıdır. 

7.5- Kitle Durağanlık Endeksi (Population Stability Index)

PSI, iki veri seti arasındaki durağanlığı inceler. Sonuç, aşağıdaki karar mekanizmasına göre belirlenmektedir.  

  • PSI < 0.10 => Insignificant change in population.
  • PSI ≤ 0.25 => Minor shift in population.
  • PSI > 0.25 => Major shift in population.
risk_data %>% psi(df = ., count_observed = "COUNT_OBSERVED", count_estimated = "COUNT_ESTIMATED",trace = T, simplfy = F)

PSI değeri 0.0152 olduğundan iki seri arasında PSI değerine göre farklılaşma yoktur. 

7.6- Traffic Light Testleri

Traffic Light Testleri iki seri arasındaki farkın şiddetine göre değerini yeşil, sarı, kırmızı renklendirerek açıklayan bir yöntemdir. Sonuç, aşağıdaki karar mekanizmasına göre belirlenmektedir.  

Test Statistics < 0.01 => Red
Test Statistics ≤ 0.05 => Orange
Test Statistics > 0.05 => Green

risk_data %>% traffic_light_tests(df = ., 
                                  total_observations = "COUNT_OBSERVED", 
                                  dr_observation = "DR_OBS", 
                                  dr_estimate = "DR_EST", 
                                  rho = 0.07)

 

 dr_pool bazında eğitim ve test verisindeki değerlerin arasında istatistiksel olarak anlamlı olmadığı görselleştirilmiştir. Hesaplanan test istatistiği değerlerinin %5 değerinden büyük olması sebebiyle risk grubu değerlerinin eğitim ve test verisi için ayrışmadığı gözlemlenmiştir. 

8- Frekans Tabloları 

8.1- Kategorik Değişkenler

Veri setindeki kategorik değişkenlerin frekansile tablolarış oluşturulur. Frekanslar ile ilgili olan analizler bu tablolar yardımı ile yapılabilir. 

train_frequency <- get_frequency_table(data_train %>% 
                                         select_if(., is.factor), 
                                       y_target = "default")      
train_frequency
test_frequency <- get_frequency_table(data_test %>% 
                                        select_if(., is.factor), 
                                      y_target = "default")
test_frequency

Yukarıda faktör olarak atanan değişkenlerin frekans tabloları hesaplanmıştır. Bu tablolar üzerinden HHI ve PSI yöntemlerini uygulamak için farklı bir fonksiyon yapısı kullanılmaktadır. 

HHI için; 

herfindahl_hirschman_index_table(df=train_frequency, 
                                 total_observations = "OBSERVATION",
                                 simplfy = F)
herfindahl_hirschman_index_table(df=test_frequency, 
                                 total_observations = "OBSERVATION", 
                                 simplfy = F)

herfindahl_hirschman_index_table() fonksiyonu ile frekans tablosu oluşturulmuş bir değişkenin yoğunluğu ölçülebilir. 

Eğitim ve test seti için faktör değişkenlerine ait yoğunluklar yukardaki gibi ölçülmüştür. Yüksek yoğunluğa sahip değişkenler, modelleme öncesinde bu tarz yöntemlerle tespit edilmeli gerekiyorsa downsampling yöntemleri ile veri seti küçültülüp dengeli bir yapı oluşturulmalıdır.

 PSI için;

psi_table(df = train_frequency, 
          df_column = "DATA", 
          count_observed = "OBSERVATION", 
          count_estimated = "SUBTOTAL_OBSERVATION",
          simplfy = T)
psi_table(df = test_frequency, 
          df_column = "DATA", 
          count_observed = "OBSERVATION", 
          count_estimated = "SUBTOTAL_OBSERVATION",
          simplfy = T)

psi_table() fonksiyonu ile, oluşturulan frekans tablolarını kullanarak faktör değişkenlerinin eğitim test seti arasındaki durağanlığını ölçmek mümkündür. 

Eğitim ve test setlerinde faktör değişkenlerinin farklılaşıp farklılaşmadığını görebiliyoruz. Şekilde görüldüğü üzere küçük farklılıklar olduğu ölçülmüştür. 

8.2- Sürekli Değişkenler 

Veri setindeki sürekli değişkeni kendi içerisinde kategorilere ayırarak, bağımlı değişken olan default değişkeni ile aralarındaki frekans dağılımlarını incelemek için get_risk_table() fonksiyonu kullanılmıştır. Aşağıda data_train veri setindeki duration, telephone, foreignWorker ve amount değişkenlerinin, default değerine göre frekans dağılımları hesaplanmıştır. Görselde sadece duration değişkeninin dağılımı gösterilmiştir.

get_risk_table(df_master = data_train, 
               df_new = data_test_wt, 
               y_target = "default",
               x_target = c("telephone", "foreignWorker", "amount")) %>% 
  filter(KEY == "duration") %>% unnest(RISK_DATA)

Yukarıda duration değişkenindeki gözlemleri 6 kategoriye ayırarak, bu kategorilerin default değişkeni ile aralarındaki frekans dağılımlarının tablosu oluşturulmuştur. Sonuç olarak sürekli değişkenlerdeki yoğunluğu gözlemleyebilmek için, değişkeni 6 kategoriye indirgeyerek bağımlı değişken ile aralarındaki ilişkiyi gözlemlemek mümkün olmuştur.

Kredi riski hesaplamalarında veri farklı kaynaklardan geldiği için verinin dağılımı hakkında bilgiye sahip olmadan herhangi bir varsayım kontrolü veya modelleme işlemi yapmak doğru değildir. Yoğunluk, hedef değişkenin kategorik olduğu bir veri setinin karakteristiğidir. Dolayısıyla iki veri setini karşılaştırmak için, veriye farklı yönlerinden yaklaşarak yoğunluklarını farklı yöntemlerle ölçmek ve yorumlamak gereklidir.

Kullanılan fonksiyonlara Github hesabımdan ulaşabilirsiniz. 

Hepinize sağlıklı günler dilerim.

 

 

Yazar Hakkında
Toplam 13 yazı
Mustafa Nayansak
Mustafa Nayansak
Yorumlar (Yorum yapılmamış)

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

×

Bir Şeyler Ara