changed timestep to date, made amounts smaller and more interpretable
Browse files
app.py
CHANGED
@@ -5,7 +5,7 @@ from deeploy import Client
|
|
5 |
from utils import get_request_body, get_fake_certainty, get_model_url, get_random_suspicious_transaction
|
6 |
from utils import get_explainability_texts, get_explainability_values, send_evaluation, get_comment_explanation
|
7 |
from utils import COL_NAMES, feature_texts
|
8 |
-
from utils import create_data_input_table, create_table, ChangeButtonColour, get_weights
|
9 |
|
10 |
logging.basicConfig(level=logging.INFO)
|
11 |
|
@@ -113,11 +113,12 @@ if st.session_state.got_explanation:
|
|
113 |
prediction_log_id = st.session_state.prediction_log_id
|
114 |
datapoint_pd = st.session_state.datapoint_pd
|
115 |
certainty = st.session_state.certainty
|
|
|
116 |
|
117 |
col1, col2 = st.columns(2)
|
118 |
|
119 |
with col1:
|
120 |
-
create_data_input_table(
|
121 |
|
122 |
with col2:
|
123 |
st.subheader('AML Model Hit')
|
@@ -130,7 +131,7 @@ if st.session_state.got_explanation:
|
|
130 |
|
131 |
explainability_texts, sorted_indices = get_explainability_texts(shap_values, feature_texts)
|
132 |
weights = get_weights(shap_values, sorted_indices)
|
133 |
-
explainability_values = get_explainability_values(sorted_indices,
|
134 |
create_table(explainability_texts, explainability_values, weights, 'Important Suspicious Factors')
|
135 |
|
136 |
st.subheader("")
|
|
|
5 |
from utils import get_request_body, get_fake_certainty, get_model_url, get_random_suspicious_transaction
|
6 |
from utils import get_explainability_texts, get_explainability_values, send_evaluation, get_comment_explanation
|
7 |
from utils import COL_NAMES, feature_texts
|
8 |
+
from utils import create_data_input_table, create_table, ChangeButtonColour, get_weights, modify_datapoint
|
9 |
|
10 |
logging.basicConfig(level=logging.INFO)
|
11 |
|
|
|
113 |
prediction_log_id = st.session_state.prediction_log_id
|
114 |
datapoint_pd = st.session_state.datapoint_pd
|
115 |
certainty = st.session_state.certainty
|
116 |
+
datapoint = modify_datapoint(datapoint_pd)
|
117 |
|
118 |
col1, col2 = st.columns(2)
|
119 |
|
120 |
with col1:
|
121 |
+
create_data_input_table(datapoint, COL_NAMES)
|
122 |
|
123 |
with col2:
|
124 |
st.subheader('AML Model Hit')
|
|
|
131 |
|
132 |
explainability_texts, sorted_indices = get_explainability_texts(shap_values, feature_texts)
|
133 |
weights = get_weights(shap_values, sorted_indices)
|
134 |
+
explainability_values = get_explainability_values(sorted_indices, datapoint)
|
135 |
create_table(explainability_texts, explainability_values, weights, 'Important Suspicious Factors')
|
136 |
|
137 |
st.subheader("")
|
utils.py
CHANGED
@@ -4,8 +4,11 @@ from random import randrange, uniform
|
|
4 |
import pandas as pd
|
5 |
import logging
|
6 |
import numpy as np
|
|
|
|
|
|
|
7 |
|
8 |
-
COL_NAMES = ['
|
9 |
'Transaction type',
|
10 |
'Amount transferred',
|
11 |
'Sender\'s initial balance',
|
@@ -20,7 +23,7 @@ COL_NAMES = ['Time step',
|
|
20 |
'Sender ID',
|
21 |
'Receiver ID']
|
22 |
|
23 |
-
feature_texts = {0: "
|
24 |
4: "Initial balance of recipient: ", 5: "New balance of recipient: ", 6: "Sender's balance was exactly credited: ",
|
25 |
7: "Receiver's balance was exactly credited: ", 8: "Transaction over 450.000: ", 9: "Frequent receiver of transactions: ", 10: "Receiver is merchant: ", 11: "Sender ID: ", 12: "Receiver ID: ",
|
26 |
13: "Transaction type is Cash out", 14: "Transaction type is Transfer", 15: "Transaction type is Payment", 16: "Transaction type is Cash in", 17: "Transaction type is Debit"}
|
@@ -59,8 +62,13 @@ def get_explainability_texts(shap_values, feature_texts):
|
|
59 |
return positive_texts, sorted_positive_indices
|
60 |
|
61 |
|
62 |
-
def
|
63 |
-
|
|
|
|
|
|
|
|
|
|
|
64 |
rounded_data = [round(value, 2) if isinstance(value, float) else value for value in data]
|
65 |
transformed_data = transformation(input=rounded_data, categories=CATEGORIES)
|
66 |
vals = []
|
@@ -72,11 +80,18 @@ def get_explainability_values(pos_indices, datapoint):
|
|
72 |
vals.append(val)
|
73 |
return vals
|
74 |
|
75 |
-
#
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
def get_weights(shap_values, sorted_indices, target_sum=0.95):
|
82 |
weights = [shap_values[x] for x in sorted_indices]
|
@@ -141,9 +156,8 @@ def get_comment_explanation(certainty, explainability_texts, explainability_valu
|
|
141 |
comment = f"Model certainty is {certainty}" + '\n''\n' + result
|
142 |
return comment
|
143 |
|
144 |
-
def create_data_input_table(
|
145 |
st.subheader("Transaction details")
|
146 |
-
data = datapoint.iloc[0].tolist()
|
147 |
data[7:12] = [bool(value) for value in data[7:12]]
|
148 |
rounded_list = [round(value, 2) if isinstance(value, float) else value for value in data]
|
149 |
df = pd.DataFrame({"Feature name": col_names, "Value": rounded_list })
|
|
|
4 |
import pandas as pd
|
5 |
import logging
|
6 |
import numpy as np
|
7 |
+
import random
|
8 |
+
from datetime import datetime, timedelta
|
9 |
+
from babel.numbers import format_currency
|
10 |
|
11 |
+
COL_NAMES = ['Transaction date',
|
12 |
'Transaction type',
|
13 |
'Amount transferred',
|
14 |
'Sender\'s initial balance',
|
|
|
23 |
'Sender ID',
|
24 |
'Receiver ID']
|
25 |
|
26 |
+
feature_texts = {0: "Date of transaction: ", 1: "Amount transferred: ", 2: "Initial balance of sender: ", 3: "New balance of sender: ",
|
27 |
4: "Initial balance of recipient: ", 5: "New balance of recipient: ", 6: "Sender's balance was exactly credited: ",
|
28 |
7: "Receiver's balance was exactly credited: ", 8: "Transaction over 450.000: ", 9: "Frequent receiver of transactions: ", 10: "Receiver is merchant: ", 11: "Sender ID: ", 12: "Receiver ID: ",
|
29 |
13: "Transaction type is Cash out", 14: "Transaction type is Transfer", 15: "Transaction type is Payment", 16: "Transaction type is Cash in", 17: "Transaction type is Debit"}
|
|
|
62 |
return positive_texts, sorted_positive_indices
|
63 |
|
64 |
|
65 |
+
def random_past_date_from_last_year():
|
66 |
+
one_year_ago = datetime.now() - timedelta(days=365)
|
67 |
+
random_days = random.randint(0, (datetime.now() - one_year_ago).days)
|
68 |
+
random_date = one_year_ago + timedelta(days=random_days)
|
69 |
+
return random_date.strftime('%Y-%m-%d')
|
70 |
+
|
71 |
+
def get_explainability_values(pos_indices, data):
|
72 |
rounded_data = [round(value, 2) if isinstance(value, float) else value for value in data]
|
73 |
transformed_data = transformation(input=rounded_data, categories=CATEGORIES)
|
74 |
vals = []
|
|
|
80 |
vals.append(val)
|
81 |
return vals
|
82 |
|
83 |
+
def modify_datapoint(datapoint): # should return list, with correct numbers/amounts, and date
|
84 |
+
data = datapoint.iloc[0].tolist()
|
85 |
+
data[0] = random_past_date_from_last_year()
|
86 |
+
modified_amounts = data.copy()
|
87 |
+
if any(val > 12000 for val in data[2:7]):
|
88 |
+
modified_amounts[2:7] = [value / 100 if value != 0 else 0 for value in data[2:7]]
|
89 |
+
if any(val > 120000 for val in modified_amounts[2:7]):
|
90 |
+
new_list = [value / 10 if value != 0 else 0 for value in modified_amounts[2:7]]
|
91 |
+
modified_amounts[2:7] = new_list
|
92 |
+
rounded_data = [round(value, 2) if isinstance(value, float) else value for value in modified_amounts]
|
93 |
+
rounded_data[2:7] = [format_currency(value, 'EUR', locale='en_GB') for value in rounded_data[2:7]]
|
94 |
+
return rounded_data
|
95 |
|
96 |
def get_weights(shap_values, sorted_indices, target_sum=0.95):
|
97 |
weights = [shap_values[x] for x in sorted_indices]
|
|
|
156 |
comment = f"Model certainty is {certainty}" + '\n''\n' + result
|
157 |
return comment
|
158 |
|
159 |
+
def create_data_input_table(data, col_names):
|
160 |
st.subheader("Transaction details")
|
|
|
161 |
data[7:12] = [bool(value) for value in data[7:12]]
|
162 |
rounded_list = [round(value, 2) if isinstance(value, float) else value for value in data]
|
163 |
df = pd.DataFrame({"Feature name": col_names, "Value": rounded_list })
|