An Unsupervised Mathematical Scoring Model
By: Abhishek Mungoli
Tags: Analytics, Artificial Intelligence, Mathematics, Data Science, Machine Learning

An Unsupervised Mathematical Scoring Model

Unleashing the power of mathematical models

Picture by Geralt on Pixabay

A Mathematical model is a description of a system using mathematical equations. The system is governed by a set of mathematical equations that can be linear, non-linear, static, or dynamic. The model can learn the parameters of the equation from available data and even predict the future.

In this blog, I will discuss one such practical mathematical model that can be utilized in a variety of problems in the absence of labeled data with some prior domain knowledge. All the codes and datasets used in this blog can be found here.

Our Mathematical Model: Logistic Function

Logistic function commonly known as the Sigmoid function is a mathematical function having a characteristic “S”-shaped curve or sigmoid curve.

The logistic function can take any value of x between -∞ to +∞ Source

where,

X₀ = the X value of the sigmoid’s midpoint

L = the curve’s maximum value

k = the logistic growth rate or steepness of the curve.

The logistic function can take any value of x between -∞ to +∞. For x approaching +∞, f(x) approaches L and for x approaching -∞, f(x) approaches 0.

The standard sigmoid function returns a value in the range 0 to 1. The equation is given by

Sigmoid can take any value of x between -∞ to +∞ Source

For x = 0, S(x=0) = 0.5 x < 0, S(x<0) < 0.5 and x >0, S(x>0) > 0.5 So, the Sigmoid function is 0-centered.

Problem Statement

We have financial data of customers available. One feature from it is the credit amount i.e. the credit already in the name of the customer. Now, depending on the amount of credit we intend to generate a risk score between 0–1.

Snapshot of Customers and existing credit amount data

The distribution of the data can vary in different datasets and among different features. Let’s see the distribution of credit_amount.

Histogram plot of credit_amount

The credit_amount is skewed towards the right. In different datasets and use-cases, the skewness or distribution of data may vary.

We wish to come up with a scoring mechanism that penalizes the outliers more.

In our case, we will come up with an ideal behavior and try to learn the parameters for the logistic function that can best mimic the ideal behavior. Let’s define the ideal behavior:

The Risk score to be in range 0 to 1. The data to be centered at the 65th percentile of data. (Assumption since we want to penalize the outliers more) Ideally, we wish the score for 65th percentile to be 0.50, for 75th percentile to be 0.65, for 80th percentile to be 0.70, and 85th percentile to be 0.75. For the rest of the data, we wish the scores to vary accordingly. Different features may have a different distribution and range, so we wish to come up with a technique that can learn the parameters of the logistic function to match the ideal behavior defined in Step 3.

For our problem of defining a risk score for credit_amount using the logistic function, let’s decode the parameters.

The logistic function can take any value of x between -∞ to +∞ Source

where,

X₀ = the X value of the sigmoid’s midpoint

L = the curve’s maximum value

k = the logistic growth rate or steepness of the curve.

Since we want the risk score range between 0 and 1, L = 1.

Since we want the logistic function to be centered around 65th percentile of data, X₀ = 65th percentile of credit amount

The growth rate k, we will learn through Random search, which can best mimic the ideal behavior with minimum Mean squared error from the ideal behavior defined in Step 3.

# Logistic function ~ b denotes X₀ and c denotes k(growth rate)

def sigmoid(x,b,c):

return 1 / (1 + math.exp(-c * (x-b)))

Calculating error for a probable growth rate ‘k’

# Mean Squared error between ideal and observed behavior

# b denotes X₀ and c denotes k(growth rate)

def cal_error(c,pcts,values_expected):

error = math.pow(sigmoid(pcts[0],pcts[3],c) - values_expected[0],2) + math.pow(sigmoid(pcts[1],pcts[3],c) - values_expected[1],2) + math.pow(sigmoid(pcts[2],pcts[3],c) - values_expected[2],2) + math.pow(sigmoid(pcts[3],pcts[3],c) - values_expected[3],2)

return error

Random search to find the best ‘k’, growth rate

def find_best_decay_parameter(pcts,values_expected):

best_error = 999999

best_c = 1.0

iterations = 5000

for i in range(iterations):

tmp = random.random()

error = cal_error(tmp,pcts,values_expected)

if error<best_error:

best_error = error

best_c = tmp

return best_c

Calling the function

percentiles = [85,80,75,65]

values_expected = [0.75,0.70,0.65,0.50]

b,c = find_decay_parameter(df.credit_amount,values_expected)

Output

Best value of Growth rate 'k' = 0.00047

Value of L = 1

value of X₀ = 3187

65th 75th 80th 85th

Value 3187 3972 4720 5969

Expected Score 0.50 0.65 0.70 0.75

Observed Score 0.50 0.59 0.67 0.79

I checked how the score varies with the different credit amounts

credit_amounts = [100,500,1200,3000,4000,5200,6000,7500,10000,12000,20000,25000]

risk = []

mp_values = {}

for credit_amount in credit_amounts:

mp_values[credit_amount] = round(sigmoid(credit_amount,b,c),2)

Output: