marcilioduarte commited on
Commit
96f4571
·
1 Parent(s): dc41981

Modernize credit risk Gradio app and prepare house prices app support

Browse files
Files changed (2) hide show
  1. app.py +82 -167
  2. requirements.txt +2 -1
app.py CHANGED
@@ -1,176 +1,91 @@
1
- ## IMPORTING LIBS
2
 
3
- import pandas as pd
4
- import plotly.express as px
5
- from pathlib import Path
6
 
7
- from sklearn.metrics import f1_score, precision_score, recall_score, confusion_matrix
 
8
 
9
- import pickle
10
  import gradio as gr
11
 
12
- BASE_DIR = Path(__file__).resolve().parent
13
-
14
- ## CREATING FUNCTION
15
-
16
- def predict_credit_worthiness(name, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22):
17
- path = BASE_DIR / "model" / "model.pickle"
18
- greet = 'Hey, ' + name + '!'
19
- with open(path, 'rb') as file:
20
- model = pickle.load(file)
21
- inputs = {'Account Balance_1': int(x1),
22
- 'Account Balance_2': int(x2),
23
- 'Account Balance_3': int(x3),
24
- 'Payment Status of Previous Credit_1': int(x4),
25
- 'Payment Status of Previous Credit_3': int(x5),
26
- 'Purpose_1': int(x6),
27
- 'Purpose_4': int(x7),
28
- 'Value Savings/Stocks_1': int(x8),
29
- 'Value Savings/Stocks_3': int(x9),
30
- 'Value Savings/Stocks_5': int(x10),
31
- 'Length of current employment_1': int(x11),
32
- 'Length of current employment_4': int(x12),
33
- 'Instalment per cent_4': int(x13),
34
- 'Guarantors_1': int(x14),
35
- 'Duration in Current address_1': int(x15),
36
- 'Duration in Current address_2': int(x16),
37
- 'Most valuable available asset_1': int(x17),
38
- 'Most valuable available asset_4': int(x18),
39
- 'Concurrent Credits_3': int(x19),
40
- 'Type of apartment_1': int(x20),
41
- 'No of Credits at this Bank_1': int(x21),
42
- 'Occupation_1': int(x22)
43
- }
44
- prediction = model.predict([list(inputs.values())])
45
-
46
- y_test = pd.read_parquet(BASE_DIR / "data" / "processed" / "y_test.parquet")
47
- y_test = y_test.squeeze()
48
-
49
- yhat = pd.read_parquet(BASE_DIR / "data" / "processed" / "yhat.parquet")
50
- yhat = yhat.squeeze()
51
-
52
- precision = precision_score(y_test, yhat).round(2)
53
- recall = recall_score(y_test, yhat).round(2)
54
- f1 = f1_score(y_test, yhat).round(2)
55
-
56
- features_names = ['No account', 'No balance', 'Some balance', 'No credit problems',
57
- 'Some credit problems', 'New car', 'Other purpose', 'No savings',
58
- 'DM betwenn [100, 1000]', 'DM >= 1000', 'Employment: <1 year (or unemployed)', 'Employment: 4<x<7 years',
59
- 'Installment smaller than 20%', 'No guarantors', 'Less than a year in same address', '1<x<4 years in address',
60
- 'Not available / no assets', 'Ownership of house or land', 'No further running credits', 'Free ap',
61
- 'One credit at thins bank','Unemployed or unskilled']
62
- importance = model.feature_importances_
63
- data = pd.DataFrame()
64
- data['Feature Importance'] = importance
65
- data['Feature'] = features_names
66
- p = px.bar(data, y='Feature Importance', x='Feature', width=1200, height=500)
67
-
68
- cfm = confusion_matrix(y_test, yhat)
69
- cfm_plot = px.imshow(cfm,
70
- x=['Predicted 0', 'Predicted 1'],
71
- y=['Actual 0', 'Actual 1'],
72
- color_continuous_scale='Blues',
73
- labels=dict(x="Predicted", y="Actual", color="Count"),
74
- text_auto=True)
75
-
76
  if prediction == 1:
77
- return (greet + ' According to our model, your client is eligible for the loan.',
78
- 'Precision: '+ str(precision),
79
- 'Recall: '+ str(recall),
80
- 'F1 Score: '+ str(f1),
81
- p,
82
- cfm_plot)
83
  else:
84
- return (greet + ' Unfortunately, according to our model, your client is not eligible for the loan for now :(.',
85
- 'Precision: '+ str(precision),
86
- 'Recall: '+ str(recall),
87
- 'F1 Score: '+ str(f1),
88
- p,
89
- cfm_plot)
90
-
91
- ## creating the interface
92
-
93
- with gr.Blocks() as demo:
94
- gr.Markdown('# Credit Worthiness Prediction')
95
- gr.Markdown("""
96
- To predict our clients' creditworthiness, please use this application as follows:
97
-
98
- 1. Enter your name and navigate through the client's information tabs. Select the boxes that best match your client's characteristics. Leave blank if none apply.
99
-
100
- 2. Once completed, click 'Predict' to determine if the client is creditworthy.
101
- """)
102
- with gr.Accordion('Name'):
103
- name = gr.Textbox(lines=1, label='Your name')
104
- with gr.Accordion("Enter your client's information"):
105
- with gr.Tab('Account Balance'):
106
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
107
- x1 = gr.Checkbox(1, label='No account')
108
- x2 = gr.Checkbox(0, label='No balance')
109
- x3 = gr.Checkbox(0, label='Some balance')
110
- with gr.Tab('Payment status of previous credit'):
111
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
112
- x4 = gr.Checkbox(1, label='Some problems')
113
- x5 = gr.Checkbox(0, label='No problems in this bank')
114
- with gr.Tab('Purpose'):
115
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
116
- x6 = gr.Checkbox(1, label='New car')
117
- x7 = gr.Checkbox(0, label='Other')
118
- with gr.Tab('Value savings/stocks'):
119
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
120
- x8 = gr.Checkbox(1, label='No savings')
121
- x9 = gr.Checkbox(0, label='DM betwenn [100, 1000]')
122
- x10 = gr.Checkbox(0, label='DM >= 1000')
123
- with gr.Tab('Length of current employment'):
124
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
125
- x11 = gr.Checkbox(1, label='Below 1 year (or unemployed)')
126
- x12 = gr.Checkbox(0, label='Between 4 and 7 years')
127
- with gr.Tab('Instalment per cent'):
128
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
129
- x13 = gr.Checkbox(0, label='Smaller than 20%')
130
- with gr.Tab('Guarantors'):
131
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
132
- x14 = gr.Checkbox(0, label='No guarantors')
133
- with gr.Tab('Duration in current address'):
134
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
135
- x15 = gr.Checkbox(1, label='Less than a year')
136
- x16 = gr.Checkbox(0, label='Between 1 and 4 years')
137
- with gr.Tab('Most valuable available asset'):
138
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
139
- x17 = gr.Checkbox(1, label='Not available / no assets')
140
- x18 = gr.Checkbox(0, label='Ownership of house or land')
141
- with gr.Tab('Concurrent credits'):
142
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
143
- x19 = gr.Checkbox(0, label='No further running credits')
144
- with gr.Tab('Type of apartment'):
145
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
146
- x20 = gr.Checkbox(0, label='Free apartment')
147
- with gr.Tab('Number of credits at this Bank'):
148
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
149
- x21 = gr.Checkbox(0, label='One credit')
150
- with gr.Tab('Occupation'):
151
- gr.Markdown('Select only one option. Leave all boxes blank if none of the options fits the client.')
152
- x22 = gr.Checkbox(0, label='Unemployed or unskilled with no permanent')
153
- predict_button = gr.Button('Predict')
154
- prediction_output = gr.Label(num_top_classes=2)
155
- with gr.Accordion('Metrics and plots'):
156
- with gr.Tab('Metrics'):
157
- with gr.Row():
158
- precision_output = gr.Label()
159
- with gr.Row():
160
- recall_output = gr.Label()
161
  with gr.Row():
162
- f1_output = gr.Label()
163
- with gr.Tab('Feature Importances'):
164
- fimp_output = gr.Plot()
165
- with gr.Tab('Confusion Matrix'):
166
- cfm_output = gr.Plot()
167
- predict_button.click(fn=predict_credit_worthiness,
168
- inputs=[name, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22],
169
- outputs=[prediction_output,precision_output, recall_output, f1_output, fimp_output, cfm_output])
170
- gr.Markdown('''
171
- Want to work in a project together or have interest in my services? Reach me:
172
- [Linkedin](https://www.linkedin.com/in/marcilioduarte98/)
173
- [Github](https://github.com/marcilioduarte)
174
- @marcilioduarte | Economics and Data Science
175
- ''')
 
 
 
 
 
176
  demo.launch()
 
1
+ """Gradio app for credit worthiness inference."""
2
 
3
+ from __future__ import annotations
 
 
4
 
5
+ import sys
6
+ from pathlib import Path
7
 
 
8
  import gradio as gr
9
 
10
+ PROJECT_ROOT = Path(__file__).resolve().parent
11
+ sys.path.insert(0, str(PROJECT_ROOT / "src"))
12
+
13
+ from credit_risk.app_support import format_metrics_markdown, load_artifacts # noqa: E402
14
+ from credit_risk.config import FEATURE_GROUPS, NOT_SELECTED_LABEL # noqa: E402
15
+ from credit_risk.features import build_inference_frame # noqa: E402
16
+
17
+ ARTIFACTS = load_artifacts()
18
+
19
+
20
+ def predict_credit_worthiness(name: str, *selections: str) -> tuple[str, str, object, object]:
21
+ """Predict loan eligibility from UI selections."""
22
+ selection_by_group = {}
23
+ for group, selected_label in zip(FEATURE_GROUPS, selections):
24
+ if selected_label == NOT_SELECTED_LABEL:
25
+ selection_by_group[group.name] = None
26
+ else:
27
+ selection_by_group[group.name] = selected_label
28
+
29
+ inference_frame = build_inference_frame(selection_by_group)
30
+ prediction = int(ARTIFACTS.model.predict(inference_frame)[0])
31
+
32
+ if hasattr(ARTIFACTS.model, "predict_proba"):
33
+ probabilities = ARTIFACTS.model.predict_proba(inference_frame)[0]
34
+ confidence = max(probabilities)
35
+ else:
36
+ confidence = None
37
+
38
+ user_name = (name or "there").strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  if prediction == 1:
40
+ verdict = "eligible for the loan"
 
 
 
 
 
41
  else:
42
+ verdict = "not eligible for the loan at the moment"
43
+
44
+ if confidence is None:
45
+ prediction_text = f"Hi {user_name}. According to the model, your client is {verdict}."
46
+ else:
47
+ prediction_text = (
48
+ f"Hi {user_name}. According to the model, your client is {verdict}. "
49
+ f"(Confidence: {confidence:.2%})"
50
+ )
51
+
52
+ return (
53
+ prediction_text,
54
+ format_metrics_markdown(ARTIFACTS.metrics),
55
+ ARTIFACTS.feature_importance_plot,
56
+ ARTIFACTS.confusion_matrix_plot,
57
+ )
58
+
59
+
60
+ with gr.Blocks(title="Credit Worthiness Risk Classification") as demo:
61
+ gr.Markdown("# Credit Worthiness Risk Classification")
62
+ gr.Markdown(
63
+ "Select the option that best describes the client in each section, then run prediction."
64
+ )
65
+
66
+ name_input = gr.Textbox(label="Analyst Name", placeholder="Your name")
67
+ selection_components = []
68
+
69
+ with gr.Accordion("Client Profile Inputs", open=True):
70
+ for group in FEATURE_GROUPS:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  with gr.Row():
72
+ component = gr.Radio(
73
+ choices=[NOT_SELECTED_LABEL, *group.labels],
74
+ value=NOT_SELECTED_LABEL,
75
+ label=group.name,
76
+ )
77
+ selection_components.append(component)
78
+
79
+ predict_button = gr.Button("Predict")
80
+ prediction_output = gr.Textbox(label="Prediction", interactive=False)
81
+ metrics_output = gr.Markdown(label="Metrics")
82
+ feature_plot_output = gr.Plot(label="Feature Importance")
83
+ matrix_plot_output = gr.Plot(label="Confusion Matrix")
84
+
85
+ predict_button.click(
86
+ fn=predict_credit_worthiness,
87
+ inputs=[name_input, *selection_components],
88
+ outputs=[prediction_output, metrics_output, feature_plot_output, matrix_plot_output],
89
+ )
90
+
91
  demo.launch()
requirements.txt CHANGED
@@ -2,5 +2,6 @@ numpy==1.26.4
2
  pandas==1.5.3
3
  plotly==5.14.1
4
  scikit-learn==1.1.2
5
- gradio==3.24.1
6
  pyarrow==14.0.2
 
 
2
  pandas==1.5.3
3
  plotly==5.14.1
4
  scikit-learn==1.1.2
5
+ gradio==6.14.0
6
  pyarrow==14.0.2
7
+ joblib==1.5.2