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

如何对含双因子的ggplot2 geom_col图X轴进行分组排序

问题描述

我已尝试过本站同类问题的解决方法,但始终未能解决该问题。
当前绘图效果
我使用Kaggle平台的泰坦尼克数据集,期望实现的效果为:在每个Pclass因子分组内,代表age.class的柱状条按照计数n从低到高排序。
原实现代码如下:

library(tidyverse)
library(titanic)


df <- titanic::titanic_train

head(df)

# Start -------------------------------------------------------------------
df = df %>% 
  mutate(has.cabin = if_else(Cabin == '', 0, 1) %>% as.factor(),
         Pclass = Pclass %>% as.factor(),
         age.class = case_when(
           Age < 5  ~ 'baby',
           Age >5 & Age < 12 ~ 'Child',
           Age > 12 & Age < 18 ~ 'Teen', 
           Age > 18 & Age < 25 ~ 'Young Adult',
           Age > 25 & Age <35 ~ 'Mid Adult', 
           Age > 35 & Age < 60 ~  'Adult', 
           Age > 60 ~ 'Elderly',
           TRUE ~ 'Undefined'
                              )
         )

plot.data = df %>% count(has.cabin, Pclass, age.class) 
  

lvls <- unique(plot.data$Pclass[order(plot.data$age.class,-plot.data$n)])
plot.data$age.classv2 = factor(plot.data$age.class, levels=lvls)

plot.data %>% 
  ggplot(., aes(x = Pclass, y = n, fill = age.class)) + 
  geom_col(position = 'dodge') + 
  facet_grid(~ has.cabin)
问题原因

原代码的因子设置逻辑存在两个核心错误:

  • 生成水平向量时取错了变量:lvls提取的是Pclass列的排序结果,Pclass仅包含3个等级,完全无法匹配age.class的7个分类,后续创建的age.classv2变量因子水平不匹配,绘图时根本不会生效。
  • 普通全局因子水平无法实现分组内独立排序:R的因子水平是全局统一的,同一个分类值只能对应一个固定顺序,直接设置全局因子没法做到不同Pclass分组下age.class的排序随组内n值变化。
解决方案

使用tidytext包提供的组内重排函数可以快速实现需求,不需要手动拼接处理因子:

library(tidyverse)
library(titanic)
# 未安装tidytext可先运行下一行
# install.packages("tidytext")
library(tidytext)

df <- titanic::titanic_train

# 基础数据预处理逻辑保持不变
df = df %>% 
  mutate(has.cabin = if_else(Cabin == '', 0, 1) %>% as.factor(),
         Pclass = Pclass %>% as.factor(),
         age.class = case_when(
           Age < 5  ~ 'baby',
           Age >5 & Age < 12 ~ 'Child',
           Age > 12 & Age < 18 ~ 'Teen', 
           Age > 18 & Age < 25 ~ 'Young Adult',
           Age > 25 & Age <35 ~ 'Mid Adult', 
           Age > 35 & Age < 60 ~  'Adult', 
           Age > 60 ~ 'Elderly',
           TRUE ~ 'Undefined'
         )
  )

plot.data = df %>% 
  count(has.cabin, Pclass, age.class) %>%
  # 核心步骤:按has.cabin、Pclass分组,组内按n值从小到大重排age.class顺序
  mutate(age.class_ordered = reorder_within(age.class, n, list(has.cabin, Pclass)))

plot.data %>% 
  ggplot(aes(x = Pclass, y = n, fill = age.class_ordered)) + 
  geom_col(position = 'dodge') + 
  # 调整图例显示,去掉自动拼接的分组后缀,展示原始age.class名称
  scale_fill_reordered("age.class", labels = ~gsub("___.*", "", .)) +
  facet_grid(~ has.cabin)

如果不想额外安装tidytext包,也可以手动实现相同逻辑:计数后按has.cabin、Pclass、n排序,给每个「分组+age.class」组合生成唯一标识后设置为因子,绘图时同样调整刻度标签去掉分组后缀即可,核心逻辑和上述函数完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 23:18:20