R语言按唯一game_id分组计算球员传球累积统计量的实现方法
实现核心逻辑
基于cumsum的特性,只需要先构造符合计数规则的0/1指示变量,再按game_id和player的分组粒度对指示变量做累积求和,就能完全匹配统计规则:
- 对“是否为传球动作”的指示变量做组内累积:因为非传球动作的指示值是0,累积时不会改变之前的统计值,刚好满足“非传球行沿用之前累计结果”的要求
- 对“是否为成功传球”的指示变量做组内累积:非传球、传球失败的行指示值为0,同样不会干扰之前的累计值
- 最后计算成功率时,对累计传球数为0的场景做除以0的防护,统一赋值为0即可。
具体实现代码
基础R版本(完全依赖原生函数,无额外包依赖)
# 构造0/1计数标记 df1$is_pass <- as.integer(df1$type == "pass") df1$is_success_pass <- as.integer(df1$type == "pass" & df1$result == "success") # 按比赛+球员分组,应用cumsum计算累计值 df1$pass_per_player <- ave(df1$is_pass, df1$game_id, df1$player, FUN = cumsum) df1$success_pass_player <- ave(df1$is_success_pass, df1$game_id, df1$player, FUN = cumsum) # 计算传球成功率,保留两位小数和预期输出对齐 df1$success_rate_player <- ifelse( df1$pass_per_player == 0, 0, round(df1$success_pass_player / df1$pass_per_player, 2) ) # 移除临时辅助列,生成最终数据集df2 df2 <- subset(df1, select = -c(is_pass, is_success_pass))
dplyr版本(代码更简洁,适合管道式开发)
library(dplyr) df2 <- df1 %>% # 按比赛、球员分组,分组边界完全匹配统计要求 group_by(game_id, player) %>% mutate( pass_per_player = cumsum(type == "pass"), success_pass_player = cumsum(type == "pass" & result == "success"), success_rate_player = ifelse(pass_per_player == 0, 0, round(success_pass_player / pass_per_player, 2)) ) %>% ungroup()
结果匹配说明
运行上述代码后,输出的df2会完全对齐预期结构:
- 所有非传球动作的行,累计传球数、累计成功传球数完全沿用同组同球员之前的统计值,不会因为动作类型变化产生偏移。比如比赛1中球员Z在第6、7行是运球动作,累计传球数始终保持为0
- 传球成功率的计算值和预期输出的小数精度一致,累计传球数为0的行成功率统一为0,不会出现除以0的报错
- 不同比赛的统计值完全独立,跨比赛的同球员统计值不会发生累积。比如球员X在比赛1结束时累计传球3次,进入比赛2后统计值从0开始计算,和预期逻辑完全一致
内容的提问来源于stack exchange,提问作者WenkyWong
相关产品推荐
相关产品推荐

