R语言如何提取数据框同一因子水平前序观测生成球队赛事状态列
足球赛事状态列实现方案
你的需求核心是:按时间顺序的赛事表中,为每场比赛的主队、客队分别匹配该队上一场的赛果(胜W/平D/负L),写入HomeForm和AwayForm列。以下是R中两种可直接落地的实现方式,解决你提到的“定位特定球队历史观测、提取对应信息”的核心问题。
基础R实现(无额外包依赖)
注:你提供的示例数据中
Result字段长度(15)短于主客队字段长度(30),示例代码会自动兼容长度差,保证可直接运行。
- 先为每条比赛记录拆分主队、客队的单场赛果:
Result = "H"代表主队胜、"A"代表客队胜、"D"代表平局 - 将单场双队的记录拆成逐队的长表,按球队、比赛时间排序
- 按球队分组,将赛果滞后1位,即为当前比赛对应的球队上一场状态
- 将状态值映射回原赛事表的主、客队列
# 补全Result字段长度适配原示例数据 Result <- c("H","H","D","A","H","A","H","D","H","A","A","H","D","A","A", "H","D","A","H","D","A","H","D","H","A","A","H","D","A","L") HomeTeam <- c("Liverpool", "ManCity", "ManUnited", "Tottenham", "Arsenal", "Leicester", "Chelsea", "Leeds", "Liverpool", "ManCity", "ManUnited", "Tottenham", "Arsenal", "Leicester", "Chelsea","Liverpool", "ManCity", "ManUnited", "Tottenham", "Arsenal", "Leicester", "Chelsea", "Leeds", "Liverpool", "ManCity", "ManUnited", "Tottenham", "Arsenal", "Leicester", "Chelsea") AwayTeam <- c("Chelsea", "Tottenham", "Arsenal", "ManUnited", "Leicester", "ManCity", "Leeds", "Chelsea", "Leicester", "Liverpool", "Arsenal", "ManUnited", "Tottenham", "ManCity", "Liverpool","Chelsea", "Tottenham", "Arsenal", "ManUnited", "Leicester", "ManCity", "Leeds", "Chelsea", "Leicester", "Liverpool", "Arsenal", "ManUnited", "Tottenham", "ManCity", "Liverpool") data <- data.frame(HomeTeam, AwayTeam, Result) # 计算主、客队单场赛果 data$home_res <- ifelse(data$Result == "H", "W", ifelse(data$Result == "D", "D", "L")) data$away_res <- ifelse(data$Result == "A", "W", ifelse(data$Result == "D", "D", "L")) # 构造逐队的长格式比赛记录 home_tbl <- data.frame(team = data$HomeTeam, game_idx = seq(nrow(data)), res = data$home_res) away_tbl <- data.frame(team = data$AwayTeam, game_idx = seq(nrow(data)), res = data$away_res) team_long <- rbind(home_tbl, away_tbl) team_long <- team_long[order(team_long$team, team_long$game_idx), ] # 按球队分组,取上一场的赛果(滞后1位) team_long$last_res <- ave( team_long$res, team_long$team, FUN = function(x) c(NA, head(x, -1)) # 首次参赛的球队无历史记录,用NA占位 ) # 将上一场状态映射回原表的主、客队列 data$HomeForm <- mapply( function(t, idx) team_long$last_res[team_long$team == t & team_long$game_idx == idx], data$HomeTeam, seq(nrow(data)) ) data$AwayForm <- mapply( function(t, idx) team_long$last_res[team_long$team == t & team_long$game_idx == idx], data$AwayTeam, seq(nrow(data)) )
- 核心逻辑说明:如果需要手动定位某支球队的历史记录,可直接用子集匹配语法:比如取利物浦的所有比赛记录就是
team_long[team_long$team == "Liverpool", ],取最早的1条历史记录用head(..., 1)即可;逐组滞后的写法比手动逐行匹配的效率高很多,尤其适合大批量赛事数据。
tidyverse实现(逻辑更简洁,适合大表)
用dplyr、tidyr的内置函数实现相同逻辑,代码可读性更强:
library(dplyr) library(tidyr) data |> # 计算主客队单场赛果,给每条比赛标记时间序号 mutate( home_res = case_when(Result == "H" ~ "W", Result == "D" ~ "D", Result == "A" ~ "L"), away_res = case_when(Result == "A" ~ "W", Result == "D" ~ "D", Result == "H" ~ "L"), game_idx = row_number() ) |> # 拆成逐队的长格式记录 pivot_longer( cols = c(HomeTeam, AwayTeam), names_to = "team_type", values_to = "team" ) |> # 匹配每条逐队记录对应的赛果 mutate(res = ifelse(team_type == "HomeTeam", home_res, away_res)) |> # 按球队分组,取上一场的赛果(滞后1位) group_by(team) |> arrange(game_idx, .by_group = T) |> mutate(last_res = lag(res)) |> ungroup() |> # 转回宽表,提取主、客队的上一场状态 pivot_wider( id_cols = game_idx, names_from = team_type, values_from = last_res ) |> # 合并回原表的全部字段 left_join(data, by = "game_idx")
- 扩展说明:如果需要取前2场的状态做累计统计,只需把
lag(res)调整为取前2条的聚合逻辑即可;首次参赛的球队返回NA值,可通过replace_na()替换为"TBD"这类默认标记。
内容的提问来源于stack exchange,提问作者KjetilH
相关产品推荐
相关产品推荐

