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

在R中按组补全缺失的游戏参与数据

补全球员缺失的游戏记录(tidyverse实现)

现有数据

球员数据(p)

player game_id points
  <chr>    <int>  <int>
1 Bob          1      3
2 Bob          2     18
3 Bob          3     10
4 Andy         1     20
5 Andy         2      5
6 George       1      4
7 George       2     13
8 George       3      6
9 George       4      2

游戏数据(g)

game_id location
    <int> <chr>   
1       1 H       
2       2 A       
3       3 A       
4       4 H 

问题说明

我需要补全每个球员未参与的游戏记录,原本以为用full_join能实现,但直接对整个数据集使用时,并不会为每个球员补全缺失的game_id;只有单独对某个球员过滤后再做full_join才生效:

# 全量join无法补全每个球员的缺失记录
full_join(p, g, by = 'game_id')

  player game_id points location
  <chr>    <int>  <int> <chr>   
1 Bob          1      4 H       
2 Bob          2     10 A       
3 Bob          3     12 A       
4 Andy         1      7 H       
5 Andy         2     20 A       
6 George       1      2 H       
7 George       2     11 A       
8 George       3     17 A       
9 George       4      1 H  

# 单个球员过滤后join可补全缺失记录
full_join(p |> filter(player == 'Bob'), g, by = 'game_id')

  player game_id points location
  <chr>    <int>  <int> <chr>   
1 Bob          1      4 H       
2 Bob          2     10 A       
3 Bob          3     12 A       
4 NA           4     NA H 

希望用tidyverse实现如下理想结果(注:示例中points数值仅为示意,核心是每个球员对应所有game_id记录,未参与的游戏对应的points留空):

player game_id points
   <chr>    <int>  <int>
 1 Bob          1     17
 2 Bob          2      1
 3 Bob          3     16
 4 Bob          4     NA
 5 Andy         1     12
 6 Andy         2      4
 7 Andy         3     NA
 8 Andy         4     NA
 9 George       1      9
10 George       2      8
11 George       3     14
12 George       4     18

另外,考虑到数据量较大时full_join效率不高,想知道是否可以按球员分组执行join,或者有更高效的实现方式?

解决方案

方法1:分组后执行full_join

按player分组,对每组单独和游戏数据做full_join,再合并结果。逻辑直观,但数据量极大时性能一般:

library(tidyverse)

p |>
  group_by(player) |>
  group_modify(~ full_join(.x, g, by = "game_id")) |>
  ungroup()

方法2:expand生成全组合 + left_join(更高效)

先生成所有球员和游戏ID的全组合,再和原始球员数据做left_join,避免分组循环,效率更高:

p |>
  expand(player, game_id = g$game_id) |>
  left_join(p, by = c("player", "game_id")) |>
  left_join(g, by = "game_id")

核心是expand()函数,它会创建player和所有game_id的笛卡尔积,确保每个球员对应所有游戏;再通过left_join关联原始数据,缺失的points自动显示为NA,同时保留location信息。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:15:02