为什么我选了Golang来做CBA数据统计
说实话,一开始我没想到会用Golang来搞CBA(中国篮球协会)的数据库统计,之前用Python写爬虫和数据分析习惯了,但最近接手一个项目,要求处理海量的CBA历史比赛数据——从1995年甲A联赛到现在的每一场得分、篮板、助攻、抢断、盖帽,还有球员的投篮热区图数据,数据量一上来,Python那点性能就有点吃力了,尤其是在做实时统计的时候。
然后我就想到了Golang,为什么?并发能力强,编译成单二进制文件部署简单,而且处理结构化数据的速度真心快,我试了下用goroutine并行抓取多个赛季的数据,那效率,啧啧,比Python翻了好几倍。
第一步:设计数据库表结构(像搭篮球战术板一样)
做统计前,必须先把数据仓库理清楚,我建了这么几张核心表,每张表的字段我都按照实际比赛记录来设计:
| 表名 | 关键字段 | 用途说明 |
|---|---|---|
players |
id, name, team_id, position, height, weight | 球员基本信息,位置分后卫/前锋/中锋 |
teams |
id, name, city, founded_year | 球队基础数据,包括主场城市 |
games |
id, home_team_id, away_team_id, game_date, home_score, away_score | 比赛主客场比分,时间字段建立索引 |
player_stats |
id, game_id, player_id, points, rebounds, assists, steals, blocks, minutes | 单场个人统计,这是最核心的一张表 |
这张player_stats表,我特意加了minutes字段,因为效率值(PER)计算必须要用到出场时间,没有这个字段,很多高级统计根本做不了。
并发抓取:用goroutine把1995年的数据挖出来
CBA官网的数据是分页的,每页20行,我写了个爬虫,用goroutine并发请求多个赛季的页面,这里有个坑——早期赛季数据格式和现在不一样,有的字段是空字符串,有的直接是,所以我在解析的时候,必须用类型断言加正则过滤,不然strconv.Atoi直接panic给你看。
看段核心代码,我做了个简单的并发池:
func fetchSeasonData(season int, wg *sync.WaitGroup, results chan<- []PlayerStats) {
defer wg.Done()
baseURL := fmt.Sprintf("https://api.cba.com/stats?season=%d", season)
// 这里分页遍历,每页生成一个goroutine去抓
for page := 1; page <= totalPages; page++ {
// 实际请求和处理
stats := parsePage(pageData)
results <- stats
}
}
这样设计之后,读取CBA历史上二十多年的比赛数据,从原来的半小时缩短到了三分钟,主协程用range从channel里消费数据,写入数据库的时候再开一个批量插入的协程,基本上没有瓶颈。
统计指标:别只盯着场均得分
很多人做篮球统计就喜欢算场均得分、总篮板这些基础数据,但CBA数据库统计要做得有价值,必须上点进阶指标,我用Golang写了一套计算这些指标的函数:
- 有效命中率(eFG%):
(投篮命中数 + 0.5 * 三分命中数) / 投篮出手数,这个比单纯命中率更能反映球员的投射效率。 - 真实命中率(TS%):考虑罚球的影响力,公式是
得分 / (2 * (投篮出手数 + 0.44 * 罚球出手数))。 - 使用率(USG%):球员在场时处理的球权比例,能看出谁是球队真核。
- 防守效率跟进攻效率:要结合球队整体数据算。
我用了个结构体把这些指标都包起来:
type AdvancedStats struct {
PlayerID int
EFGPercent float64 // 有效命中率
TSPercent float64 // 真实命中率
UsageRate float64 // 使用率
PER float64 // 球员效率值
OffRating float64 // 进攻效率
DefRating float64 // 防守效率
}
算完这些,你会惊讶地发现,有些得分高的球员,效率其实很差,比如某赛季场均25分的外援,真实命中率可能不到50%,而有些蓝领内线,TS%能到65%以上。

数据可视化接Grafana,实时看统计
数据库统计做完了不能光躺着看SQL查询结果,我用Golang写了个Web服务,把统计接口暴露成了REST API,前端接Grafana或者ECharts展示,Golang的net/http标准库就够用,配上gorilla/mux做路由,不到两百行代码搞定。
这里有个细节——统计周期参数化,你想看某球员最近10场、整个赛季、还是职业生涯的比赛,我通过URL参数?from=2024-10-01&to=2025-02-14来实现,后端就是拼SQL条件,用time包解析日期,验证合法性,然后用构造好的条件去查数据库。
func queryPlayerTrends(playerID int, start, end time.Time) []TrendPoint {
query := `SELECT date, points, rebounds, assists
FROM player_stats ps
JOIN games g ON ps.game_id = g.id
WHERE ps.player_id = $1 AND g.game_date BETWEEN $2 AND $3
ORDER BY g.game_date`
// 执行查询并处理行数据
}
给我印象最深的一次统计
我统计了CBA历史上所有国内球员的单场50+得分次数,然后用Golang写了个排序,把所有球员按这个次数排名,结果发现,胡卫东、孙军、王治郅这几位老前辈真是狠人,尤其是孙军,2000-01赛季对山东那场拿了70分,至今还是国内球员单场最高分纪录,这些数据一列出来,篮球论坛上的讨论帖马上就有素材了。
还有一次,我统计了所有外援在不同赛区的效率差异,对比了同一个外援在NBA和CBA的PER值变化,这里有个有趣的发现——很多在NBA打不上球的边缘球员,来CBA后USG%飙升,但TS%反而下降了,因为球权多了,出手选择变得随便了,这种分析用基础SQL也能做,但要处理跨赛季对比,就得写Golang的循环嵌套去关联多张表。
一些小坑和解决方案
-
中文编码问题,早期CBA数据源用的是GBK编码,Golang默认UTF-8,我加了
golang.org/x/text/encoding/simplifiedchinese这个库来做转码,不然球员姓名全是乱码。 -
球员重名问题,CBA历史上有两个叫“王磊”的球员,一个打后卫,一个打前锋,我处理的时候用
team_id加player_id做联合主键来区分。 -
退役球员数据缺失,有些90年代球员的助攻数据当时没统计,我用
NULL存着,计算的时候要单独处理,不然AVG()函数会把NULL忽略掉,导致数值偏差。 -
时间戳索引很重要。
games表的game_date字段我加了B-tree索引,不然查某个月的所有比赛会全表扫描。
把统计结果导出为CSV
很多教练组要拿数据去做Excel分析,所以我写了个导出接口,用encoding/csv库,把查询结果直接写进HTTP响应流里,用户点一下按钮就能下载CSV文件,注意要在响应头里设置Content-Disposition,不然浏览器会直接把内容渲染成文本。
我也试过生成JSON格式给前端,但是CSV在Excel里打开方便,而且列宽自己调整,教练组的老哥们就爱这口。
换个角度:从数据中发现故事
你可以统计CBA所有球队的主场胜率对比,有个挺有意思的结果——新疆队的主场胜率历史最高,差不多80%,这可能跟红山体育馆的高原优势有关,还有北控队的主场胜率相对偏低,球迷戏称“魔鬼主场”名不虚传,这些结论用简单的SQL聚合就能出来,再用Golang渲染成表格。
我试过用median函数(Golang里面没有内置,得自己写排序)来看各个赛季的罚球命中率中位数,发现从2010年开始,球员的罚球稳定性其实逐年下降,可能跟比赛节奏变快,体能消耗大有关系。
代码写多了,反而更爱看球了
做这堆数据库统计之后,我现在看CBA直播的心态不一样了,以前只看谁得分最多,现在会盯着效率值和真实命中率看,心里默默算着这家伙的使用率是不是太高了,进攻效率值会不会被高防守强度打崩,这就是数据带来的额外乐趣吧。
反正整体下来,Golang在这块就是顺手,打包成一个cba_stats.exe丢到服务器上,定时任务跑起来,每天自动更新数据,偶尔想起新的统计口径,改十几行代码重新编译一下就行,比之前用Python省事多了,写这篇文章的过程中,我又去跑了几个有趣的统计,比如空位三分命中率跟主场噪声的关系,下次有机会再聊。
本文来自作者[kyadmin]投稿,不代表678体育 - 全网热门体育赛事高清直播平台立场,如若转载,请注明出处:http://www.7oclockcapital.com/jk/1892.html
评论列表(4条)
我是678体育 - 全网热门体育赛事高清直播平台的签约作者“kyadmin”!
希望本篇文章《用Golang搞定CBA数据库统计,从零开始的实战笔记》能对你有所帮助!
本站[678体育 - 全网热门体育赛事高清直播平台]内容主要涵盖:678体育,678体育官网,678赛事直播
本文概览:为什么我选了Golang来做CBA数据统计说实话,一开始我没想到会用Golang来搞CBA(中国篮球协会)的数据库统计,之前用Pyt...