我是格斗运动的忠实粉丝,尤其是拳击是我的最爱。 尽管它看起来可能是纯粹的体育运动,而您的唯一目标是发件箱或将对手击倒,但人们所期望的却更具战略意义,并且融入了元素心理学。 就像下棋游戏一样,每次掷拳都要计算,漫不经心地过度伸展自己可能会使您更容易受到反击的打击,而过于被动和防守可能会使势头向对手有利,而不会使您获得足够的积分来赢得战斗。 如果您让自我怀疑陷入困境或被对手吓倒,那么您已经输掉了这场战斗。 最重要的是,您需要尊重这项运动及其带来的威胁生命的危险。 用Sugar Ray Leonard的话来说,“你不玩拳击”。

从表面上看,这可能不是“绅士运动”。 大多数职业拳击手如何以令人难以置信的运动精神操守自己,总是给我留下深刻的印象。 我发现这类似于生活,而对手就是生活的挑战。

鉴于对拳击的兴趣,我决定为我的Capstone项目之一构建一个Web应用程序,该应用程序将显示最终用户根据所选战斗机而出现不同战斗结果的概率。 但是,在此之前,我想观察数据并回答我的一些遗留问题。 我对不同年龄组之间的胜率和战斗姿态特别感兴趣。 我还想清楚地了解我的数据集中的拳击手所赢得的胜利数量,并将其与打出的回合数量并列。 最后,我想根据每个拳击手打的回合的结果和他们击败的对手的能力来建立每个分区前10名拳击手的名单。 为了回答这些问题,我决定构建一个交互式仪表板,其中包含与问题相关的可视化效果。 互动性使我可以使用自己的体重级别/分区和性别作为过滤器,以针对所选体重级别和性别的拳击手定制可视化效果。 这将作为我项目的探索性数据分析部分。

进入数据

对于这个项目,我获得了3843个拳击手的列表,每个拳击手都有指向其个人资料的URL。 该链接包括与每个拳击手关联的唯一标识符。

data[ 'id' ] = data[ 'players_links' ].str.extract( '(\d+)' )

为了丰富我在每架战斗机上的数据,我需要提取数字唯一标识符。 我在GitHub上的一个基于node.js的API上找到了一个API,该API要求拳击手的唯一ID,以便提取与每个战斗员进行的比赛有关的所有数据,裁判的记分卡,每次比赛的长度,结果和其他数据这可能对我的项目很有价值。

然后,使用此列表,我在node.js中创建了一个函数,该函数将读取从每个战斗机的配置文件URL中提取的每个唯一标识符,将ID附加到API中的方法中,该方法将允许我获得所需的输出并将输出写入到新的csv。 您可以在我的GitHub上查看所有代码。

async function writeData ( )  {const csv = require ( 'csv-parser' )const results = [];fs.createReadStream( 'C:\\Users\\User\\Documents\\GitHub\\Springboard Capstone BoxingPredictionWebApp\\boxingdata\\readdata.csv' ).pipe(csv()).on( 'data' , ( data )=> results.push(data)).on( 'end' , async () => {const cookieJar = await getCookieJar();const promises = [];results.forEach( ( data ) => {promises.push(boxrec.getPersonById(cookieJar,data.id));})const fighters = await Promise .all(promises); fighters.forEach( ( fighter ) => {let data = '' ;for ( const key in fighter.output) {if ( Array .isArray(fighter.output[key])) {data += JSON .stringify(fighter.output[key]) + ',' ;} else if ( typeof fighter.output[key] === 'object' ) {data += JSON .stringify(fighter.output[key]) + ',' ;} else {data += fighter.output[key] + ',' ;}}data = data.replace( /(^,)|(,$)/g , "" );data += '\n' ;fs.appendFile( 'C:\\Users\\User\\Documents\\datatest.csv' ,data, ( err ) => {if (err) throw err;});

由于API以JSON格式返回输出。 我留下的数据不干净而且有点混乱。 列间距不一致,对于某些拳击手,第7列似乎与给定拳击手的出生日期相关,而在其他情况下,该列具有与给定拳击手的首次比赛日期相关的数据。

观察和理解数据以及输出的性质揭示了一种模式。 每次打架都以日期键开始,键的值是给定打架的日期。 我使用这种逻辑根据给定战斗机进行的独特回合来划分栏目。

df = pd.DataFrame(file_full[file_full.columns[ 0 :]].apply( lambda x: ' ' .join(x.astype(str)),axis= 1 ))
df = pd.DataFrame(df[ 0 ].str.replace( 'date' , 'dateday' ))
#split each fight into a separate column
df_split = pd.DataFrame(df[ 0 ].str.split( 'date' ,expand= True ))
def func (df,col) :return df[col].str.extract( 'day(?P<day>.*?)firstBoxerRating(?P<firstBoxerRating>.*?)firstBoxerWeight(?P<firstBoxerWeight>.*?)judges(?P<JudgeID>.*?)links(?P<Links>.*?)location(?P<location>.*?)metadata(?P<metadata>.*?)numberOfRounds(?P<numberofrounds>.*?)outcome(?P<outcome>.*?)rating(?P<rating>.*?)referee(?P<referee>.*?)secondBoxer(?P<secondBoxer>.*?)secondBoxerLast6(?P<secondBoxerLast6>.*?)secondBoxerRating(?P<secondBoxerRating>.*?)secondBoxerRecord(?P<secondBoxerRecord>.*?)secondBoxerWeight(?P<secondBoxerWeight>.*?)titles(?P<titles>.*?){' )
for i in range( 1 ,len(df_split.columns) -1 ):df_split[[ 'date' +str(i), 'firstBoxerRating' +str(i), 'firstBoxerWeight' +str(i), 'JudgeID' +str(i), 'Links' +str(i),'location' +str(i), 'metadata' +str(i), 'numberofrounds' +str(i), 'outcome' +str(i), 'rating' +str(i),'referee' +str(i), 'secondBoxer' +str(i), 'secondBoxerLast6' +str(i), 'secondBoxerRating' +str(i),'secondBoxerRecord' +str(i), 'secondBoxerWeight' +str(i), 'titles' +str(i)]] = func(df_split,i)

我继续将数据集中的列连接为一列。 我认为将所有数据都放在一列中将使提取与我指定的字符模式匹配的数据组更加容易,然后根据此数据创建列。 我遍历各列,将不同的字符模式提取到多个唯一的列中。 对于每场比赛,我都有回合的日期,拳击手的等级和体重,与裁判相关的信息(法官姓名和记分卡),回合的位置,元数据,包括比赛的时间,拳击手的别名等,轮次,回合的结果,与裁判有关的信息,对手的姓名,最近6次的回合结果,他们的等级,当时的所有拳击记录(发生回合时),他们的体重和任何头衔由两个拳击手举行。 对于这些属性中的每一个,我都有85列,这大概是因为该数字是我的数据集中拳击手搏击次数最多的一次。

进一步的清理涉及两个过程,我不得不重复多次。 这涉及删除字符并将数据格式更改为字符串或浮点数,


#cleanup first boxer rating
def remove_colon (col_name) :return merged[col_name].str.replace( ':' , '' )
#weights need to be converted to float
def firstweight (col_name) :a = remove_colon(col_name)return pd.to_numeric(a,errors= 'coerce' )
#update first boxer rating columns
boxer_var = list_var( 'firstBoxerRating' )
for i in boxer_var:merged[i] = remove_colon(i)
#update weight
weight_var = list_var( 'firstBoxerWeight' )
for i in weight_var:merged[i] = firstweight(i)

或从每列中提取字符模式。 对于清理过程的完整分解,您可以查看我的完整代码 。

def split_time (col) :return merged[col].str.extract( '(\d*\:\d+)' ,expand= True )
times = list_var( 'metadata' )
for i in times:merged[i] = split_time(i)

为了找到战斗姿态之间的胜率,我决定建立一个热图。 为此,我将数据从宽到长整形,将数据专门限制在需要的列上。 简而言之,在每次战斗中,我查看了两个拳击手的战斗姿态,计算了战斗姿态的获胜次数,计算了每种姿态组合之间的总搏斗次数,然后将两者相除,得出我所定义的“胜利”。率”。

我使用相同的逻辑来构建数据集,然后使用该逻辑来构建另一个热图来比较不同年龄组之间的胜率。 对于年龄段,我将战斗机年龄划分为5年时间间隔,以创建20-25、25-30等年龄段。我强烈希望看到30-35岁年龄段(可能是35-40岁年龄段)的胜率会大大提高男性体重师。 有趣的是,这些似乎是大多数精英拳击手似乎达到顶峰的年龄范围。 我编写的代码在GitHub存储库中可用。

因为我想按分区显示前十名的拳击手。 我需要弄清楚自定义评分的工作原理。 尽管我本可以完全专注于获胜和平局,但每次获胜和平局都应获得奖励,但我认为我需要惩罚战斗机的损失。 我给每场比赛X10奖励胜利,X5奖励平局,-X10罚分损失。 我还想考虑一架特定战斗机击败对手的能力。 击败许多对手是一项了不起的壮举,但击败一名优秀的拳击手与击败一名旅行社之间是有区别的。

opp_names = [ 'secondBoxer' +str(i) for i in range( 1 , 85 )]
outcome_cols = [ 'outcome' +str(i) for i in range( 1 , 85 )]
#remove quotation marks from secondboxer name
data[opp_names] = data[opp_names].astype(str).apply( lambda x: x.str.replace( '"' , '' ))
#get points for each opponent, if negative convert to zero
data[opp_names]=data[opp_names].apply( lambda x : x.map(dict(zip(topten.name,topten.total_points))))
data[opp_names] = data[opp_names].fillna( 0 )
data[opp_names] = data[opp_names].mask(data[opp_names] < 0 , 0 )
data[outcome_cols] = data[outcome_cols].astype(str).apply( lambda x: x.str.replace( '"' , '' ))
#add opp points to total points if outcome was a win
topten[ 'total_points' ] = (data[opp_names].where(data[outcome_cols].eq( 'win ' ).values, 0 ).sum(axis= 1 )/ 5 ) + (topten[ 'total_points' ])

我使用上一段所述的奖励系统,为每个对手返回了总分。 对于拳击手来说,没有得分(可能是因为缺少数据或拳击手还没有打架)或得分为负(因为拳击手输掉了更多赢得他/她的打斗),所以我用0。然后,我将对手的得分相加,即战斗的结果是获胜(即,result_cols中列出的列中的字符串等于获胜),将得分除以5,并将其加到战斗机的总得分中。

我将得分除以5,是因为我不希望对手的得分超过从胜利和失败得出的得分。 我不想创造一个场景,在这个场景中击败得分为500的玩家会使他的整体得分翻倍。 但是,如果给定的战斗机有击败高素质对手的历史,那么他们对手的才能就会大大提高他们的等级。

但是,我的自定义评分的问题在于,在很多情况下,我缺少有关某些拳击手(包括一些精英拳击手)的数据。 但是,我将不断改进此仪表板。 此等级的另一个局限性在于,得分不取决于战斗发生的时间以及对手在该时间点的得分。 我只是根据对手的总赢,输和平局来查看对手的当前得分。

构建交互式仪表板

我选择使用破折号包来帮助构建仪表板。 该软件包结合了flask和react.js元素,使其成为一个非常强大且美观的软件包,可用于构建交互式仪表板。

对于每个可视化,我都通过回调装饰器声明了输入和输出。 输入要么包括过滤器(例如分区和性别),要么是我创建的要显示在信息中心顶部的图像轮播的图片。

@app.callback(dash.dependencies.Output( 'total-bouts-v-bouts-won' , 'figure' ),[dash.dependencies.Input( 'weight_class' , 'value' ),dash.dependencies.Input( 'gender' , 'value' )])

在装饰器下,我创建了一些函数,用于根据用户的输入选择来更新可视化效果。

def update_scatterplot (weight_class,gender) :if weight_class is None or weight_class == []:weight_class = WEIGHT_CLASSif gender is None or gender == []:gender = GENDERweight_df = data[(data[ 'division' ].isin(weight_class))]weight_df = weight_df[(weight_df[ 'sex' ].isin(gender))]return {'data' : [go.Scatter(x=weight_df[ 'bouts_fought' ],y=weight_df[ 'w' ],text=weight_df[ 'name' ],mode= 'markers' ,opacity= 0.5 ,marker={'size' : 14 ,'line' : { 'width' : 0.5 , 'color' : 'blue' }},)],

例如,通过散点图显示整个集合,重点放在给定战斗机所赢得的胜利和总回合上,选择给定的分区和/或性别会根据用户的选择更改图形的输出。

创建这些过滤器的过程涉及使用破折号上的一些核心组件,特别是使用多个下拉组件来创建下拉菜单,使人们可以选择单个或多个选项。

  dcc.Dropdown(id= 'weight_class' ,options=[{ 'label' : i, 'value' : i} for i in data[ 'division' ].unique()],multi= True),dcc.Dropdown(id= 'gender' ,options=[{ 'label' : i, 'value' :i} for i in fight_outcomes[ 'sex' ].unique()],multi= True),

Dash还允许您使用HTML组件,我使用了其中的一些组件将图像轮播放置在仪表板顶部的中心,并控制图像在轮播上的变化速度。

html.Section(id= 'slideshow' ,children=[html.Div(style={ 'backgroundColor' :colors[ 'background' ],'textAlign' : 'center' },id= 'slideshow-container' ,children=[html.Div(id= 'image' ),dcc.Interval(id= 'interval' ,interval= 3000 ),])])

我遇到的一个小问题是我的热图上的轴排序。 为确保x轴和y轴的顺序一致且顺序正确,我通过使用categoryarray定义了我的轴出现的顺序来对x轴进行自定义排序。 这使我可以根据我在列表中定义的自定义定义顺序来设置x轴的顺序。 您可以在此处获得我用来构建这些可视化效果的代码的完整视图。

为了使设计最简单的仪表板对所有人可见,我选择将仪表板部署在Heroku上 。 欢迎在Twitter @emmoemm上将任何反馈,建议或评论发送给我

From: https://hackernoon.com/d-nr1o32po

我如何构建一个交互式仪表板Web应用程序以可视化拳击数据相关推荐

  1. Nest的基本概念,以及如何使用Nest CLI来构建一个简单的Web应用程序

    Nest是一个用于构建高效.可扩展的Node.js服务器端应用程序的框架.它是基于Express.js构建的,并且提供了多种新特性和抽象层,可以让开发者更加轻松地构建复杂的应用程序. 本文将介绍Nes ...

  2. 如何构建一个交互式数据分析 Web 应用?

    作者 | AJ Gordon 责编 | Carol 头图 | CSDN  付费下载于视觉中国 出品 | CSDN云计算(ID:CSDNcloud) 本文主要介绍如何利用Python的Streamlit ...

  3. 使用Spring boot,Thymeleaf,AngularJS从零开始构建一个新的Web应用程序-第1部分

    在这一系列博客文章中,我们将使用以下技术堆栈构建完整的响应式Web应用程序: 1)弹簧靴 – Spring MVC网站 – Spring Data JPA –Spring安全 2)Thymeleaf用 ...

  4. 使用Spring boot,Thymeleaf,AngularJS从零开始构建一个新的Web应用程序-第3部分

    在之前的博客中,我们使用Thymeleaf,Bower和Bootstrap构建了登录页面,并将其部署到了Heroku. 在此博客中,我们将介绍用于前端的AngularJS和在后端的Spring Boo ...

  5. Plotly 和 Dash 构建 Python 交互式仪表板类 App

    特点 借助 Plotly 的 Dash 框架,Python 程序员现在可以比以往更轻松地开发完整的数据应用程序和交互式仪表板 Dash 应用程序可供非技术受众使用,这将使更广泛的人群可以进行数据分析 ...

  6. 使用ASP.NET Core,JavaScript,PostegreSql和ChartJs的动态仪表板Web应用程序

    目录 介绍 先决条件 创建项目架构 创建数据库 实现后端 一)创建DataAccess 1)创建实体和关系 2)设置数据库 3)创建存储库 II)实现应用逻辑 III)实现Web服务 IV)测试Web ...

  7. 如何构建一个简单的语音识别应用程序

    "In this 10-year time frame, I believe that we'll not only be using the keyboard and the mouse ...

  8. Flutter 构建一个完整的聊天应用程序

    在本教程中,我将向您展示如何使用 Flutter 构建一个完整的聊天应用程序.对于这一部分,我们将创建应用程序的 UI 原型,然后我将向您展示如何使用 firebase 创建后端服务并创建聊天系统. ...

  9. 一个合格的web前端程序员要学会哪些技能?

    想要成为一名合格的web前端程序猿,要学习的东西有很多,那么web前端要学会哪些技能呢?来看看下面的详细介绍就知道了. 一个合格的web前端程序员要学会哪些技能?想从事web前端开发,只会HTML.C ...

  10. hosts多个ip对应一个主机名_一个简单的Web应用程序,用作连接到ssh服务器的ssh客户端...

    WebSSH 一个简单的Web应用程序,用作连接到ssh服务器的ssh客户端.它是用Python编写的,基于tornado,paramiko和xterm.js. 特征 支持SSH密码验证,包括空密码. ...

最新文章

  1. 数据建模学习笔记-2-《高质量数据库建模 2-建模流程》
  2. 大头贴计算机教程,美颜相机大头贴在哪里 教你怎么弄动漫大头贴
  3. 《HTML5 界面设计与开发》 读书笔记
  4. Xposed注入实现分析及免重启定制
  5. windows下修改mysql密码 10054错误
  6. 06.动态SQL和foreach
  7. Oracle Stream Replication技术
  8. wordpress后台无法登录问题
  9. JDK源码系列(3)-String
  10. linux 编译环境包,linux上war包编译环境搭建
  11. Tensorflow高级封装
  12. SQL Agent服务无法启动如何破
  13. python深拷贝和浅拷贝的区别_python 深拷贝与浅拷贝的区别
  14. 手把手教你如何使用IOMETER测试工具测试存储
  15. ASP.NET快速入门
  16. android编程:调节视频画面分辨率,Android实现任意分辨率视频编码的思考与实现
  17. 洛谷P2440 木材加工 —二分答案
  18. android 设置录像帧率,华为手机设置相机录像帧率的方法
  19. 【数据处理】PS动作功能(附:下雨效果)
  20. 多传感器融合track fusion

热门文章

  1. ERR Target instance replied with error: NOAUTH Authentication required
  2. Game of Thrones : 权利的游戏
  3. 我只会SQL,到底能不能找到工作?
  4. 数据分析报告入门(3)
  5. 【约束优先级问题二】动态高度cell
  6. 国内支持Amazon Alexa的智能家居
  7. python降序排序_python中如何降序排列
  8. android xposed 简书,Xposed 入坑篇
  9. 使用Excel TRIMMEAN忽略异常值
  10. 门面担当——外观模式