# cost sensitive loss function in lightbm with individual cost

i am looking for a cost sensitive function that will have weights according to individual row feature (like amount) this way i can penalize more FN which has large amount vs. low dollar amount. took the raw solution from the excellent article : https://maxhalford.github.io/blog/lightgbm-focal-loss/ and incorporated it into the objective function (correctly ?) , but i wonder how should i do the same for the evaluation function.

here is the code:

class FocalLoss_with_amt:

def __init__(self, gamma, alpha=None):
self.alpha = alpha
self.gamma = gamma

def at(self, y):
if self.alpha is None:
return np.ones_like(y)
return np.where(y, self.alpha, 1 - self.alpha)

def pt(self, y, p):
p = np.clip(p, 1e-15, 1 - 1e-15)
return np.where(y, p, 1 - p)

def __call__(self, y_true, y_pred):
at = self.at(y_true)
pt = self.pt(y_true, y_pred)
return -at * (1 - pt) ** self.gamma * np.log(pt)

def grad(self, y_true, y_pred):
y =  2 * y_true - 1  # {0, 1} -> {-1, 1}
at = self.at(y_true)
pt = self.pt(y_true, y_pred)
g = self.gamma
return at * y * (1 - pt) ** g * (g * pt * np.log(pt) + pt - 1)

def hess(self, y_true, y_pred):
y =  2 * y_true - 1  # {0, 1} -> {-1, 1}
at = self.at(y_true)
pt = self.pt(y_true, y_pred)
g = self.gamma

u = at * y * (1 - pt) ** g
du = -at * y * g * (1 - pt) ** (g - 1)
v = g * pt * np.log(pt) + pt - 1
dv = g * np.log(pt) + g + 1

return (du * v + u * dv) * y * (pt * (1 - pt))

def init_score(self, y_true):
res = optimize.minimize_scalar(
lambda p: self(y_true, p).sum(),
bounds=(0, 1),
method='bounded'
)
p = res.x
log_odds = np.log(p / (1 - p))
return log_odds

def lgb_obj(self, preds, train_data):
amt = train_data.get_weight()
y = train_data.get_label()
p = special.expit(preds)
return amt*self.grad(y, p), amt*self.hess(y, p)

def lgb_eval(self, preds, train_data):
amt = train_data.get_weight()
y = train_data.get_label()
p = special.expit(preds)
is_higher_better = False
return 'focal_loss', self(y, p).mean(), is_higher_better

fl_amt = FocalLoss_with_amt(alpha=0.27242, gamma=2.478478446)

d_train.set_weight(weight=np.log(X_train['amount']))
d_val.set_weight(weight=np.log(X_val['amount']))

model_amt=lgb.train(best, d_train, 10000, valid_sets=[d_val], fobj=fl_amt.lgb_obj,
feval=fl_amt.lgb_eval,early_stopping_rounds=40, verbose_eval=500)