Περιγραφή του Dataset και Πηγή

Το dataset περιλαμβάνει πληροφορίες για 45.000 πελάτες που έχουν αιτηθεί για προσωπικά δάνεια. Περιλαμβάνει χαρακτηριστικά όπως ηλικία, εισόδημα, σκοπός δανείου, εμπειρία, ιστορικό πίστωσης, και αν ο πελάτης αποπλήρωσε ή όχι το δάνειό του.

Πηγή: Το dataset διατίθεται από το Kaggle.

Επιχειρηματική Αναλυτική – Αιτιολόγηση Επιλογής

Η πρόβλεψη πιθανής καθυστέρησης πληρωμής ενός δανείου είναι κρίσιμη για τα χρηματοπιστωτικά ιδρύματα. Μέσω αυτής της ανάλυσης, μπορούμε να εντοπίσουμε προφίλ πελατών με αυξημένο ρίσκο, να διαμορφώσουμε καλύτερες πολιτικές αξιολόγησης και να βελτιώσουμε τις διαδικασίες έγκρισης δανείων.

Πιθανά Επιχειρηματικά Ερωτήματα

  • Ποιοι παράγοντες αυξάνουν τον κίνδυνο αθέτησης πληρωμής;
  • Ποιοι πελάτες είναι περισσότερο αξιόπιστοι;
  • Υπάρχουν δημογραφικά πρότυπα που επηρεάζουν το ρίσκο;

Διάβασμα δεδομένων

loan_data <- read.csv("C:/Users/User/Downloads/loan_data.csv")

Περιγραφή Μεταβλητών

Πίνακας Περιγραφής Μεταβλητών
Μεταβλητή Τύπος
person_age Αριθμητικό
person_gender Κατηγορική
person_education Κατηγορική
person_income Αριθμητικό
person_emp_exp Αριθμητικό
person_home_ownership Κατηγορική
loan_amnt Αριθμητικό
loan_intent Κατηγορική
loan_int_rate Αριθμητικό
loan_percent_income Αριθμητικό
cb_person_cred_hist_length Αριθμητικό
credit_score Αριθμητικό
previous_loan_defaults_on_file Κατηγορική
loan_status Δυαδικό

Περιγραφικά Στατιστικά

summary(loan_data)
##    person_age     person_gender      person_education   person_income    
##  Min.   : 20.00   Length:45000       Length:45000       Min.   :   8000  
##  1st Qu.: 24.00   Class :character   Class :character   1st Qu.:  47204  
##  Median : 26.00   Mode  :character   Mode  :character   Median :  67048  
##  Mean   : 27.76                                         Mean   :  80319  
##  3rd Qu.: 30.00                                         3rd Qu.:  95789  
##  Max.   :144.00                                         Max.   :7200766  
##  person_emp_exp   person_home_ownership   loan_amnt     loan_intent       
##  Min.   :  0.00   Length:45000          Min.   :  500   Length:45000      
##  1st Qu.:  1.00   Class :character      1st Qu.: 5000   Class :character  
##  Median :  4.00   Mode  :character      Median : 8000   Mode  :character  
##  Mean   :  5.41                         Mean   : 9583                     
##  3rd Qu.:  8.00                         3rd Qu.:12237                     
##  Max.   :125.00                         Max.   :35000                     
##  loan_int_rate   loan_percent_income cb_person_cred_hist_length  credit_score  
##  Min.   : 5.42   Min.   :0.0000      Min.   : 2.000             Min.   :390.0  
##  1st Qu.: 8.59   1st Qu.:0.0700      1st Qu.: 3.000             1st Qu.:601.0  
##  Median :11.01   Median :0.1200      Median : 4.000             Median :640.0  
##  Mean   :11.01   Mean   :0.1397      Mean   : 5.867             Mean   :632.6  
##  3rd Qu.:12.99   3rd Qu.:0.1900      3rd Qu.: 8.000             3rd Qu.:670.0  
##  Max.   :20.00   Max.   :0.6600      Max.   :30.000             Max.   :850.0  
##  previous_loan_defaults_on_file  loan_status    
##  Length:45000                   Min.   :0.0000  
##  Class :character               1st Qu.:0.0000  
##  Mode  :character               Median :0.0000  
##                                 Mean   :0.2222  
##                                 3rd Qu.:0.0000  
##                                 Max.   :1.0000

Δημιουργία του καθαρισμένου dataset (αφαίρεση outliers)

Βλέπουμε μερικά πολύ σημαντικά outliers στο σύνολο δεδομένων μας.Είναι σημαντικό να αφαιρεθούν ώστε να μην επηρεαστούν αρνητικά οι προβλέψεις μας.

loan_data_clean <- loan_data %>%
  filter(person_age <= 90, person_emp_exp <= 70, person_income <= 5000000)

Διαγράμματα

1. Scatterplot – Ηλικία και Χρόνια Εργασιακής Εμπειρίας

ggplot(loan_data_clean, aes(x = person_age, y = person_emp_exp, color = factor(loan_status))) +
  geom_jitter(alpha = 0.5, width = 0.3, height = 0.3) +
  labs(title = "Years of Experience vs. Age (Colored by Loan Status)",
       x = "Age", y = "Employment Experience",
       color = "Loan Status\n(0 = No Default, 1 = Defaulted)") +
  scale_color_manual(values = c("red", "blue"),
                     labels = c("No Default", "Defaulted")) +
  theme_minimal()

Διάγραμμα 1. Σχέση Ηλικίας και Εμπειρίας ανά Κατάσταση Δανείου.

Σχόλιο: Οι περισσότερες καθυστερήσεις συμβαίνουν σε άτομα με χαμηλή εμπειρία και ηλικία.

2. Boxplot – Ποσό Δανείου ανά Κατοχή Κατοικίας

ggplot(loan_data_clean, aes(x = person_home_ownership, y = loan_amnt, fill = factor(loan_status))) +
  geom_boxplot() +
  labs(title = "Loan Amount by Home Ownership",
       x = "Home Ownership", y = "Loan Amount ($)",
       fill = "Loan Status") +
  theme_minimal()

Διάγραμμα 2. Ποσό Δανείου ανά Κατοχή Κατοικίας.

Σχόλιο: Οι ιδιοκτήτες κατοικίας φαίνεται να λαμβάνουν μικρότερα δάνεια με λιγότερες καθυστερήσεις, ενώ οι ενοικιαστές εμφανίζουν μεγαλύτερη διακύμανση και υψηλότερο ρίσκο καθυστέρησης.

3. Ιστόγραμμα – Εισόδημα και Κατάσταση Δανείου

ggplot(loan_data_clean, aes(x = person_income, fill = factor(loan_status))) +
  geom_histogram(position = "identity", alpha = 0.6, bins = 50) +
  labs(title = "Income Distribution by Loan Status",
       x = "Income", y = "Count", fill = "Loan Status") +
  theme_minimal()

Διάγραμμα 3. Κατανομή Εισοδήματος με βάση την Κατάσταση Δανείου.

Σχόλιο: Οι χαμηλότεροι μισθοί σχετίζονται με υψηλότερο ποσοστό καθυστέρησης.

4. Bar Chart – Εκπαίδευση και Κατάσταση Δανείου

ggplot(loan_data_clean, aes(x = person_education, fill = factor(loan_status))) +
  geom_bar(position = "dodge", color = "black") +
  labs(title = "Loan Status by Person Education",
       x = "Education Level", y = "Count",
       fill = "Loan Status\n(0 = No Default, 1 = Defaulted)") +
  theme_light()

Διάγραμμα 4. Κατάσταση Δανείου ως προς την Εκπαίδευση.

Σχόλιο: Οι δανειολήπτες με υψηλότερη εκπαίδευση φαίνεται να έχουν μικρότερα ποσοστά καθυστέρησης.

Επιλογή Μεταβλητών για Συσταδοποίηση

Για λόγους απλότητας, και εύκολης αντίληψης των διαγραμμάτων, ανάμεσα σε όλες τις αριθμητικές μεταβλητές, θα επιλεχθούν δύο. Ποιες όμως αποτελούν την καλύτερη επιλογή; Για αυτήν την απάντηση θα χρησιμοποιήσουμε την διασπορά και την συσχέτηση των μεταβλητών.

Train <- loan_data_clean
# Επιλογή αριθμητικών στηλών
numeric_vars <- Train[, sapply(Train, is.numeric)]

# Υπολογισμός διασποράς κάθε μεταβλητής
variances <- sapply(numeric_vars, var, na.rm = TRUE)

# Εμφάνιση διασποράς σε φθήνουσα σειρά
variances_sorted <- sort(variances, decreasing = TRUE)
print(variances_sorted)
##              person_income                  loan_amnt 
##               4.009726e+09               3.987741e+07 
##               credit_score             person_emp_exp 
##               2.540021e+03               3.502119e+01 
##                 person_age cb_person_cred_hist_length 
##               3.482821e+01               1.502283e+01 
##              loan_int_rate                loan_status 
##               8.874551e+00               1.728653e-01 
##        loan_percent_income 
##               7.605037e-03
# bar plot
barplot(variances_sorted, las = 2, col = "skyblue", 
        main = "Διασπορά μεταβλητών", ylab = "Variance")

Η διασπορά μάς δίνει πληροφορίες για το πόσο διαφορετικές είναι οι τιμές μιας μεταβλητής από τον μέσο όρο της — δηλαδή, πόση πληροφορία (ή ποικιλία) κουβαλάει η κάθε μεταβλητή.

Όπως φαίνεται στο παραπάνω διάγραμμα, η μεταβλητή person_income έχει πολύ υψηλότερη διασπορά σε σύγκριση με όλες τις υπόλοιπες. Αυτό σημαίνει ότι περιέχει σημαντική διαφοροποίηση στις τιμές της και επομένως μπορεί να προσφέρει ουσιαστικό διαχωρισμό μεταξύ των παρατηρήσεων. Οι υπόλοιπες μεταβλητές εμφανίζουν σχετικά χαμηλή διασπορά, γεγονός που τις καθιστά λιγότερο χρήσιμες για τον σχηματισμό διακριτών ομάδων.

Επομένως, η person_income είναι ισχυρή υποψήφια μεταβλητή για να χρησιμοποιηθεί στη διαδικασία συσταδοποίησης.

Αφού βρήκαμε ποιες μεταβλητές έχουν σημαντική διασπορά (variance), πρέπει τώρα να ελέγξουμε ποιες από αυτές δεν είναι πολύ συσχετισμένες μεταξύ τους. Αν δύο μεταβλητές έχουν πολύ υψηλή συσχέτιση (π.χ. > 0.85), σημαίνει ότι “μεταφέρουν” την ίδια πληροφορία. Στη συσταδοποίηση, αυτό μπορεί να προκαλέσει παραμόρφωση και επαναλαμβανόμενη πληροφορία.

# Επιλογή μόνο αριθμητικών μεταβλητών
numeric_vars <- loan_data_clean[, sapply(loan_data_clean, is.numeric)]

# Υπολογισμός πίνακα συσχέτισης (χωρίς NAs)
cor_matrix <- cor(numeric_vars, use = "complete.obs")

# Προβολή πίνακα
print(round(cor_matrix, 2))
##                            person_age person_income person_emp_exp loan_amnt
## person_age                       1.00          0.15           0.95      0.05
## person_income                    0.15          1.00           0.14      0.31
## person_emp_exp                   0.95          0.14           1.00      0.05
## loan_amnt                        0.05          0.31           0.05      1.00
## loan_int_rate                    0.01          0.00           0.02      0.15
## loan_percent_income             -0.04         -0.29          -0.04      0.59
## cb_person_cred_hist_length       0.88          0.13           0.84      0.04
## credit_score                     0.17          0.03           0.18      0.01
## loan_status                     -0.02         -0.17          -0.02      0.11
##                            loan_int_rate loan_percent_income
## person_age                          0.01               -0.04
## person_income                       0.00               -0.29
## person_emp_exp                      0.02               -0.04
## loan_amnt                           0.15                0.59
## loan_int_rate                       1.00                0.13
## loan_percent_income                 0.13                1.00
## cb_person_cred_hist_length          0.02               -0.03
## credit_score                        0.01               -0.01
## loan_status                         0.33                0.38
##                            cb_person_cred_hist_length credit_score loan_status
## person_age                                       0.88         0.17       -0.02
## person_income                                    0.13         0.03       -0.17
## person_emp_exp                                   0.84         0.18       -0.02
## loan_amnt                                        0.04         0.01        0.11
## loan_int_rate                                    0.02         0.01        0.33
## loan_percent_income                             -0.03        -0.01        0.38
## cb_person_cred_hist_length                       1.00         0.15       -0.01
## credit_score                                     0.15         1.00       -0.01
## loan_status                                     -0.01        -0.01        1.00
# heatmap
library(corrplot)
## corrplot 0.95 loaded
corrplot(cor_matrix, method = "color", type = "upper",
         tl.col = "black", tl.cex = 0.8, order = "hclust",
         title = "Πίνακας Συσχέτισης Αριθμητικών Μεταβλητών")

Από τον πίνακα συσχέτισης προκύπτει ότι ορισμένες μεταβλητές παρουσιάζουν υψηλή μεταξύ τους συσχέτιση, όπως οι person_age και person_emp_exp, ή loan_amnt και person_income. Αυτό καθιστά ανεπιθύμητη την κοινή χρήση τους στη συσταδοποίηση, καθώς θα μεταφέρουν παρόμοια πληροφορία. Αντίθετα, οι μεταβλητές loan_percent_income, loan_int_rate και credit_score εμφανίζουν χαμηλή μεταξύ τους συσχέτιση και διαφορετική πληροφορία, γεγονός που τις καθιστά πιο κατάλληλες για χρήση σε clustering.

Για την εφαρμογή συσταδοποίησης (clustering), θα επιλεχθούν λοιπόν οι μεταβλητές person_income και loan_int_rate. Η person_income παρουσιάζει τη μεγαλύτερη διασπορά ανάμεσα στις αριθμητικές μεταβλητές, άρα προσφέρει πλούσια πληροφορία και συμβάλλει ουσιαστικά στον διαχωρισμό των ομάδων. Από την άλλη, η loan_int_rate εμφανίζει χαμηλή συσχέτιση με το εισόδημα, συνεπώς προσθέτει ανεξάρτητη πληροφορία στο μοντέλο και ενισχύει τη διακριτική ικανότητα του clustering. Η επιλογή αυτών των δύο μεταβλητών εξασφαλίζει καλύτερη ποιότητα συσταδοποίησης και πιο ερμηνεύσιμα αποτελέσματα.

# Δημιουργία νέου dataset με τις επιλεγμένες μεταβλητές
cluster_data <- loan_data_clean %>%
  select(person_income, loan_int_rate)

# Κανονικοποίηση 
scaled_data <- scale(cluster_data)

Η κανονικοποίηση είναι απαραίτητη επειδή το person_income έχει πολύ μεγαλύτερη κλίμακα από το loan_int_rate, και αυτό θα επηρεάσει άδικα τους υπολογισμούς απόστασης.

Ιεραρχική Συσταδοποίηση

set.seed(123)
sample_data <- scaled_data[sample(1:nrow(scaled_data), 2000), ]  # δείγμα 2000 γραμμών

# υπολογισμός αποστάσεων και συσταδοποίηση
dist_matrix <- dist(sample_data, method = "euclidean")
hc_model <- hclust(dist_matrix, method = "ward.D2")
plot(hc_model, labels = FALSE, main = "Ιεραρχική Συσταδοποίηση (Δείγμα 2000)")

Λόγω του μεγάλου μεγέθους του dataset (45.000 παρατηρήσεις), η ιεραρχική συσταδοποίηση δεν μπορεί να εφαρμοστεί σε όλα τα δεδομένα, καθώς απαιτεί τεράστια μνήμη RAM για να υπολογίσει τον πίνακα αποστάσεων. Για τον λόγο αυτό, χρησιμοποιήθηκε ένα τυχαίο υποσύνολο 2000 παρατηρήσεων, το οποίο είναι επαρκές για να παρατηρηθεί η δομή των συστάδων και η γενική εικόνα του δενδρογράμματος.

Το δενδρόγραμμα που προέκυψε από την ιεραρχική συσταδοποίηση με τη μέθοδο Ward.D2 απεικονίζει τη σταδιακή συγχώνευση παρατηρήσεων και ομάδων βάσει της μεταξύ τους ομοιότητας. Παρατηρείται ότι οι συστάδες σχηματίζονται με σαφήνεια σε δύο ή τρεις βασικούς κλάδους, κάτι που υποδηλώνει την ύπαρξη φυσικού διαχωρισμού στο δείγμα.

clusters_hc <- cutree(hc_model, k = 3)
table(clusters_hc)
## clusters_hc
##    1    2    3 
## 1378  619    3

Η συσταδοποίηση σε 3 ομάδες αποκάλυψε μία πολύ μικρή ομάδα (3 παρατηρήσεις), η οποία πιθανότατα αντιπροσωπεύει ακραίες τιμές (outliers), δηλαδή άτομα με ιδιαίτερα υψηλό εισόδημα ή πολύ διαφορετικά χαρακτηριστικά από το υπόλοιπο δείγμα. Οι δύο βασικές συστάδες περιλαμβάνουν τον κύριο όγκο των πελατών, διαχωρίζοντας πιθανώς μεταξύ μεσαίου/χαμηλού εισοδήματος και συγκριτικά υψηλότερου. Η παρουσία της πολύ μικρής συστάδας δείχνει ότι η ιεραρχική συσταδοποίηση μπορεί να ανιχνεύσει υποσύνολα σπάνιων περιπτώσεων, ενισχύοντας τη δυνατότητα στοχευμένης ανάλυσης σε μελλοντική επιχειρησιακή στρατηγική.

Συσταδοποίηση με K-Means

Επιλέγουμε k=3, καθώς από την ιεραρχική συσταδοποίηση φάνηκε να γίνεται ένας καλός διαχωρισμός.

# Εκπαίδευση K-means με 3 συστάδες
set.seed(123)
kmeans_model_3 <- kmeans(scaled_data, centers = 3, nstart = 25)

# Προσθήκη cluster labels
cluster_data$cluster3 <- factor(kmeans_model_3$cluster)

# Μέγεθος συστάδων
table(cluster_data$cluster3)
## 
##     1     2     3 
## 25802 17282  1908
ggplot(cluster_data, aes(x = person_income, y = loan_int_rate, color = cluster3)) +
  geom_point(alpha = 0.6) +
  labs(title = "K-Means με 3 Συστάδες",
       x = "Εισόδημα", y = "Επιτόκιο",
       color = "Συστάδα") +
  theme_minimal()

Το παραπάνω διάγραμμα παρουσιάζει την οπτική αναπαράσταση των 3 συστάδων που προέκυψαν με τον αλγόριθμο K-Means, βάσει των μεταβλητών εισόδημα (person_income) και επιτόκιο δανείου (loan_int_rate). Οι συστάδες φαίνεται να διαφοροποιούνται κυρίως ως προς το εισόδημα:

Η πρώτη συστάδα (κόκκινη) συγκεντρώνει άτομα με πολύ χαμηλό εισόδημα και υψηλά επιτόκια.

Η δεύτερη συστάδα (πράσινη) περιλαμβάνει πελάτες με μέτριο εισόδημα και μέτρια επιτόκια.

Η τρίτη συστάδα (μπλε) περιλαμβάνει άτομα με πολύ υψηλά εισοδήματα, ανεξαρτήτως επιτοκίου — πιθανότατα πρόκειται για outliers.

Η ταξινόμηση των παρατηρήσεων είναι εύλογη και αποκαλύπτει χρήσιμες ομάδες πελατών. Η διαφοροποίηση με βάση το εισόδημα είναι κυρίαρχη, ενώ το επιτόκιο λειτουργεί επικουρικά στον σχηματισμό των ομάδων. Το γεγονός ότι η τρίτη συστάδα είναι διακριτή και μικρή, επιβεβαιώνει την παρουσία μιας ομάδας πελατών με ιδιαίτερο οικονομικό προφίλ.

# Elbow Method για εύρεση βέλτιστου αριθμού συστάδων
set.seed(123)

# Υπολογισμός WCSS (Within Cluster Sum of Squares) για 1 έως 10 συστάδες
wcss <- numeric(10)

for (k in 1:10) {
  kmeans_model <- kmeans(scaled_data, centers = k, nstart = 20)
  wcss[k] <- kmeans_model$tot.withinss
}
## Warning: did not converge in 10 iterations
## Warning: did not converge in 10 iterations
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 2249600)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 2249600)
# Διάγραμμα Elbow
plot(1:10, wcss, type = "b", pch = 19, col = "steelblue",
     xlab = "Αριθμός Συστάδων (k)",
     ylab = "WCSS (Συνολικό Σφάλμα Εντός Συστάδων)",
     main = "Elbow Method για Επιλογή k")

Σύμφωνα με τη μέθοδο “Elbow”, η βέλτιστη τιμή του k εντοπίζεται γύρω στο 3, καθώς από εκεί και πέρα η μείωση στο WCSS γίνεται πιο ήπια. Το αποτέλεσμα αυτό επιβεβαιώνει την ανάλυση της ιεραρχικής συσταδοποίησης, όπου παρατηρήθηκαν 2 βασικές ομάδες και μία τρίτη μικρή (πιθανώς αποτελούμενη από outliers). Συνεπώς, η επιλογή 3 συστάδων στον αλγόριθμο K-Means θεωρείται αιτιολογημένη και στατιστικά ορθή.