R语言:为数据框添加条件赋值列时mutate+case_when报错排查
问题描述
现有三个R语言数据框:
completed_games:存储已完成、且至少涉及1支FBS队的大学橄榄球比赛数据VoA_Variables:存储各队统计数据、评分及排名FCS:存储FCS大学橄榄球队评分
需求是筛选出涉及Air Force队的比赛数据生成AirForce数据框,并添加两列:
home_VoA_rating:主队为FBS队时从VoA_Variables取对应VoA_Rating;为FCS队时从FCS取对应ratingaway_VoA_rating:客队按相同规则取值
当前执行mutate中的case_when时报错:
Error in
mutate():
! Problem while computinghome_VoA_rating = case_when(...).
Caused by error incase_when():
!TRUE ~ FCS$rating[FCS$team == home_team]must be length 10 or one, not 0.
将case_when替换为直接赋值0时代码可正常运行,需解决该条件赋值报错并实现目标列的正确添加。原代码如下:
AirForce <- completed_games |> filter(home_team == "Air Force" | away_team == "Air Force") |> mutate(home_VoA_rating = case_when(home_team %in% VoA_Variables$team ~ VoA_Variables$VoA_Rating[VoA_Variables$team == home_team], TRUE ~ FCS$rating[FCS$team == home_team]), away_VoA_rating = case_when(away_team %in% VoA_Variables$team ~ VoA_Variables$VoA_Rating[VoA_Variables$team == away_team], TRUE ~ FCS$rating[FCS$team == away_team]), actual_diff = case_when(home_team == 'Air Force' ~ home_points - away_points, TRUE ~ away_points - home_points), projected_diff = case_when(home_team == 'Air Force' ~ home_VoA_rating - away_VoA_rating, TRUE ~ away_VoA_rating - home_VoA_rating), Resume_Score = projected_diff - actual_diff)
报错原因
当某个球队既不在VoA_Variables也不在FCS中时,FCS$rating[FCS$team == home_team]会返回长度为0的向量,而case_when要求每个分支返回的向量长度必须与数据框行数一致(此处为10行)或长度为1,因此触发报错。
解决方案
推荐用左连接替代直接向量索引,这更符合dplyr的操作逻辑,也能避免索引匹配失败的问题,具体代码如下:
# 生成统一的球队评分表,合并FBS和FCS的评分数据 team_ratings <- bind_rows( VoA_Variables |> select(team, VoA_Rating) |> rename(rating = VoA_Rating), FCS |> select(team, rating) ) # 筛选比赛数据并匹配评分 AirForce <- completed_games |> filter(home_team == "Air Force" | away_team == "Air Force") |> # 匹配主队评分 left_join(team_ratings, by = c("home_team" = "team")) |> rename(home_VoA_rating = rating) |> # 匹配客队评分 left_join(team_ratings, by = c("away_team" = "team")) |> rename(away_VoA_rating = rating) |> # 计算后续差值列 mutate( actual_diff = if_else(home_team == 'Air Force', home_points - away_points, away_points - home_points), projected_diff = if_else(home_team == 'Air Force', home_VoA_rating - away_VoA_rating, away_VoA_rating - home_VoA_rating), Resume_Score = projected_diff - actual_diff )
方案说明
- 用
bind_rows合并两个评分表,确保所有FBS和FCS球队的评分都在同一表中 left_join会自动按球队名称匹配评分,找不到匹配时返回NA,彻底避免空向量问题- 用
if_else替代双分支的case_when,逻辑更简洁高效
备选方案(保留case_when写法)
如果必须使用case_when,可添加分支处理球队不在两个表中的情况,确保返回长度合法的向量:
AirForce <- completed_games |> filter(home_team == "Air Force" | away_team == "Air Force") |> mutate( home_VoA_rating = case_when( home_team %in% VoA_Variables$team ~ VoA_Variables$VoA_Rating[VoA_Variables$team == home_team], home_team %in% FCS$team ~ FCS$rating[FCS$team == home_team], TRUE ~ NA_real_ # 处理既不在FBS也不在FCS的球队 ), away_VoA_rating = case_when( away_team %in% VoA_Variables$team ~ VoA_Variables$VoA_Rating[VoA_Variables$team == away_team], away_team %in% FCS$team ~ FCS$rating[FCS$team == away_team], TRUE ~ NA_real_ ), actual_diff = case_when(home_team == 'Air Force' ~ home_points - away_points, TRUE ~ away_points - home_points), projected_diff = case_when(home_team == 'Air Force' ~ home_VoA_rating - away_VoA_rating, TRUE ~ away_VoA_rating - home_VoA_rating), Resume_Score = projected_diff - actual_diff )
内容的提问来源于stack exchange,提问作者gshelor
相关产品推荐
相关产品推荐

