Δέντρα απόφασης πάνω στο dataset credit card clients.
Η παρούσα εργασία επικεντρώνεται στην ανάλυση ενός dataset σχετικού με την πρόβλεψη αθέτησης πληρωμών από πελάτες πιστωτικών καρτών. Χρησιμοποιώντας το περιβάλλον R θα εξετάσουμε τη δομή των δεδομένων, θα εντοπίσουμε σχέσεις μεταξύ μεταβλητών και θα υλοποιήσουμε μοντέλα πρόβλεψης όπως δέντρα απόφασης (CART).
Η ανάλυση περιλαμβάνει: - Εισαγωγή και καθαρισμό του dataset - Διερεύνηση των συσχετίσεων μεταξύ μεταβλητών μέσω πίνακα συσχετίσεων - Εκπαίδευση και αξιολόγηση μοντέλων CART - Υπολογισμό μετρικών απόδοσης και συγκρίσεις με baseline (θα μπορούσαμε και λογιστικά μοντέλα) - Χρήση cross-validation για βελτιστοποίηση του δέντρου
Στόχος είναι να αναδείξουμε πώς ένα μοντέλο βασισμένο σε δέντρο μπορεί να δώσει ερμηνεύσιμα και αποδοτικά αποτελέσματα στην πρόβλεψη συμπεριφοράς πελατών.
## Rows: 30000 Columns: 24
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): SEX, EDUCATION, MARRIAGE
## dbl (21): LIMIT_BAL, AGE, PAY_0, PAY_2, PAY_3, PAY_4, PAY_5, PAY_6, BILL_AMT...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Εμφανίζει τις πρώτες 5 εγγραφές του πίνακα credit, ώστε να πάρουμε μια πρώτη εικόνα των δεδομένων. Χρήσιμο για να δούμε τα πρώτα δεδομένα κάθε στήλης και να εντοπίσουμε γρήγορα πιθανά προβλήματα (π.χ. κενά, περίεργες τιμές κ.λπ.).
head(credit) # Πρώτες 5 εγγραφές
## # A tibble: 6 × 24
## LIMIT_BAL SEX EDUCATION MARRIAGE AGE PAY_0 PAY_2 PAY_3 PAY_4 PAY_5 PAY_6
## <dbl> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 20000 Female University Married 24 2 2 -1 -1 -2 -2
## 2 120000 Female University Single 26 -1 2 0 0 0 2
## 3 90000 Female University Single 34 0 0 0 0 0 0
## 4 50000 Female University Married 37 0 0 0 0 0 0
## 5 50000 Male University Married 57 -1 0 -1 0 0 0
## 6 50000 Male Graduate … Single 37 0 0 0 0 0 0
## # ℹ 13 more variables: BILL_AMT1 <dbl>, BILL_AMT2 <dbl>, BILL_AMT3 <dbl>,
## # BILL_AMT4 <dbl>, BILL_AMT5 <dbl>, BILL_AMT6 <dbl>, PAY_AMT1 <dbl>,
## # PAY_AMT2 <dbl>, PAY_AMT3 <dbl>, PAY_AMT4 <dbl>, PAY_AMT5 <dbl>,
## # PAY_AMT6 <dbl>, default <dbl>
Δείχνει βασικά περιγραφικά στατιστικά για κάθε μεταβλητή του dataset
summary(credit) # Περιγραφικά στατιστικά
## LIMIT_BAL SEX EDUCATION MARRIAGE
## Min. : 10000 Length:30000 Length:30000 Length:30000
## 1st Qu.: 50000 Class :character Class :character Class :character
## Median : 140000 Mode :character Mode :character Mode :character
## Mean : 167484
## 3rd Qu.: 240000
## Max. :1000000
## AGE PAY_0 PAY_2 PAY_3
## Min. :21.00 Min. :-2.0000 Min. :-2.0000 Min. :-2.0000
## 1st Qu.:28.00 1st Qu.:-1.0000 1st Qu.:-1.0000 1st Qu.:-1.0000
## Median :34.00 Median : 0.0000 Median : 0.0000 Median : 0.0000
## Mean :35.49 Mean :-0.0167 Mean :-0.1338 Mean :-0.1662
## 3rd Qu.:41.00 3rd Qu.: 0.0000 3rd Qu.: 0.0000 3rd Qu.: 0.0000
## Max. :79.00 Max. : 8.0000 Max. : 8.0000 Max. : 8.0000
## PAY_4 PAY_5 PAY_6 BILL_AMT1
## Min. :-2.0000 Min. :-2.0000 Min. :-2.0000 Min. :-165580
## 1st Qu.:-1.0000 1st Qu.:-1.0000 1st Qu.:-1.0000 1st Qu.: 3559
## Median : 0.0000 Median : 0.0000 Median : 0.0000 Median : 22382
## Mean :-0.2207 Mean :-0.2662 Mean :-0.2911 Mean : 51223
## 3rd Qu.: 0.0000 3rd Qu.: 0.0000 3rd Qu.: 0.0000 3rd Qu.: 67091
## Max. : 8.0000 Max. : 8.0000 Max. : 8.0000 Max. : 964511
## BILL_AMT2 BILL_AMT3 BILL_AMT4 BILL_AMT5
## Min. :-69777 Min. :-157264 Min. :-170000 Min. :-81334
## 1st Qu.: 2985 1st Qu.: 2666 1st Qu.: 2327 1st Qu.: 1763
## Median : 21200 Median : 20089 Median : 19052 Median : 18105
## Mean : 49179 Mean : 47013 Mean : 43263 Mean : 40311
## 3rd Qu.: 64006 3rd Qu.: 60165 3rd Qu.: 54506 3rd Qu.: 50191
## Max. :983931 Max. :1664089 Max. : 891586 Max. :927171
## BILL_AMT6 PAY_AMT1 PAY_AMT2 PAY_AMT3
## Min. :-339603 Min. : 0 Min. : 0 Min. : 0
## 1st Qu.: 1256 1st Qu.: 1000 1st Qu.: 833 1st Qu.: 390
## Median : 17071 Median : 2100 Median : 2009 Median : 1800
## Mean : 38872 Mean : 5664 Mean : 5921 Mean : 5226
## 3rd Qu.: 49198 3rd Qu.: 5006 3rd Qu.: 5000 3rd Qu.: 4505
## Max. : 961664 Max. :873552 Max. :1684259 Max. :896040
## PAY_AMT4 PAY_AMT5 PAY_AMT6 default
## Min. : 0 Min. : 0.0 Min. : 0.0 Min. :0.0000
## 1st Qu.: 296 1st Qu.: 252.5 1st Qu.: 117.8 1st Qu.:0.0000
## Median : 1500 Median : 1500.0 Median : 1500.0 Median :0.0000
## Mean : 4826 Mean : 4799.4 Mean : 5215.5 Mean :0.2212
## 3rd Qu.: 4013 3rd Qu.: 4031.5 3rd Qu.: 4000.0 3rd Qu.:0.0000
## Max. :621000 Max. :426529.0 Max. :528666.0 Max. :1.0000
str(credit) # Δομή δεδομένων
## spc_tbl_ [30,000 × 24] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ LIMIT_BAL: num [1:30000] 20000 120000 90000 50000 50000 50000 500000 100000 140000 20000 ...
## $ SEX : chr [1:30000] "Female" "Female" "Female" "Female" ...
## $ EDUCATION: chr [1:30000] "University" "University" "University" "University" ...
## $ MARRIAGE : chr [1:30000] "Married" "Single" "Single" "Married" ...
## $ AGE : num [1:30000] 24 26 34 37 57 37 29 23 28 35 ...
## $ PAY_0 : num [1:30000] 2 -1 0 0 -1 0 0 0 0 -2 ...
## $ PAY_2 : num [1:30000] 2 2 0 0 0 0 0 -1 0 -2 ...
## $ PAY_3 : num [1:30000] -1 0 0 0 -1 0 0 -1 2 -2 ...
## $ PAY_4 : num [1:30000] -1 0 0 0 0 0 0 0 0 -2 ...
## $ PAY_5 : num [1:30000] -2 0 0 0 0 0 0 0 0 -1 ...
## $ PAY_6 : num [1:30000] -2 2 0 0 0 0 0 -1 0 -1 ...
## $ BILL_AMT1: num [1:30000] 3913 2682 29239 46990 8617 ...
## $ BILL_AMT2: num [1:30000] 3102 1725 14027 48233 5670 ...
## $ BILL_AMT3: num [1:30000] 689 2682 13559 49291 35835 ...
## $ BILL_AMT4: num [1:30000] 0 3272 14331 28314 20940 ...
## $ BILL_AMT5: num [1:30000] 0 3455 14948 28959 19146 ...
## $ BILL_AMT6: num [1:30000] 0 3261 15549 29547 19131 ...
## $ PAY_AMT1 : num [1:30000] 0 0 1518 2000 2000 ...
## $ PAY_AMT2 : num [1:30000] 689 1000 1500 2019 36681 ...
## $ PAY_AMT3 : num [1:30000] 0 1000 1000 1200 10000 657 38000 0 432 0 ...
## $ PAY_AMT4 : num [1:30000] 0 1000 1000 1100 9000 ...
## $ PAY_AMT5 : num [1:30000] 0 0 1000 1069 689 ...
## $ PAY_AMT6 : num [1:30000] 0 2000 5000 1000 679 ...
## $ default : num [1:30000] 1 1 0 0 0 0 0 0 0 0 ...
## - attr(*, "spec")=
## .. cols(
## .. LIMIT_BAL = col_double(),
## .. SEX = col_character(),
## .. EDUCATION = col_character(),
## .. MARRIAGE = col_character(),
## .. AGE = col_double(),
## .. PAY_0 = col_double(),
## .. PAY_2 = col_double(),
## .. PAY_3 = col_double(),
## .. PAY_4 = col_double(),
## .. PAY_5 = col_double(),
## .. PAY_6 = col_double(),
## .. BILL_AMT1 = col_double(),
## .. BILL_AMT2 = col_double(),
## .. BILL_AMT3 = col_double(),
## .. BILL_AMT4 = col_double(),
## .. BILL_AMT5 = col_double(),
## .. BILL_AMT6 = col_double(),
## .. PAY_AMT1 = col_double(),
## .. PAY_AMT2 = col_double(),
## .. PAY_AMT3 = col_double(),
## .. PAY_AMT4 = col_double(),
## .. PAY_AMT5 = col_double(),
## .. PAY_AMT6 = col_double(),
## .. default = col_double()
## .. )
## - attr(*, "problems")=<externalptr>
## [1] 30000 24
## Το dataset περιέχει 30000 εγγραφές και 24 μεταβλητές.
Το dataset default of credit card clients περιλαμβάνει
στοιχεία πελατών σχετικά με τις πιστωτικές τους κάρτες και αν τελικά
αθέτησαν πληρωμή (default) ή όχι. Περιέχει τις εξής μεταβλητές:
| Μεταβλητή | Περιγραφή |
|---|---|
| LIMIT_BAL | Πίστωση που παραχωρήθηκε στον πελάτη (σε ΝΤ) |
| SEX | Φύλο του πελάτη (1 = Άνδρας, 2 = Γυναίκα) |
| EDUCATION | Εκπαιδευτικό επίπεδο (1 = μεταπτυχιακό, 2 = πανεπιστημιακό, κ.λπ.) |
| MARRIAGE | Οικογενειακή κατάσταση (1 = παντρεμένος, 2 = εργένης, κ.λπ.) |
| AGE | Ηλικία του πελάτη |
| PAY_0 έως PAY_6 | Ιστορικό καθυστέρησης πληρωμών τελευταίων 7 μηνών |
| BILL_AMT1 έως BILL_AMT6 | Υπόλοιπο λογαριασμού ανά μήνα (τελευταίοι 6 μήνες) |
| PAY_AMT1 έως PAY_AMT6 | Ποσό που πληρώθηκε ανά μήνα (τελευταίοι 6 μήνες) |
| default.payment.next.month | Στόχος: 1 = Αθέτηση πληρωμής, 0 = Όχι |
Όλες οι μεταβλητές είναι αριθμητικές, εκτός από τη
default.payment.next.month, η οποία είναι δυαδική και
χρησιμοποιείται ως target (εξαρτημένη μεταβλητή).
φΔυστυχώς δεν πρόλαβα να το fittaro καλά να φαίνονται οι αριθμοί αλλά ναι.. Γενικά φτιάχνω συνήθως πάντα στην αρχή το correlation matrix για να δωούμε γρήγορα και εύκολα ποιες είναι οι δυνατές συσχετίσεις που υπάρχουν στο dataset.
Παραθέτω διαγράμματα μεταξύ κάποιων μεταβλητών-ζευγαριών για καλύτερη κατανόηση του dataset
Το γράφημα παρουσιάζει την κατανομή των επιπέδων εκπαίδευσης σε διαφορετικές καταστάσεις γάμου. Παρατηρούμε ότι η πλειοψηφία των πελατών είναι είτε Single είτε Married, και στις δύο περιπτώσεις κυριαρχεί η εκπαίδευση University, ακολουθούμενη από Graduate School και High School. Η κατηγορία “Other” είναι γενικά αμελητέα και στις τρεις κατηγορίες.
Η πλειοψηφία των πελατών φαίνεται να συγκεντρώνεται στις ηλικίες 30–40, με σταδιακή μείωση μετά τα 45. Η κατανομή είναι ασύμμετρη προς τα δεξιά (δεξιόστροφη), υποδηλώνοντας ότι υπάρχουν λίγοι μεγαλύτεροι σε ηλικία πελάτες με υψηλές τιμές (πιθανώς ακραίες).
Το boxplot δείχνει τη μεταβλητότητα των ποσών πληρωμής (PAY_AMT1) ανάλογα με την κατάσταση πληρωμής (PAY_0). Η πλειοψηφία των περιπτώσεων έχει μηδενικές ή αρνητικές τιμές στο PAY_0, δηλαδή πληρωμή στην ώρα τους ή πρόωρα. Παρατηρούνται πολλοί ακραίοι τιμοί (outliers), ειδικά στις κατηγορίες -2, -1 και 0, που ίσως αντιπροσωπεύουν πελάτες με πολύ υψηλές πληρωμές.
Το scatter plot δείχνει ότι δεν υπάρχει σαφής γραμμική συσχέτιση μεταξύ ηλικίας και πιστωτικού ορίου. Ωστόσο, διακρίνεται ότι αρκετοί νεότεροι πελάτες (25–40 ετών) διαθέτουν σχετικά υψηλά όρια πίστωσης. Οι πιο ηλικιωμένοι παρουσιάζουν μεγαλύτερη διασπορά, αλλά τα πολύ υψηλά όρια είναι λιγότερα.
Σε αυτό το βήμα χωρίζουμε τα δεδομένα μας σε training και test set. Το training set θα χρησιμοποιηθεί για να εκπαιδεύσουμε το μοντέλο, ενώ το test set θα χρησιμοποιηθεί για να αξιολογήσουμε την ακρίβειά του σε νέα δεδομένα.
## Πλήθος στο training set: 21000
## Πλήθος στο test set: 9000
Σε αυτό το σημείο εκπαιδεύουμε το δέντρο απόφασης με την εντολή
rpart. Επιλέγουμε ως εξαρτημένη μεταβλητή τη
default, δηλαδή αν ο πελάτης χρεωστικής κάρτας θα
καθυστερήσει να πληρώσει. Όλες οι υπόλοιπες μεταβλητές θα
χρησιμοποιηθούν ως προβλεπτικές.Για την εκπαίδευση του δέντρου βάλαμε να
εκπαιδευτούν όλες οι μεταβλητές και αυτό δηλώνεται από το συμβολάκι
~.
TreeModel <- rpart(default ~ ., data = Train, method = "class")
prp(TreeModel)
## n= 21000
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 21000 4645 0 (0.7788095 0.2211905)
## 2) PAY_0< 1.5 18781 3100 0 (0.8349396 0.1650604) *
## 3) PAY_0>=1.5 2219 674 1 (0.3037404 0.6962596) *
Εδώ εφαρμόζουμε το εκπαιδευμένο δέντρο στο test set και ελέγχουμε πόσο καλά προβλέπει τις τιμές. Υπολογίζουμε την ακρίβεια του μοντέλου, δηλαδή το ποσοστό των σωστών προβλέψεων.
## PredictCART
## 0 1
## 0 6730 279
## 1 1359 632
## [1] 0.818
Εφαρμόσαμε το μοντέλο που φτιάξαμε σε νέα δεδομένα, συγκεκριμένα στα test δεδομένα και πήραμε ακρίβεια 0.818.
Εδώ συγκρίνουμε το μοντέλο μας με το “τετριμμένο” μοντέλο (baseline), με την εννοία ότι κρίνοντας απλά από το ποσοστό που έχει η εξαρτημένη μεταβλητή στο dataset ε και ανάλογα μετά εμείς θα κάναμε προβλέψει υπέρ που προβλέπει πάντα την πιο συχνή τιμή. Αν η ακρίβεια του δέντρου μας είναι υψηλότερη, τότε αξίζει να το κρατήσουμε.
##
## 0 1
## 7009 1991
## Baseline accuracy (predict always 0 ): 0.779
Για να αξιολογήσουμε το μοντέλο πιο πλήρως, σχεδιάζουμε την καμπύλη ROC που δείχνει την ισορροπία μεταξύ true positive και false positive rate.
Ο υπολογισμός του AUC (Area Under Curve) μας δείχνει πόσο “διαχωρίσιμο” είναι το μοντέλο. Τιμές κοντά στο 1 είναι πολύ καλές, ενώ τιμές γύρω στο 0.5 δείχνουν τυχαία πρόβλεψη.
## [1] 0.6388112
Τέλος, εφαρμόζουμε cross-validation για να βρούμε την καλύτερη τιμή
της παραμέτρου πολυπλοκότητας cp του δέντρου. Με αυτόν τον
τρόπο αποφεύγουμε υπερπροσαρμογή (overfitting) και βελτιστοποιούμε την
απόδοση του μοντέλου.
## CART
##
## 21000 samples
## 23 predictor
## 2 classes: 'No', 'Yes'
##
## No pre-processing
## Resampling: Cross-Validated (7 fold)
## Summary of sample sizes: 18000, 18001, 18001, 18000, 17999, 18000, ...
## Resampling results across tuning parameters:
##
## cp Accuracy Kappa
## 0.01 0.8202856 0.3583058
## 0.02 0.8202856 0.3583058
## 0.03 0.8202856 0.3583058
## 0.04 0.8202856 0.3583058
## 0.05 0.8202856 0.3583058
## 0.06 0.8202856 0.3583058
## 0.07 0.8202856 0.3583058
## 0.08 0.8202856 0.3583058
## 0.09 0.8202856 0.3583058
## 0.10 0.8202856 0.3583058
## 0.11 0.8202856 0.3583058
## 0.12 0.8202856 0.3583058
## 0.13 0.8202856 0.3583058
## 0.14 0.8202856 0.3583058
## 0.15 0.8202856 0.3583058
## 0.16 0.8202856 0.3583058
## 0.17 0.8202856 0.3583058
## 0.18 0.8202856 0.3583058
## 0.19 0.7942855 0.1451929
## 0.20 0.7788095 0.0000000
##
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was cp = 0.18.
## PredictCV
## No Yes
## 0 6730 279
## 1 1359 632
## [1] 0.818
Αυτό θα επιστρέψει έναν πίνακα με τις σχετικές επιδράσεις (importance scores) όλων των μεταβλητών. Αν το μοντέλο είναι πολύ απλό (που ήταν), θα δεις ότι μόνο η PAY_0 έχει θετικό σκορ — οι υπόλοιπες θα έχουν 0.
varImp(TreeModel)
## Overall
## PAY_0 1119.9573
## PAY_2 821.8774
## PAY_3 619.5308
## PAY_4 568.7317
## PAY_5 510.4024
## LIMIT_BAL 0.0000
## SEX 0.0000
## EDUCATION 0.0000
## MARRIAGE 0.0000
## AGE 0.0000
## PAY_6 0.0000
## BILL_AMT1 0.0000
## BILL_AMT2 0.0000
## BILL_AMT3 0.0000
## BILL_AMT4 0.0000
## BILL_AMT5 0.0000
## BILL_AMT6 0.0000
## PAY_AMT1 0.0000
## PAY_AMT2 0.0000
## PAY_AMT3 0.0000
## PAY_AMT4 0.0000
## PAY_AMT5 0.0000
## PAY_AMT6 0.0000
Η μεταβλητή PAY_0 έχει το μεγαλύτερο score (1119.96), επιβεβαιώνει τον λόγο που χρησιμοποιήθηκε περισσότερο για split.
Ακολουθούν PAY_2, PAY_3, PAY_4, PAY_5 με θετικό σκορ πάλι αλλά χαμηλότερο — παρόλο που δεν εμφανίστηκαν στο απλό δέντρο που είδαμε, ο αλγόριθμος τα αξιολόγησε ως χρήσιμα splits κατά την κατασκευή του δέντρου.
Όλες οι άλλες (π.χ. SEX, EDUCATION, LIMIT_BAL, BILL_AMT κ.λπ.) έχουν 0, δηλαδή δεν συνέβαλαν καθόλου στη διαμόρφωση του δέντρου.
Παρατηρήσαμε ότι το δέντρο που δημιουργήθηκε ήταν εξαιρετικά απλό, με μόλις μία διακλάδωση που βασίζεται στη μεταβλητή PAY_0. Ουσιαστικά, ο αλγόριθμος επέλεξε μόνο αυτό το χαρακτηριστικό για να διαχωρίσει τις παρατηρήσεις σε δύο κατηγορίες. Αυτό μπορεί να σημαίνει ότι η PAY_0 είναι πολύ ισχυρός προβλεπτικός παράγοντας για την πιθανότητα καθυστέρησης στην πληρωμή, τουλάχιστον σε σχέση με τις υπόλοιπες μεταβλητές.
Οι μεταβλητές PAY_0, PAY_2 κ.λπ. είναι ένδειξη της συνέπειας του πελάτη στο παρελθόν. Δεν μας εκπλήσσει ότι αυτές είναι οι πιο σημαντικές για την πρόβλεψη αν θα καθυστερήσει να πληρώσει και τον επόμενο μήνα.
Από τη μία, αυτό κάνει το μοντέλο απλό και εύκολο στην ερμηνεία. Από την άλλη, ενδέχεται να έχει χάσει πληροφορία από άλλες μεταβλητές — για αυτό και στη συνέχεια εφαρμόζουμε cross-validation με pruning, ώστε να επιτρέψουμε στο δέντρο να γίνει ελαφρώς πιο πολύπλοκο και να αξιοποιήσει περισσότερα χαρακτηριστικά.