背景

想要用ML模型拟合业务,但实际中经常会遇到类似下面的场景:

  • 二手车价格预估:同一辆车,预估的价格与里程应该是严格负相关的;
  • 保费预估:保额越高,保费越高;
  • 理财产品中,比如余额宝,用户的利率敏感度预估(利率敏感度=用户余额变化/利率变化):同一用户,理财产品利率越高,购买金额越高,余额越高;

如果直接用比如xgb或dnn模型拟合 X -> Y,

$$ p_y=f(x), where\ x = [x_c, x_p] $$

其中f为xgb或dnn等具体模型,x_c为先验无关的特征(比如二手车里面的品牌和里程特征无关),x_p为先验相关的特征。由于噪声数据的存在,模型最终的打分输出很难保证上面先验的 单调性约束。比如采用树模型建模,即有可能对于同一个用户,出现保额越高,预估的保费更低的情况,这显然是不符合常理且没法跟业务解释的。因此必须在模型设计时考虑变量的先验约束。一种最简单的方法,将上面的模型做成纯线性LR模型,则目标变量y和x一定是线性的单调关系。但是,LR可能对无约束的其他特征变量的学习不够充分(欠拟合)。因此在该基础上,自然想到对其他变量采用其他的建模方法,而约束变量采用先验的建模方法。

单独建模先验约束特征

一种自然想到的方法是,将f拆解成2部分:

$$ p_y=f_c(x_c) + f_p(x_c,x_p) $$

其中:

  • $f_c$主要建模先验无关特征,可以是任意复杂模型,其输入只能是$x_c$;
  • $f_p$单独建模先验信息,必须是满足先验约束的模型,一般是满足单调性的模型,比如LR、IsotonicRegression等,其输入包含$x_p$;

根据这个思路,二手车价格的建模就可以表达为:predicted car_value = 基础平均价格(baseclean_trade) + 里程相关的价格(predicted mieage_adjustment)。

1714909145219

这种方法建模有个问题,数据集怎么构造?针对二手车预估这个问题,标签一般只有最终的车价,basecleantrade model和averagemileage模型的标签怎构造呢?

  • basecleantrade model:除里程相关特征(odometer,mileage等)外,其他特征group by计算平均价格作为标签,即同款车在不同里程下的平均价格作为标签;
  • averagemileage:里程特征的平均作为标签,其他特征作为模型的输入;

从数据构造过程也可以看出,要采用这种方法的话,就一定得保证同款车有多个不同里程下的数据,这样效果才会好。

在DNN中End2End建模先验信息

上面需要建模多个模型,前序模型无法用到最终要拟合的目标信息,势必会带来一定的性能损失,能否只用一个模型,做到End2End的训练呢?答案是可以在DNN中加入先验。

同样对于二手车价格的建模,如下图,可以在DNN中针对里程这一项加入先验约束(mileageadjust module)。

图里画的是线性约束。具体用什么约束函数最优,是通过数据分析得到的,如果统计数据发现更满足线性关系那就采用线性先验,如果是类似指数类的分布,可能survival/cox function作为先验约束函数能达到更平滑的效果。

1714909409568

根据这个思路,如果我要预估理财中的用户利率敏感度可以怎么做呢?把上面的思路顺一顺:

  1. 分析历史数据中“利率变化"和“余额变化"的关系,如果是接近线性,那就可以用线性先验,如果只是单调则可以考虑survival/cox function;也可以结合一些业务/经济规律来定义先验,比如需求价格弹性
  2. DNN建模,在模型中加入步骤1中得到的先验约束;

最终,利率敏感度建模可以类似下面这样(先验有点类似于需求价格弹性先验)。其中$Q_t$是用户在t日的余额,$r_t$是产品在t日的利率,$Q_{t->t+N}$用户余额变化,$x_{t^+}$是用户利率变化,模型训练完后的$E_d$即可输出作为利率敏感度。

1714911096323

扩展

其实了解过uplift因果模型的同学,应该很容易发现这里的建模方式和uplift中的s-learner很像,只是s-learner中一般treatment是二元变量,但是这里例子中的变量(比如利率,里程等)是连续型变量。

所以要继续深入可以研究将uplift中的方法引入到先验建模场景中。