有线电视的时代已经过去,现在大家都是在线观看电影、短视频等。相信大家会发现大数据会根据个人的“喜好”推荐一些类似的视频内容,线上的流量是有限的,那么如何推荐,能保证视频播放量,还可以最大化视频播放总量呢?
问题描述
在很多视频在线流量调控场景,需要在保证每个视频内容播放量的同时,使得播放总量最大化。如广告、通知、宣发内容等。而线上流量是有限的,且不同的宣发内容对用户的吸引力不一样。
我们把问题模型建立如下:
- 决策优化变量:把视频内容 (剧集、电影、综艺等)推荐给用户群 的概率 , , 其中 为用户群集合, 为视频内容集合。
- 最大化目标:视频播放总量。 可以建模为点击率预测值( ) * 把 推荐给
的概率( )
- 参数 是将内容 推荐给用户 的预估点击率, 是保量内容集合, 则是内容 的播放量保量值。
- 约束:为某些宣发内容的播放量保量
则整个问题建模为:
数据
假设有如下的数据(实际业务数据会更多)。
保量约束表:
item0 |
item1 |
item2 |
|
下界 |
0 |
0 |
1 |
上界 |
∞ |
∞ |
∞ |
CTR 预估表:
user0 |
user1 |
|
item0 |
0.52 |
0.92 |
item1 |
0.31 |
0.93 |
item2 |
0.82 |
0.91 |
使用MindOpt求解器的API
直接采用求解器的API,需要查阅API文档来理解API的意思,没有建模语言可读性高。请参阅https://solver.damo.alibaba.com/doc/html/API%20reference/API-python/index.html来查看PythonAPI的使用说明。
关于Python的例子,在文档的5.建模与优化求解章节有Python的示例。这里是个LP的问题,我们可以参考:https://solver.damo.alibaba.com/doc/html/model/lp/linear%20optimization-python.html
下面我们分三种方式描述在本平台环境中的运行方法:
方法1:cell中直接输入代码运行
请运行下面cell中的代码,点击本窗口上面的播放△运行,或者摁shift+enter键运行:
# LP_4_distribution.py from mindoptpy import * if __name__ == "__main__": MDO_INFINITY = MdoModel.get_infinity() # 声明参数 Broadcast_Req = \ { # requirement: ( lower bound, upper bound) "item0" : ( 0, MDO_INFINITY), "item1" : ( 0, MDO_INFINITY), "item2" : ( 1, MDO_INFINITY) } Show_req = \ { # requirement: ( lower bound, upper bound) "user0" : ( 1, 1), "user1" : ( 1, 1) } CTR_value = \ { #( user, item ) : value ("user0","item0") : 0.52, ("user0","item1") : 0.31, ("user0","item2") : 0.82, ("user1","item0") : 0.92, ("user1","item1") : 0.93, ("user1","item2") : 0.91 } # Step 1. Create a model and change the parameters. model = MdoModel() try: # Step 2. Input model. # Change to maximize problem. model.set_int_attr("MinSense", 0) # Add variables. var = {} for ctr_name_ui, ctr_data in CTR_value.items(): var[ctr_name_ui] = model.add_var(0, 1, ctr_data, None, ctr_name_ui[0]+"-"+ctr_name_ui[1], False) # Add constraints. cons = {} # 播放量在范围内 for req_item_name, req_data in Broadcast_Req.items(): expr_i = MdoExprLinear() for ctr_name_ui, ctr_data in CTR_value.items(): if req_item_name == ctr_name_ui[1]: expr_i.add_term(var[ctr_name_ui], ctr_data) cons["Each_Item_Broadcast_In_Range-"+req_item_name] = model.add_cons(req_data[0], req_data[1], expr_i, "Each_Item_Broadcast_In_Range-"+req_item_name) # 每个用户有视频看 for req_user_name, req_data in Show_req.items(): expr_u = MdoExprLinear() for ctr_name_ui, ctr_data in CTR_value.items(): if req_user_name == ctr_name_ui[0]: expr_u.add_term(var[ctr_name_ui], 1) cons[ "Each_User_Total_X_Probability-"+req_user_name] = model.add_cons(req_data[0], req_data[1], expr_u, "Each_User_Total_X_Probability-"+req_user_name) # Step 3. Solve the problem and populate the result. model.solve_prob() model.display_results() time.sleep(1) #for print status_code, status_msg = model.get_status() if status_msg == "OPTIMAL": print("----\n") print("The solver terminated with an OPTIMAL status (code {0}).".format(status_code)) print("目标函数总收益是: {0}".format(model.get_real_attr("PrimalObjVal"))) print("原始解是:") for var_name,var_val in var.items(): primal_soln = var_val.get_real_attr("PrimalSoln") print(var_name," : " ,primal_soln) print("对偶解是:") for cons_name,cons_val in cons.items(): dual_soln = cons_val.get_real_attr("DualSoln") print(cons_name," : " ,dual_soln) else: print("Optimizer terminated with a(n) {0} status (code {1}).".format(status_msg, status_code)) except MdoError as e: print("Received Mindopt exception.") print(" - Code : {}".format(e.code)) print(" - Reason : {}".format(e.message)) except Exception as e: print("Received exception.") print(" - Reason : {}".format(e)) finally: # Step 4. Free the model. model.free_mdl()
运行之后,得到如下结果:
Start license validation (current time : 01-MAR-2023 20:59:34). License validation terminated. Time : 0.002s Model summary. - Num. variables : 6 - Num. constraints : 5 - Num. nonzeros : 12 - Bound range : [1.0e+00,1.0e+00] - Objective range : [3.1e-01,9.3e-01] - Matrix range : [3.1e-01,1.0e+00] Presolver started. Presolver terminated. Time : 0.000s Simplex method started. Model fingerprint: ==gZul3Z3V2dldnZ Iteration Objective Dual Inf. Primal Inf. Time 0 1.76000e+00 0.0000e+00 1.0900e+00 0.00s 1 1.74604e+00 0.0000e+00 0.0000e+00 0.00s Postsolver started. Simplex method terminated. Time : 0.003s Optimizer summary. - Optimizer used : Simplex method - Optimizer status : OPTIMAL - Total time : 0.004s Solution summary. Primal solution - Objective : 1.7460439560e+00 ---- The solver terminated with an OPTIMAL status (code 1). 目标函数总收益是: 1.7460439560439562 原始解是: ('user0', 'item0') : 0.0 ('user0', 'item1') : 0.0 ('user0', 'item2') : 1.0 ('user1', 'item0') : 0.0 ('user1', 'item1') : 0.8021978021978021 ('user1', 'item2') : 0.19780219780219788 对偶解是: Each_Item_Broadcast_In_Range-item0 : -0.0 Each_Item_Broadcast_In_Range-item1 : -0.0 Each_Item_Broadcast_In_Range-item2 : -0.021978021978021997 Each_User_Total_X_Probability-user0 : 0.838021978021978 Each_User_Total_X_Probability-user1 : 0.93
方法2:命令行直接运行.py文件
上面是直接在cell中运行所有的脚本,我们也可以建立个新文档,将Python代码存在LP_4_distribution.py文件。然后在Launcher中打开Terminal,执行python xx.py
文件来运行。
您也可以下载本.py文件,在自己的电脑上安装MindOpt求解器,然后在自己电脑的环境运行。
Luancher可以点击左上角的+打方块打开,Terminal在最下方,如截图示意。打开的窗口可以拖动调整位置。
打开的窗口可以拖动调整位置。
然后在Terminal命令行里运行如下指令:
python src/model/LP_4_distribution.py
运行得到的结果同方法1:
方法3:cell magic
在Python内核时候,模式运行,如下面的cell中,命令行指令前面增加!
来运行,请注意文件相对目录。
! python ./model/LP_4_distribution.py
运行得到的结果如同方法1:
求解结果
目标函数总收益是: 1.7460439560439562 代表总点击量预估为约1.75。
求解后变量的原始解是:
('user0', 'item2') : 1.0 代表将第2号视频播放给第0号用户的概率为1,
('user1', 'item1') : 0.8021978021978021 代表将第1号视频播放给第1号用户的概率为0.8,
('user1', 'item2') : 0.19780219780219788 代表将第2号视频播放给第1号用户的概率为0.2。
从结果上看,该分配方式,满足所有约束条件。
有兴趣的用户可以自行调节本例中涉及的参数,观察效果的变化。
联系我们
钉钉:y7r_yr2crky16
邮箱地址:solver.damo@list.alibaba-inc.com