You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于R优化NHL API数据爬取的技术求助

NHL API 进球数据提取优化方案

背景

我是R语言新手,对NHL API完全陌生,使用nhlapi包提取所有进球记录时,代码可运行但效率极低:遍历34370场游戏耗时约11小时,处理嵌套的球员列表耗时约2小时,急需优化建议。

以下是精简后的原始代码:

require("nhlapi")
require("data.table")
require("tidyverse")
require("hms")

assign("last.warning", NULL, envir = baseenv())

# 示例游戏ID列表,全量为34370个
cSelGames <- c(2021020001, 2021020002, 2021020003, 2021020004)
liNumGames <- length(cSelGames)
print(liNumGames)

# 遍历拉取游戏数据
Sys.time()
dtGoals <- data.table()
for (liGameNum in 1:liNumGames) {
  lblob_feed <- nhl_games_feed(gameId = cSelGames[liGameNum])
  ldtFeed <- as.data.table(c(lblob_feed[[1]]$gamePk, lblob_feed[[1]]$liveData$plays$allPlays))
  setnames(ldtFeed, 1, "gamePk")
  
  if ('result.eventCode' %in% colnames(ldtFeed)) {
    if (!('team.triCode' %in% colnames(ldtFeed))) {ldtFeed[, ':=' (team.triCode = NA)]}
    if (!('result.strength.code' %in% colnames(ldtFeed))) {ldtFeed[, ':=' (result.strength.code = NA)]}
    if (!('result.emptyNet' %in% colnames(ldtFeed))) {ldtFeed[, ':=' (result.emptyNet = NA)]}
    
    ldtGoals_new <- ldtFeed[(result.eventTypeId == 'GOAL')
                    ,list(gamePk, result.eventCode, players, result.description
                          , team.triCode, about.period, about.periodTime
                          , about.goals.away, about.goals.home, result.strength.code, result.emptyNet)]
    dtGoals <- rbindlist(list(dtGoals, ldtGoals_new), use.names=TRUE, fill=TRUE)
  }
}
Sys.time()

# 处理嵌套的players字段
dtGoal_player <- data.table()
for (i in 1:dtGoals[,.N]) {
  s_result.eventCode <- dtGoals[i,result.eventCode]
  dtGoal_player_new <- as.data.table(dtGoals[i,players[[1]]])
  dtGoal_player_new[, ':=' (result.eventCode=s_result.eventCode)]
  dtGoal_player <- rbindlist(list(dtGoal_player, dtGoal_player_new), use.names=TRUE, fill=TRUE)
}

dtGoals[, players:=NULL]
dtGoal_player[, lag.playerType:=c('nomatch', playerType[-.N]), by=result.eventCode]
dtGoal_player[, playerType2:=ifelse((playerType==lag.playerType),'Assist2',playerType)]
dtGoal_player_t <- dcast.data.table(dtGoal_player, result.eventCode ~ playerType2
                                    , value.var='player.id', fun.aggregate=max)

# 合并数据
dtGoals <- merge(dtGoals, dtGoal_player_t, by="result.eventCode")
Sys.time()

问题解答

1. 能否通过NHL API直接提取指定列/行数据?

NHL公开API本身不支持请求时筛选特定字段或行,必须全量拉取feed后本地处理,但可以通过以下方式减少拉取成本:

  • 批量请求游戏数据:nhl_games_feed支持传入多个gameId(比如一次传50个),将HTTP请求次数从3万+降至几百次,大幅减少网络耗时。
  • 选择必要的feed类型:若不需要实时数据,可尝试指定feedType="boxscore"(仅拉取赛事统计摘要),但如果需要完整进球事件,仍需拉取live类型feed。

2. 嵌套players字段转data.table的高效方法

完全不需要循环处理,用data.table原生操作可将2小时的处理时间压缩到几分钟内:

# 直接展开嵌套的players列表,自动关联result.eventCode
dtGoal_player <- dtGoals[, rbindlist(players, idcol = FALSE), by = result.eventCode]

# 处理重复的Assist类型,用分组内的行号生成Assist1/Assist2
dtGoal_player[, playerType2 := fifelse(
  playerType == "Assist", 
  paste0("Assist", rowid(result.eventCode, playerType)), 
  playerType
), by = result.eventCode]

# 转宽表
dtGoal_player_t <- dcast.data.table(
  dtGoal_player, 
  result.eventCode ~ playerType2, 
  value.var = "player.id", 
  fun.aggregate = max
)

核心逻辑是用rbindlist直接批量展开嵌套列表,用rowid替代循环生成的lag判断,避免逐行操作的性能损耗。

3. 构建全面NHL赛事事件数据库的建议

  • 本地缓存原始数据:用qs包(高效存储R对象)或SQLite缓存拉取的游戏feed,避免重复请求API,测试时可直接读取本地数据。
  • 并行请求优化:用furrr包实现并行拉取,将游戏ID分成多个批次,每个批次用并行任务处理,进一步减少网络等待时间:
    library(furrr)
    plan(multisession, workers = 4) # 根据CPU核心数调整
    game_batches <- split(cSelGames, ceiling(seq_along(cSelGames)/50)) # 每50个游戏为一批
    all_feeds <- future_map(game_batches, nhl_games_feed)
    
  • 增量更新机制:维护一个已处理游戏ID的列表(存在本地文件或数据库),每次仅拉取新增的赛季/未处理的游戏,无需全量重新拉取。
  • 数据类型优化:将字符型字段(如team.triCode)转为因子,时间字段(如about.periodTime)转为hms类型,减少内存占用并提升后续查询速度。
  • 错误处理:用purrr::possibly包裹nhl_games_feed,添加重试机制,避免单个请求失败导致整个程序中断:
    safe_nhl_feed <- possibly(nhl_games_feed, otherwise = NULL)
    lblob_feed <- safe_nhl_feed(gameId = cSelGames[liGameNum])
    
  • 数据库存储:将最终结构化数据存入SQLite或PostgreSQL,方便后续查询、筛选和分析,比纯R对象更稳定且支持多工具访问。

内容的提问来源于stack exchange,提问作者rks13

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 17:15:54