Skip to content

Commit

Permalink
#5 Set specific rejection code probabilities based on type of rejecte…
Browse files Browse the repository at this point in the history
…d transaction status
  • Loading branch information
oislen committed Jun 14, 2023
1 parent db1e60b commit 77b0688
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 16 deletions.
2 changes: 1 addition & 1 deletion scripts/app/gen_trans_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def gen_trans_data(user_data, device_obj, card_obj, ip_obj, transaction_obj, app

# generate transaction status and error code
rejection_rates_dict = gen_trans_rejection_rates(trans_data = trans_data)
trans_data[['transaction_status', 'transaction_error_code']] = trans_data.apply(lambda series: gen_trans_status(series = series, rejection_rates_dict = rejection_rates_dict, rejection_codes = transaction_obj.rejection_codes), result_type = 'expand', axis = 1)
trans_data[['transaction_status', 'transaction_error_code']] = trans_data.apply(lambda series: gen_trans_status(series = series, rejection_rates_dict = rejection_rates_dict), result_type = 'expand', axis = 1)

# sort data by transaction date
trans_data = trans_data.sort_values(by = 'transaction_date').reset_index(drop = True)
Expand Down
8 changes: 6 additions & 2 deletions scripts/cons.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
data_model_card_types_dict = {'visa':0.5, 'mastercard':0.5}
data_model_payment_channels = {'paypal':0.4, 'adyen':0.3, 'worldpay':0.2, 'docomo':0.1}
data_model_transaction_status = {'successful':0.94, 'pending':0.03, 'rejected':0.03}
data_model_rejection_codes = {'E900:ConnectionTimeout':0.2, 'E901:SuspectedFraud':0.2, 'E902:AuthenicationFailure':0.2, 'E903:UserCancelled':0.2, 'E904:InsufficientFunds':0.2}
data_model_inconsistent_country_codes_rejection_rate = {1:0.001, 2:0.005, 3:0.01}
data_model_non_card_trans_methods = {'wallet':0.95, 'points':0.05}
data_model_non_card_trans_methods = {'wallet':0.95, 'points':0.05}
data_model_rejection_codes_fraud = {'E900:ConnectionTimeout':0.15, 'E901:SuspectedFraud':0.35, 'E902:AuthenicationFailure':0.20, 'E903:UserCancelled':0.15, 'E904:InsufficientFunds':0.15}
data_model_rejection_codes_connection = {'E900:ConnectionTimeout':0.35, 'E901:SuspectedFraud':0.15, 'E902:AuthenicationFailure':0.15, 'E903:UserCancelled':0.2, 'E904:InsufficientFunds':0.15}
data_model_rejection_codes_user = {'E900:ConnectionTimeout':0.15, 'E901:SuspectedFraud':0.15, 'E902:AuthenicationFailure':0.15, 'E903:UserCancelled':0.35, 'E904:InsufficientFunds':0.2}
data_model_rejection_codes_funds = {'E900:ConnectionTimeout':0.15, 'E901:SuspectedFraud':0.15, 'E902:AuthenicationFailure':0.15, 'E903:UserCancelled':0.2, 'E904:InsufficientFunds':0.35}
data_model_rejection_codes_authentication = {'E900:ConnectionTimeout':0.15, 'E901:SuspectedFraud':0.2, 'E902:AuthenicationFailure':0.35, 'E903:UserCancelled':0.15, 'E904:InsufficientFunds':0.15}
1 change: 0 additions & 1 deletion scripts/objects/Transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ def __init__(self, n_transaction_hashes, start_date, end_date):
self.lam = cons.data_model_poisson_lambda_params["transaction"]
self.payment_channels = cons.data_model_payment_channels
self.transaction_status = cons.data_model_transaction_status
self.rejection_codes = cons.data_model_rejection_codes
self.transaction_hashes_cnts_dict = gen_idhash_cnt_dict(
idhash_type="hash", n=self.n_transaction_hashes, lam=self.lam
)
Expand Down
22 changes: 10 additions & 12 deletions scripts/utilities/gen_trans_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import cons


def gen_trans_status(series, rejection_rates_dict, rejection_codes):
def gen_trans_status(series, rejection_rates_dict):
"""Generates the transaction status for a pandas series from the transaction level telecom payments data given the rejection rates dictionary from the same data
Parameters
Expand All @@ -12,8 +12,6 @@ def gen_trans_status(series, rejection_rates_dict, rejection_codes):
A pandas series from the transaction level telecom payments data
rejection_rates_dict : dict
Rejection rates generated the transaction level telecom payments data
rejection_codes : dict
A dictionary of rejection codes and assoicated proportions
Returns
-------
Expand All @@ -27,35 +25,35 @@ def gen_trans_status(series, rejection_rates_dict, rejection_codes):
# add rejections based on crime rates within country codes
if rejection_rates_dict["country_code_trans_reject_rate_dict"][np.random.choice(a=series[country_code_columns].dropna().to_list(), size=1)[0]] >= random.uniform(0, 1):
status = "rejected"
error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0]
error_code = np.random.choice(a=list(cons.data_model_rejection_codes_fraud.keys()),p=list(cons.data_model_rejection_codes_fraud.values()),size=1)[0]
# add rejections based on domain frequencies
elif rejection_rates_dict["domain_email_trans_reject_rate_dict"][series["email_domain"]] >= random.uniform(0, 1):
status = "rejected"
error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0]
error_code = np.random.choice(a=list(cons.data_model_rejection_codes_authentication.keys()),p=list(cons.data_model_rejection_codes_authentication.values()),size=1)[0]
# add rejections based on inconsistent country codes
elif cons.data_model_inconsistent_country_codes_rejection_rate[series[country_code_columns].dropna().nunique()] >= random.uniform(0, 1):
status = "rejected"
error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0]
error_code = np.random.choice(a=list(cons.data_model_rejection_codes_connection.keys()),p=list(cons.data_model_rejection_codes_connection.values()),size=1)[0]
# add rejections based on shared ips, cards and devices
elif series["device_hash"] == series["device_hash"] and rejection_rates_dict["shared_devices_reject_rate_dict"][series["device_hash"]] >= random.uniform(0, 1):
status = "rejected"
error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0]
error_code = np.random.choice(a=list(cons.data_model_rejection_codes_fraud.keys()),p=list(cons.data_model_rejection_codes_fraud.values()),size=1)[0]
elif series["ip_hash"] == series["ip_hash"] and rejection_rates_dict["shared_ips_reject_rate_dict"][series["ip_hash"]] >= random.uniform(0, 1):
status = "rejected"
error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0]
error_code = np.random.choice(a=list(cons.data_model_rejection_codes_fraud.keys()),p=list(cons.data_model_rejection_codes_fraud.values()),size=1)[0]
elif series["card_hash"] == series["card_hash"] and rejection_rates_dict["shared_cards_reject_rate_dict"][series["card_hash"]] >= random.uniform(0, 1):
status = "rejected"
error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0]
error_code = np.random.choice(a=list(cons.data_model_rejection_codes_fraud.keys()),p=list(cons.data_model_rejection_codes_fraud.values()),size=1)[0]
# add rejections based on counts of devices, ips and cards
elif rejection_rates_dict["count_devices_reject_rate_dict"][series["userid"]] >= random.uniform(0, 1):
status = "rejected"
error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0]
error_code = np.random.choice(a=list(cons.data_model_rejection_codes_funds.keys()),p=list(cons.data_model_rejection_codes_funds.values()),size=1)[0]
elif rejection_rates_dict["count_ips_reject_rate_dict"][series["userid"]] >= random.uniform(0, 1):
status = "rejected"
error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0]
error_code = np.random.choice(a=list(cons.data_model_rejection_codes_funds.keys()),p=list(cons.data_model_rejection_codes_funds.values()),size=1)[0]
elif rejection_rates_dict["count_cards_reject_rate_dict"][series["userid"]] >= random.uniform(0, 1):
status = "rejected"
error_code = np.random.choice(a=list(rejection_codes.keys()),p=list(rejection_codes.values()),size=1)[0]
error_code = np.random.choice(a=list(cons.data_model_rejection_codes_funds.keys()),p=list(cons.data_model_rejection_codes_funds.values()),size=1)[0]
# otherwise return successful status
else:
status = np.random.choice(a=['successful', 'pending'], size=1, p=[0.98, 0.02])[0]
Expand Down

0 comments on commit 77b0688

Please sign in to comment.