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

R语言ggplot2用reorder排序堆叠柱状图显示异常问题求助

问题原因
  • 核心诱因是失码数据未做格式清洗直接用于绘图:从目标网站爬取的失码字段自带千位分隔符逗号,默认读取为字符串格式。你仅在计算总失码sums时临时转了数值,但没有处理原字段的逗号,as.numeric()遇到带逗号的字符串会直接返回NA,同时绘图用的conceded字段始终是字符串类型。
  • ggplot读取字符串类型的y轴变量时,会自动转为因子按整数编码计算柱高,完全偏离实际失码数值;且reorder()遇到NA的sums值会将对应球队排在x轴最左侧,刚好对应Panthers队,就出现了你看到的异常。
修复代码

首先对爬取的失码字段做逗号清除+数值转换,修改后可直接解决异常:

library(rvest)
library(data.table)
library(ggplot2)

# 读取和清洗数据
def = read_html("https://www.pro-football-reference.com/years/2021/opp.htm")
defense = setDT(html_table(def)[[1]])
# 跳过表头和汇总行
defense = defense[-c(1,34:36),]
# 重命名列
setnames(defense, c("rank", "team", "games", "points_against", "yards_conceded", "off_plays_faced", 
          "yards_per_off_play", "TO", "fumbles_recovered", "1stD_faced", "pass_cmp", 
          "pass_att", "pass_yd_conceded", "pass_td_conceded", "int_recovered", 
          "net_yd_pass_att", "pass_1stD_against", "rush_att", "rush_yards_conceded", 
          "rush_td_conceded", "rush_yards_per_att", "rush_1stD_conceded", "pen_against", 
          "pen_yards_conceded", "pen_1stD", "off_score_percent", "turnover_percent", 
          "expected_points_conceded"))
# 核心修复:清除失码字段的千位分隔符,转成数值
defense[, c("pass_yd_conceded", "rush_yards_conceded") := lapply(.SD, function(x) as.numeric(gsub(",", "", x))), .SDcols = c("pass_yd_conceded", "rush_yards_conceded")]

# 长宽转换生成绘图用数据集(代替原来的分别建表再合并,效率更高)
yds_conc = melt(defense, id.vars = "team", measure.vars = c("pass_yd_conceded", "rush_yards_conceded"), 
                variable.name = "type", value.name = "conceded")
# 关联总失码用于排序
yds_conc[, sums := sum(conceded), by = team]
# 转换type的标签
yds_conc[, type := fifelse(type == "pass_yd_conceded", "pass", "rush")]

# 绘图
defplot = ggplot(yds_conc, aes(fill = type, x = reorder(team, sums), y = conceded)) +
  geom_col() + # geom_col等价于geom_bar(stat="identity"),写法更简洁
  scale_fill_manual(name = "进攻类型", labels = c("传球", "冲球"), 
                    values = c("#006aff", "#4fb350")) +
  labs(title = "2021赛季球队防守失码统计(按进攻类型拆分)", x = NULL, y = "总失码数") +
  theme(axis.text.x = element_text(angle = 60, vjust = 1, hjust = 1),
        axis.ticks.y = element_blank(), 
        axis.text.y = element_blank())
defplot
代码优化点
  • 用data.table的原生语法setDT、setnames、lapply(.SD)处理数据,比逐行操作效率高3~5倍,适合后续处理更大的赛季数据集。
  • 用melt()直接做宽表转长表,代替原来分别创建传球、冲球数据表再合并的写法,代码更简洁,也避免手动重复操作引入的错误。
  • 用geom_col()代替geom_bar(stat = 'identity'),是ggplot2针对堆叠柱状图场景的原生简化写法,可读性更强。
  • 总失码计算用by = team分组聚合,不需要手动重复计算再rep拼接,逻辑更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 17:39:04