In [11]:
## Data Loading
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, roc_auc_score, roc_curve
data_path = 'credit_card_default.csv'
# Load the dataset into a pandas DataFrame and set the index to the "ID" column
ccd = pd.read_csv(data_path, index_col="ID")
# Understand the data
ccd.describe()
Out[11]:
LIMIT_BAL SEX EDUCATION MARRIAGE AGE PAY_1 PAY_2 PAY_3 PAY_4 PAY_5 ... BILL_AMT4 BILL_AMT5 BILL_AMT6 PAY_AMT1 PAY_AMT2 PAY_AMT3 PAY_AMT4 PAY_AMT5 PAY_AMT6 default payment next month
count 30000.000000 30000.000000 30000.000000 30000.000000 30000.000000 30000.000000 30000.000000 30000.000000 30000.000000 30000.000000 ... 30000.000000 30000.000000 30000.000000 30000.000000 3.000000e+04 30000.00000 30000.000000 30000.000000 30000.000000 30000.000000
mean 167484.322667 1.603733 1.853133 1.553667 35.485500 -0.016700 -0.133767 -0.166200 -0.220667 -0.266200 ... 43262.948967 40311.400967 38871.760400 5663.580500 5.921163e+03 5225.68150 4826.076867 4799.387633 5215.502567 0.221200
std 129747.661567 0.489129 0.790349 0.518326 9.217904 1.123802 1.197186 1.196868 1.169139 1.133187 ... 64332.856134 60797.155770 59554.107537 16563.280354 2.304087e+04 17606.96147 15666.159744 15278.305679 17777.465775 0.415062
min 10000.000000 1.000000 0.000000 1.000000 21.000000 -2.000000 -2.000000 -2.000000 -2.000000 -2.000000 ... -170000.000000 -81334.000000 -339603.000000 0.000000 0.000000e+00 0.00000 0.000000 0.000000 0.000000 0.000000
25% 50000.000000 1.000000 1.000000 1.000000 28.000000 -1.000000 -1.000000 -1.000000 -1.000000 -1.000000 ... 2326.750000 1763.000000 1256.000000 1000.000000 8.330000e+02 390.00000 296.000000 252.500000 117.750000 0.000000
50% 140000.000000 2.000000 2.000000 2.000000 34.000000 0.000000 0.000000 0.000000 0.000000 0.000000 ... 19052.000000 18104.500000 17071.000000 2100.000000 2.009000e+03 1800.00000 1500.000000 1500.000000 1500.000000 0.000000
75% 240000.000000 2.000000 2.000000 2.000000 41.000000 0.000000 0.000000 0.000000 0.000000 0.000000 ... 54506.000000 50190.500000 49198.250000 5006.000000 5.000000e+03 4505.00000 4013.250000 4031.500000 4000.000000 0.000000
max 1000000.000000 2.000000 6.000000 3.000000 79.000000 8.000000 8.000000 8.000000 8.000000 8.000000 ... 891586.000000 927171.000000 961664.000000 873552.000000 1.684259e+06 896040.00000 621000.000000 426529.000000 528666.000000 1.000000

8 rows × 24 columns

In [2]:
 #Clean PAY_ features
pay_features = ['PAY_' + str(i) for i in range(1,7)]
# Loop through each 'pay_' feature
for x in pay_features:
# Transform the -1 and -2 values to 0, assuming these represent non-defaulted payments
  ccd.loc[ccd[x] <= 0, x] = 0
# Rename the 'default payment next month' column to 'default' for brevity
ccd.rename(columns={'default payment next month':'default'}, inplace=True)
categorical_features = ['SEX', 'EDUCATION', 'MARRIAGE']
numerical_features = ['LIMIT_BAL', 'AGE', 'PAY_1', 'PAY_2', 'PAY_3', 'PAY_4', \
  'PAY_5', 'PAY_6', 'BILL_AMT1', 'BILL_AMT2', 'BILL_AMT3', 'BILL_AMT4', \
    'BILL_AMT5', 'BILL_AMT6', 'PAY_AMT1', 'PAY_AMT2', 'PAY_AMT3', 'PAY_AMT4',\
      'PAY_AMT5', 'PAY_AMT6']
target_feature = ['default']
In [3]:
#standardize data
scaler = StandardScaler()
ccd[numerical_features] = scaler.fit_transform(ccd[numerical_features])
ccd = pd.get_dummies(ccd, columns=categorical_features, drop_first=True)
In [4]:
#splitting data inot train and test
X = ccd.drop(columns=['default'])
y = ccd['default']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
In [5]:
#model buidling
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(X_train, y_train)
rf_train_pred = rf_model.predict(X_train)
rf_test_pred = rf_model.predict(X_test)
rf_test_proba = rf_model.predict_proba(X_test)[:, 1]
dt_model = DecisionTreeClassifier(random_state=42)

dt_model.fit(X_train, y_train)
dt_train_pred = dt_model.predict(X_train)
dt_test_pred = dt_model.predict(X_test)
dt_test_proba = dt_model.predict_proba(X_test)[:, 1]

lr_model = LogisticRegression(max_iter=1000)
lr_model.fit(X_train, y_train)
lr_train_pred = lr_model.predict(X_train)
lr_test_pred = lr_model.predict(X_test)
lr_test_proba = lr_model.predict_proba(X_test)[:, 1]
In [6]:
#model performance comparison
models = ['Random Forest', 'Decision Tree', 'Logistic Regression']
train_accuracies = [
  accuracy_score(y_train, rf_train_pred),
  accuracy_score(y_train, dt_train_pred),
  accuracy_score(y_train, lr_train_pred)
]
test_accuracies = [
  accuracy_score(y_test, rf_test_pred),
  accuracy_score(y_test, dt_test_pred),
  accuracy_score(y_test, lr_test_pred)
]
auroc_scores = [
  roc_auc_score(y_test, rf_test_proba),
  roc_auc_score(y_test, dt_test_proba),
  roc_auc_score(y_test, lr_test_proba)
]
results_df = pd.DataFrame({
  'Model': models,
  'Training Accuracy': [f"{x:.4f}" for x in train_accuracies],
  'Testing Accuracy': [f"{x:.4f}" for x in test_accuracies],
  'AUROC Score': [f"{x:.4f}" for x in auroc_scores]
})
# Print the table
print("Model Performance Comparison:")
print(results_df)
Model Performance Comparison:
                 Model Training Accuracy Testing Accuracy AUROC Score
0        Random Forest            0.9994           0.8150      0.7620
1        Decision Tree            0.9995           0.7268      0.6145
2  Logistic Regression            0.8195           0.8162      0.7630
In [12]:
#print decision tree
plt.figure(figsize=(12, 8))
plot_tree(dt_model, max_depth=2, class_names=['No Default', 'Default'],filled=True)
plt.show()
No description has been provided for this image
In [15]:
# Calculate ROC curves
rf_fpr, rf_tpr, _ = roc_curve(y_test, rf_test_proba)
dt_fpr, dt_tpr, _ = roc_curve(y_test, dt_test_proba)
lr_fpr, lr_tpr, _ = roc_curve(y_test, lr_test_proba)
# ax3 = plt.plot(1, 1, 1)
plt.plot(rf_fpr, rf_tpr, label=f'Random Forest (AUC = {auroc_scores[0]:.3f})', plt.plot(dt_fpr, dt_tpr, label=f'Decision Tree (AUC = {auroc_scores[1]:.3f})', color='blue')
color='orange')
plt.plot(lr_fpr, lr_tpr, label=f'Logistic Regression (AUC = {auroc_scores[2]:.3f})', color='green')
plt.plot([0, 1], [0, 1], 'k--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve Comparison')
plt.legend()
plt.grid(True)
No description has been provided for this image
In [16]:
# Create probability distribution plots
fig, axes = plt.subplots(1, 3, figsize=(18, 5), sharey=True)
# Random Forest
sns.histplot(rf_test_proba, bins=20, kde=True, ax=axes[0], color='blue')
axes[0].set_title('Random Forest Probability Distribution')
axes[0].set_xlabel('Predicted Probability')
axes[0].set_ylabel('Frequency')
# Decision Tree
sns.histplot(dt_test_proba, bins=20, kde=True, ax=axes[1], color='orange')
axes[1].set_title('Decision Tree Probability Distribution')
axes[1].set_xlabel('Predicted Probability')
# Logistic Regression
sns.histplot(lr_test_proba, bins=20, kde=True, ax=axes[2], color='green')
axes[2].set_title('Logistic Regression Probability Distribution')
axes[2].set_xlabel('Predicted Probability')
plt.tight_layout()
plt.show()
No description has been provided for this image
In [ ]: