如何将体育博彩自定义损失函数改造为Keras可微分版本?
问题描述
我正在构建一个预测网球比赛盈利投注场次的模型,为此将投注赔率纳入yTrue变量,示例如下:
yTrue = np.array([[0,1,1.38,3.05],[1,0,1.05,7.85],[1,0,1.04,10.24],[1,0,1.22,3.71],[1,0,1.06,6.69],[1,0,1.48,2.46],[0,1,1.61,2.22]])
其中yTrue[:,0]和yTrue[:,1]代表热门选手/冷门选手的胜负标签(1表示获胜),yTrue[:,2]和yTrue[:,3]分别对应热门、冷门选手的投注赔率。假设单场投注额为1000单位:
- 数据集里第1场和最后1场冷门选手获胜,其余场次热门选手获胜,全对投注可获最大利润4120.0单位;
- 若预测结果为:
yPred = np.array([[0,1], [0,1],[1,0],[1,0],[0,1],[1,0],[1,0]])
则仅4次预测正确,总亏损为-210.0单位。
我已写出普通Python版本的损失函数:
import numpy as np yTrue = np.array([[0,1,1.38,3.05],[1,0,1.05,7.85],[1,0,1.04,10.24],[1,0,1.22,3.71],[1,0,1.06,6.69],[1,0,1.48,2.46],[0,1,1.61,2.22]]) yPred = np.array([[0,1], [0,1],[1,0],[1,0],[0,1],[1,0],[1,0]]) def myLoss(yTrue, yPred): maxPotentialProfit = 0 realProfit = 0 betUnits = 1000 for a in range(0,len(yTrue)): bet = yTrue[a] pred = yPred[a] favOdds = bet[2]-1 dogOdds = bet[3]-1 if bet[0] == 1: maxPotentialProfit += favOdds*betUnits else: maxPotentialProfit += dogOdds*betUnits if bet[0] == 1 and pred[0] == 1: realProfit += favOdds*betUnits elif bet[1] == 1 and pred[1] == 1: realProfit += dogOdds*betUnits else: realProfit -=betUnits return maxPotentialProfit - realProfit
现在需要将该损失函数改造为可微分版本,使其适配Keras框架。
可微分损失函数改造方案
要适配Keras,必须用TensorFlow的张量运算替代Python循环和硬条件判断(这类操作不可微分),核心思路是将逻辑转化为张量的逐元素运算:
步骤1:拆解yTrue的各个分量
从yTrue中提取胜负标签和净赔率(赔率-1,即每单位投注的盈利):
fav_win = yTrue[:, 0]:热门选手获胜标签dog_win = yTrue[:, 1]:冷门选手获胜标签fav_odds = yTrue[:, 2] - 1.0:热门选手净赔率dog_odds = yTrue[:, 3] - 1.0:冷门选手净赔率
步骤2:计算最大潜在利润
最大潜在利润是每场都投注正确的总盈利,用张量求和直接计算:
max_potential = K.sum( fav_win * fav_odds * bet_units + dog_win * dog_odds * bet_units )
步骤3:计算实际预测利润
原逻辑中,正确预测赚对应赔率的利润,错误则亏投注额。将该逻辑转化为张量运算:
- 预测热门的盈利/亏损:
yPred[:,0] * (fav_win*fav_odds*bet_units - (1-fav_win)*bet_units) - 预测冷门的盈利/亏损:
yPred[:,1] * (dog_win*dog_odds*bet_units - (1-dog_win)*bet_units) - 总实际利润为两者之和(每场只会预测其中一个选项)
步骤4:完整的Keras损失函数
结合以上步骤,最终可微分损失函数如下:
import tensorflow as tf from tensorflow.keras import backend as K def keras_bet_loss(yTrue, yPred): bet_units = 1000.0 # 转为浮点数避免整数运算问题 # 拆解yTrue分量 fav_win = yTrue[:, 0] dog_win = yTrue[:, 1] fav_odds = yTrue[:, 2] - 1.0 dog_odds = yTrue[:, 3] - 1.0 # 计算最大潜在利润 max_potential = K.sum( fav_win * fav_odds * bet_units + dog_win * dog_odds * bet_units ) # 计算实际利润 fav_profit = yPred[:, 0] * (fav_win * fav_odds * bet_units - (1 - fav_win) * bet_units) dog_profit = yPred[:, 1] * (dog_win * dog_odds * bet_units - (1 - dog_win) * bet_units) real_profit = K.sum(fav_profit + dog_profit) # 返回损失:最大潜在利润与实际利润的差值,模型需最小化该值 return max_potential - real_profit
关键注意事项
- 所有运算必须使用TensorFlow/Keras的张量函数(如
K.sum),不能用Python原生循环或NumPy函数,否则无法自动求导。 - 确保变量为浮点类型,避免整数运算导致的梯度消失。
- 若模型输出是概率(如Softmax激活),
yPred为0-1之间的浮点值,损失函数仍可微分,模型会自动学习让概率倾向于高利润选项。
内容的提问来源于stack exchange,提问作者velkyvont
相关产品推荐
相关产品推荐

