R语言补全数据集缺失年份行 统计F1车手各年累计夺冠数
F1车手累计夺冠赛季数补全方案(dplyr实现)
问题场景
- 运行环境:R语言,使用
jsonlite包调用Ergast API采集1950年至今的F1积分榜数据,已完成基础数据清洗 - 现有进展:已完成夺冠车手的初步累计值计算,但目前数据集仅保留了车手夺冠赛季的记录,缺少非夺冠赛季、非夺冠车手的对应行
- 目标需求:转换数据集,保证每个赛季、每位车手都有对应的
cum_seasons_won(累计夺冠赛季数)字段值- 规则示例1:1950年首个赛季,除当年冠军Nino Farina外,其余所有车手的
cum_seasons_won值为0 - 规则示例2:截至数据集最新赛季,Juan Fangio的
cum_seasons_won值应为5(对应其5次总冠军的历史成绩)
- 规则示例1:1950年首个赛季,除当年冠军Nino Farina外,其余所有车手的
- 数据集样例:

- 测试数据复现:可通过如下dput代码加载测试用样本数据
structure(list(full_name = c("Nino Farina", "Juan Fangio", "Alberto Ascari", "Alberto Ascari", "Juan Fangio", "Juan Fangio"), season_year = structure(c(-7305, -6940, -6575, -6209, -5844, -5479), class = "Date"), season_won = c(1, 1, 1, 1, 1, 1), cum_seasons_won = c(1, 1, 1, 2, 2, 3)), class = c("grouped_df", "tbl_df", "tbl", "data.frame"), row.names = c(NA, -6L), groups = structure(list( full_name = c("Alberto Ascari", "Juan Fangio", "Nino Farina" ), .rows = structure(list(3:4, c(2L, 5L, 6L), 1L), ptype = integer(0), class = c("vctrs_list_of", "vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame" ), row.names = c(NA, -3L), .drop = TRUE))
注:因不清楚该类数据转换操作的标准术语,问题表述可能存在不严谨之处
实现代码
优先使用dplyr+tidyr的tidyverse语法实现,逻辑简洁易读:
library(dplyr) library(tidyr) # 假设原始清洗后的数据集命名为f1_raw,包含字段: # full_name: 车手姓名 # season_year: 赛季年份(Date格式) # season_won: 当赛季是否夺冠,1=夺冠,0=未夺冠 f1_processed <- f1_raw %>% # 生成所有赛季、所有车手的全量交叉组合,缺失的未夺冠记录自动补全 complete(season_year, full_name, fill = list(season_won = 0)) %>% # 按车手分组,按赛季升序排序 group_by(full_name) %>% arrange(season_year, .by_group = TRUE) %>% # 逐赛季累计夺冠次数 mutate(cum_seasons_won = cumsum(season_won)) %>% ungroup()
逻辑说明
- 核心是先补全所有「赛季-车手」组合,解决原始数据只有夺冠记录、缺失非夺冠条目导致累计值无法对齐所有行的问题
complete()函数会自动遍历所有出现过的赛季、所有出现过的车手生成全配对,未夺冠的赛季默认将season_won填充为0- 分组排序后用
cumsum()做累计求和:未夺冠赛季累计值和上一赛季持平,夺冠赛季累计值+1,完全匹配需求 - 测试样例验证:样本数据中Juan Fangio共出现3次夺冠记录,运行后其最后一条记录累计值为3,和样本逻辑一致;替换为全量数据后会正确计算到5次的累计值
替代方案(无tidyr依赖)
如果不想加载tidyr,也可以用base R生成全量组合后合并,逻辑完全一致:
# 生成所有赛季+车手的组合 all_combo <- expand.grid( season_year = unique(f1_raw$season_year), full_name = unique(f1_raw$full_name) ) # 合并原始数据 f1_merged <- merge(all_combo, f1_raw, by = c("season_year", "full_name"), all.x = TRUE) f1_merged[is.na(f1_merged$season_won), "season_won"] <- 0 # 排序计算累计值 f1_merged <- f1_merged[order(f1_merged$full_name, f1_merged$season_year), ] f1_merged$cum_seasons_won <- ave(f1_merged$season_won, f1_merged$full_name, FUN = cumsum)
内容的提问来源于stack exchange,提问作者moritz
相关产品推荐
相关产品推荐

