通过上一篇文章,我们可以发现游戏的评分机制不仅和KDA有关,还受其它因素影响。于是重新定义一个模型如下:
相应的定义损失函数L(Loss function)如下,我们只需要求出a、b、c、d、e、f、g和s使得L函数最小即可。
接下来就按照上一篇文章所给出的梯度下降算法,求出最佳的a、b、c、d、e、f、g和s即可。需要注意的是L关于s的偏导数与其它的偏导数有区别。具体的偏导数如下:
最后就是通过编程来实现了,我这里使用的是C语言(如附录中完整的C语言程序)。当我看到在训练集(Training data)中训练出来的模型计算出来的最终结果时,有些兴奋,发现计算的结果非常接近于实际的评分(loss只有4.6)。
可是使用最终的模型在测试集(Testing data)中测试时,发现结果还是有一些偏差(loss超过了57)。这说明得出的模型还不够完善,可能还有一些因素没有考虑进去(如推塔数、击杀大小龙、三杀、四杀、五杀、超神等等),并且测训练集只用了30组数据。
另外,梯度下降算法可能得出来的只是局部的最小值,并非全局最小值。因为我们是求L函数的偏导数为0的点,而L函数可能会出现多个偏导数为0的点。还有一方面因素是数据精度的问题,Training data中的评分S并非真实游戏中计算得出来的,而是取了小数点后一位。但是,目前所得出来的模型已经可以说明一些问题了:每一次死亡所扣掉的分数,相当于大约两个击杀所获得的分数,或是三至四个助攻所获得的分数。
//计算结果:
S=2.688904+0.203089*K-0.413427*D+0.121452*A+0.138244*O+0.090832*H+0.010111*M+0.010000*P
计算源代码:
#include <stdio.h>
const int TA = 30;
//training data 数据来源:游戏中最近6场获胜方数据
float K[] = {2,12,4,6,2, 7,3,5,5,9, 9,3,3,1,3, 3,14,7,5,8, 7,18,0,0,4, 6,4,5,8,3};
float D[] = {2,2,2,2,2, 5,9,5,5,7, 1,0,1,0,6, 6,0,2,7,3, 4,3,3,3,4, 4,5,10,5,7};
float A[] = {2,5,7,9,9, 12,9,9,5,7, 7,4,8,4,1, 15,7,7,17,7, 8,5,11,12,9, 10,8,12,9,12};
float S[] = {4.9,12.8,8.2,10.0,8.2, 10.4,5.6,8.4,6.4,7.6, 13.3,7.3,9.4,8.2,6.8, 7.7,12.9,7.9,8.4,8.5, 7.5,13.4,7.1,6.5,8.1, 8.9,6.4,7.9,9.7,6.9};
float O[] = {8.0,40.7,18.2,15.5,17.6, 30.6,20.5,15.8,15.9,17.1, 32.7,12.6,20.7,14.8,19.1, 19.2,30.6,15.8,19.1,15.4, 17.7,34.8,20.2,12.7,14.6, 23.9,15.2,14.9,27.5,18.5};
float H[] = {12.8,25.1,16.1,27.5,18.6, 16.6,17.3,29.7,20.0,16.5, 20.7,12.9,14.4,21.8,30.2, 20.5,15.5,16.8,28.7,18.5, 17.4,19.5,17.4,15.0,30.7, 12.7,14.5,40.0,18.7,14.1};
float M[] = {17.6,23.7,17.5,17.9,23.3, 19.1,16.7,21.6,20.5,22.1, 24.2,21.9,19.0,19.7,15.3, 16.4,26.5,21.3,15.6,20.3, 22.1,28.8,16.1,15.5,17.5, 22.4,17.9,16.8,23.1,19.7};
float P[] = {15.4,65.4,42.3,57.7,42.3, 65.5,41.4,48.3,34.5,55.2, 84.2,36.8,57.9,26.3,21.1, 48.6,56.8,37.8,59.5,40.5, 51.7,79.3,37.9,41.4,44.8, 61.5,46.2,65.4,65.4,57.7};
float gradienta(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
float sum = 0;
for ( ; i < TA; ++i) {
float tmp = S[i] - a*K[i] - b*D[i] - c*A[i] - d*O[i] - e*H[i] - f*M[i] - g*P[i] - s;
sum += -2 * K[i] * tmp;
}
return sum;
}
float gradientb(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
float sum = 0;
for ( ; i < TA; ++i) {
float tmp = S[i] - a*K[i] - b*D[i] - c*A[i] - d*O[i] - e*H[i] - f*M[i] - g*P[i] - s;
sum += -2 * D[i] * tmp;
}
return sum;
}
float gradientc(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
float sum = 0;
for ( ; i < TA; ++i) {
float tmp = S[i] - a*K[i] - b*D[i] - c*A[i] - d*O[i] - e*H[i] - f*M[i] - g*P[i] - s;
sum += -2 * A[i] * tmp;
}
return sum;
}
float gradientd(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
float sum = 0;
for ( ; i < TA; ++i) {
float tmp = S[i] - a*K[i] - b*D[i] - c*A[i] - d*O[i] - e*H[i] - f*M[i] - g*P[i] - s;
sum += -2 * O[i] * tmp;
}
return sum;
}
float gradiente(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
float sum = 0;
for ( ; i < TA; ++i) {
float tmp = S[i] - a*K[i] - b*D[i] - c*A[i] - d*O[i] - e*H[i] - f*M[i] - g*P[i] - s;
sum += -2 * H[i] * tmp;
}
return sum;
}
float gradientf(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
float sum = 0;
for ( ; i < TA; ++i) {
float tmp = S[i] - a*K[i] - b*D[i] - c*A[i] - d*O[i] - e*H[i] - f*M[i] - g*P[i] - s;
sum += -2 * M[i] * tmp;
}
return sum;
}
float gradientg(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
float sum = 0;
for ( ; i < TA; ++i) {
float tmp = S[i] - a*K[i] - b*D[i] - c*A[i] - d*O[i] - e*H[i] - f*M[i] - g*P[i] - s;
sum += -2 * P[i] * tmp;
}
return sum;
}
float gradients(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
float sum = 0;
for ( ; i < TA; ++i) {
float tmp = S[i] - a*K[i] - b*D[i] - c*A[i] - d*O[i] - e*H[i] - f*M[i] - g*P[i] - s;
sum += -2 * tmp;
}
return sum;
}
void outputKDAS(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
for ( ; i < TA; ++i) {
float tmp = a*K[i] + b*D[i] + c*A[i] + d*O[i] + e*H[i] + f*M[i] + g*P[i] + s;
printf("%4.1f: %4.0f, %4.0f, %4.0f, %4.1f\n", tmp, K[i], D[i], A[i], S[i]);
}
}
float loss(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
float sum = 0;
for ( ; i < TA; ++i) {
float tmp = a*K[i] + b*D[i] + c*A[i] + d*O[i] + e*H[i] + f*M[i] + g*P[i] + s - S[i];
sum += (tmp * tmp);
}
return sum;
}
float step1 = 0.000001;
float step2 = 0.000001;
float step3 = 0.000001;
int main()
{
float a = 1;
float b = 1;
float c = 1;
float d = 0.01;
float e = 0.01;
float f = 0.01;
float g = 0.01;
float s = 1;
float ga = 0;
float gb = 0;
float gc = 0;
float gd = 0;
float ge = 0;
float gf = 0;
float gg = 0;
float gs = 0;
int t = 1000000;
int i = 0;
for ( ; i < t; ++i) {
ga = gradienta(a,b,c,d,e,f,g,s);
gb = gradientb(a,b,c,d,e,f,g,s);
gc = gradientc(a,b,c,d,e,f,g,s);
gd = gradientd(a,b,c,d,e,f,g,s);
ge = gradiente(a,b,c,d,e,f,g,s);
gf = gradientf(a,b,c,d,e,f,g,s);
gg = gradientg(a,b,c,d,e,f,g,s);
gs = gradients(a,b,c,d,e,f,g,s);
a = a - step1 * ga ;
b = b - step1 * gb ;
c = c - step1 * gc ;
d = d - step2 * gd ;
e = e - step2 * ge ;
f = f - step2 * gf ;
f = g - step2 * gg ;
s = s - step3 * gs ;
printf("%d:S= %f+%fK+%fD+%fA+%fO+%fH+%fM+%fP\n",i,s,a,b,c,d,e,f,g);
};
printf("result: S= %f+%fK+%fD+%fA+%fO+%fH+%fM+%fP, loss = %f\n",s,a,b,c,d,e,f,g,loss(a,b,c,d,e,f,g,s));
printf("ga = %f,gb = %f,gc = %f,gd = %f,ge = %f,gf = %f,gg=%f,gs=%f\n",a,b,c,d,e,f,g,s);
outputKDAS(a,b,c,d,e,f,g,s);
return 0;
}
测试源代码:
#include <stdio.h>
const int TA = 30;
//testing data 数据来源:任意6名好友(不同段位)游戏中获胜方数据
float K[] = {3,2,5,10,2, 12,2,5,16,4, 12,5,5,2,12, 7,10,3,20,2, 9,7,0,1,7, 6,6,8,9,14};
float D[] = {3,0,3,1,3, 4,4,0,3,4, 8,7,6,7,3, 5,6,6,9,9, 0,1,0,0,0, 9,7,7,9,7};
float A[] = {8,3,8,6,1, 6,19,24,6,17, 9,15,13,11,12, 6,12,9,6,22, 4,4,7,8,5, 10,17,15,17,13};
float S[] = {6.0,5.6,7.6,13.9,2.4, 8.5,5.8,9.7,10.1,5.7, 10.8,8.5,9.1,5.7,12.1, 6.5,8.4,5.4,9.0,6.4, 12.6,11.2,7.7,9.1,11.3, 5.2,7.2,8.4,9.1,11.6};
float O[] = {16.2,17.2,18.6,39.2,8.8, 21.1,8.4,28.2,29.7,12.6, 24.3,13.6,20.5,11.9,29.7, 17.4,20.7,15.2,28.5,18.2, 25.7,22.7,16.4,16.7,18.5, 14.8,18.9,21.0,17.7,27.6};
float H[] = {14.8,18.8,24.1,29.8,12.5, 23.2,30.5,15.5,12.3,18.5, 25.2,25.9,22.2,12.8,13.9, 19.4,26.4,14.9,19.5,19.8, 18.2,30.4,14.8,19.7,16.9, 18.4,11.2,15.2,36.6,18.6};
float M[] = {18.3,19.7,16.9,26.0,19.1, 21.5,15.0,18.7,23.8,21.1, 21.9,17.8,19.3,17.4,23.7, 23.5,20.0,17.9,21.2,17.4, 20.2,21.4,17.1,18.2,23.1, 23.1,18.4,19.7,16.8,22.1};
float P[] = {50.0,22.7,59.1,72.7,13.6, 46.2,53.8,74.4,56.4,53.8, 58.3,55.6,50.0,36.1,66.7, 31.0,52.4,28.6,61.9,57.1, 54.2,45.8,29.2,37.5,50.0, 37.2,53.5,53.5,60.5,62.8};
float loss(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
float sum = 0;
for ( ; i < TA; ++i) {
float tmp = a*K[i] + b*D[i] + c*A[i] + d*O[i] + e*H[i] + f*M[i] + g*P[i] + s - S[i];
sum += (tmp * tmp);
}
return sum;
}
void outputKDAS(float a, float b, float c,float d, float e, float f, float g, float s)
{
int i = 0;
for ( ; i < TA; ++i) {
float tmp = a*K[i] + b*D[i] + c*A[i] + d*O[i] + e*H[i] + f*M[i] + g*P[i] + s;
printf("%4.1f: %4.0f, %4.0f, %4.0f, %4.1f\n", tmp, K[i], D[i], A[i], S[i]);
}
}
int main()
{
//2.688904+0.203089K+-0.413427D+0.121452A+0.138244O+0.090832H+0.010111M+0.010000P
float a = 0.203089;
float b = -0.413427;
float c = 0.121452;
float d = 0.138244;
float e = 0.090832;
float f = 0.010111;
float g = 0.010000;
float s = 2.688904;
printf("testing data:\n");
outputKDAS(a,b,c,d,e,f,g,s);
printf("Loss = %f\n",loss(a,b,c,d,e,f,g,s));
return 0;
}