【Python】基于竞赛图法的NBA常规赛球队排名

背景

目前,NBA常规赛的球队排名按胜率从高到底依次排列。这样的排名方式非常简单,容易被大众普遍接受。但是,由于NBA常规赛赛制的非对称循环的特点,这样的排名规则并非完全公平,因此本文将尝试建立更合理的NBA常规赛的球队排名的数学模型。

常规赛赛制
NBA总共有30支球队,分为东部联盟,西部联盟,各15支球队。每个联盟各有3个赛区,每个赛区5支球队。基于球队所在城市之间的距离,82场常规赛的安排情况如下:

  1. 和不同联盟的球队打2场比赛,主客场各1场(总计30场);
  2. 和同赛区的球队打4场,各2个主场(总计16场);
  3. 和同联盟不同赛区的4支球队打3场(总计12场)6支球队打4场(合计24场);这其中打3场的球队是与这支球队上赛季战绩相差较大的,而且球队距离较远,由电脑编排的。

在NBA常规赛赛制中,每个球队间相互比赛的次数并不相同,往往存在有队伍因不幸多次遇到较强的队伍而输掉比赛,而碰到弱队的场次又很少,根据传统排名,该队伍就会被错误地排在排行榜的下游。
在这里插入图片描述

理论依据

排名的目的是根据比赛成绩排出反映各队真实水平的一个顺序,由于NBA常规赛赛制的非对称循环的特点,按胜率从高到底依次排列方法缺乏一定的公平性。因此,本文尝试建立能够处理不同场次的权重的NBA常规赛的球队排名的数学模型。

因此本文将根据竞争图法和层次分析法的原理,通过python建立NBA常规赛的球队排名的数学模型。

这里参考了这篇足球队排名的文章

数据

30个球队编号
在这里插入图片描述
2018-2019赛程整理
在这里插入图片描述

代码

import numpy as np 
import os
import pandas as pd
from pandas import Series,DataFrame



def score(df):
    num = np.zeros([30,30])  # 比赛场次矩阵
    score = np.zeros([30,30])  # 累计得分矩阵
    win_score = np.zeros([30,30])  # 胜利得分矩阵
    # 根据每场比赛,填充上面3个矩阵
    for i in range(len(df)):
        x = df['客队'][i]-1
        y = df['主队'][i]-1
        num[x][y] += 1  # 每一轮比赛增加一场比赛场数
        num[y][x] += 1
        a = int(df['比分'][i].split('-')[1])-int(df['比分'][i].split('-')[0])
        if(df['赛果'][i]=='胜'):
            win_score[y][x] += 1    # 增加胜者场数
            win_score[x][y] -= 1
            score[y][x] += a  # 增加累计赢了多少分
            score[x][y] -= a
                
        if(df['赛果'][i]=='负'):
            win_score[y][x] -= 1
            win_score[x][y] += 1
            score[y][x] += a
            score[x][y] -= a
    
    for i in range(len(score)):
        for j in range(len(score)):            
            if (win_score[i][j]>0):
                win_score[i][j] = 2 * win_score[i][j]   # 净胜一场计2分
                if(score[i][j]/num[i][j] > 15):   # 平均每场赢球15分以上,增加胜利得分1分
                    win_score[i][j] += 1
             
            
               
    for i in range(len(score)):
        for j in range(len(score)): 
            if(i == j):
                win_score[i][j] = 1  # 自己跟自己记为1
            if (win_score[i][j] < 0):
                win_score[i][j] = 1 / win_score[j][i]   # 负数时为正数的倒数
            if (win_score[i][j] == 0):  # 其他情况即为两球队互有胜负,记为1
                win_score[i][j] = 1
    
    
    return win_score



def normalization(data):  # 归一化矩阵
    _range = np.max(data) - np.min(data)
    return (data - np.min(data)) / _range



def final_score(win_score0):  # 得到最终得分矩阵
    for i in range(len(win_score0)):
        win_score0[:,i] = normalization(win_score0[:,i])
        
    final_score = np.zeros(30)
    for i in range(len(final_score)):
        final_score[i] = win_score0[i,:].sum()

    return final_score



def rank(df0,final_score):  # 根据最终得分矩阵,按序号给球队排名
    df_fianl = df0
    df_fianl['排名'] = 0
    rank = np.argsort(final_score)
    for i in range(0,len(rank)):
        df_fianl['排名'][rank[i]] = 30-i
        
    return df_fianl  


if __name__ == '__main__':
    # 导入数据
    file=os.path.dirname(os.path.abspath('__file__'))#返回代码所在目录
    data_file=os.path.join(file,'2018-2019赛程整理.csv')#返回数据所在文件位置
    df=pd.read_csv(data_file,engine='python',encoding='gbk')
    data_file=os.path.join(file,'30个球队编号.csv')#返回数据所在文件位置
    df0=pd.read_csv(data_file,engine='python',encoding='gbk')  
    
    #得到分数矩阵
    win_score = score(df)
    
    
    #得到球队最终分数
    final_score = final_score(win_score)
    
    #得到球队最终排名
    df_fianl = rank(df0,final_score)
    
    #导出最终排位表格
    if(os.path.exists(os.path.join(file,'层次分析法2019.csv'))):#如果输出结果表格已经存在,则删除
        os.remove(os.path.join(file,'层次分析法2019.csv'))
    df_fianl.to_csv('层次分析法2019.csv',index=False,encoding='gbk') #去掉index,输出表格csv

结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值