quantile函数_python&机器学习|为风控业务定制损失函数与评价函数(XGB/LGB)

印象里刘老师 @北冥乘海生 曾说过,算法工程师的第三层境界,是“擅定义问题” 可以为业务写出优雅简洁的损失函数与目标函数。自认没有这个本事。新书里面有一小段代码,简单构造了一个局部捕获率最优的评价函数,在实际业务中也取得了不错的业务表现,分享给大家。

XGBoost模型支持自定义评价函数损失函数。只要保证损失函数二阶可导,通过评价函数的最大化既可以对模型参数进行求解。实际使用中,可以考虑根据业务目标对这两者进行调整。

举个例子,假设现在有一个提额模型,用处是将分数最高的20%客户给与更高的额度。也就是期望分数最高的20%的客群正样本捕获率最大化。可能在保证上述前提,同时保证模型对正负样本有一定的区分能力。所以可以改写一个保证模型区分度,同时又能优化局部正样本捕获率的评价函数 。

⭐️自定义XGBoost模型损失函数与评价函数。

1.	# 自定义对数损失函数 
2.	def loglikelood(preds, dtrain):  
3.	    labels = dtrain.get_label()  
4.	    preds = 1.0 / (1.0 + np.exp(-preds))  
5.	    grad = preds - labels  
6.	    hess = preds * (1.0-preds)  
7.	    return grad, hess  
8.	  
9.	# 评价函数:前20%正样本占比最大化  
10.	def binary_error(preds, train_data):  
11.	    labels = train_data.get_label()  
12.	    dct = pd.DataFrame({'pred':preds,'percent':preds,'labels':labels})  
13.	    #取百分位点对应的阈值  
14.	    key = dct['percent'].quantile(0.2)  
15.	    #按照阈值处理成二分类任务  
16.	    dct['percent']= dct['percent'].map(lambda x :1 if x <= key else 0)    
17.	    #计算评价函数,权重默认0.5,可以根据情况调整  
18.	    result = np.mean(dct[dct.percent== 1]['labels'] == 1)*0.5 
19.	               + np.mean((dct.labels - dct.pred)**2)*0.5  
20.	    return 'error',result  
21.	  
22.	watchlist  = [(dtest,'eval'), (dtrain,'train')]  
23.	param = {'max_depth':3, 'eta':0.1, 'silent':1}  
24.	num_round = 100  
25.	# 自定义损失函数训练  
26.	bst = xgb.train(param, dtrain, num_round, watchlist, loglikelood, binary_error)

可以看到评价函数由两部分组成,⭐️第一部分权重默认为0.5,目的是使得前20%样本中的正样本占比最大。因为正样本的标签为0,因此pandas.quantile()函数分位点参数0.2,表示预估为正样本概率最大的前20%分位点。⭐️第二部分权重同样默认设置为0.5,目的是让模型对正负样本的识别能力得到保障。

实际使用中,可以根据,对模型表现的侧重点,进行权重选择 。比如当更希望模型关注于捕获率时,可以调整第一部分权重为0.8,将第二部分权重调整为0.2。本文给出的是一种启发性的思路,读者还可以根据实际情况改写更贴合业务的损失函数。

⭐️LightGBM中也同样支持自定义损失函数和评价函数。代码上有一些细微差别。评价函数需要返回三部分,用False代替。

 # 自定义二分类对数损失函数
def loglikelood(preds, train_data):
    labels = train_data.get_label()
    preds = 1. / (1. + np.exp(-preds))
    grad = preds - labels
    hess = preds * (1. - preds)
    return grad, hess

# 自定义前20%正样本占比最大化的评价函数
def binary_error(preds, train_data):
    labels = train_data.get_label()
    dct = pd.DataFrame({'pred':preds,'percent':preds,'labels':labels})
    #取百分位点对应的阈值
    key = dct['percent'].quantile(0.2)
    #按照阈值处理成二分类任务
    dct['percent']= dct['percent'].map(lambda x :1 if x <= key else 0)  
    #计算评价函数,权重默认0.5,可以根据情况调整
    result = np.mean(dct[dct.percent== 1]['labels'] == 1)*0.9 + np.mean((dct.labels - dct.pred)**2)*0.5
    return 'error',result, False

gbm = lgb.train(params,
                lgb_train,
                num_boost_round=100,
                init_model=gbm,
                fobj=loglikelood,
                feval=binary_error,
                valid_sets=lgb_eval)

感谢阅读。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值