R新手求助:如何重构数据框以使用ggplot绘制分类条形图
解决ggplot分组条形图的数据格式问题
嘿,我来帮你搞定这个问题!你遇到的核心问题是ggplot只认「长格式(tidy data)」的数据,但你现在创建的是宽格式的数据框——列是日期,行是不同的分组类别,这完全不符合ggplot「每一行对应一个观测值」的要求。下面分两步帮你重构数据并画出想要的分组条形图:
第一步:把现有宽格式数据转成ggplot需要的长格式
首先我们需要把你已经计算好的df_conversionrates转成长格式,这里用tidyr包的pivot_longer函数(属于tidyverse家族,和你已经加载的dplyr、ggplot2完美兼容):
# 先加载tidyr包(如果还没装的话先运行install.packages("tidyr")) library(tidyr) # 1. 把行名转换为正式列,再将宽格式转成长格式 df_tidy <- df_conversionrates %>% rownames_to_column(var = "category") %>% # 把行名(分组类别)变成单独一列 pivot_longer( cols = -category, # 除了category列,其他列都要转成观测行 names_to = "day", # 原来的列名(日期)存到day列 values_to = "conversion_rate" # 原来的转化率数值存到conversion_rate列 ) # 2. 给类别改个更友好的名字(可选,但图上显示会更清晰) df_tidy <- df_tidy %>% mutate(category = case_when( category == "conversionrate_control" ~ "Control Group", category == "conversionrate_treatment" ~ "Treatment Group" ))
转完之后,你的数据结构会变成这样(每一行是一个「日期+类别」的独立观测):
| category | day | conversion_rate |
|---|---|---|
| Control Group | Monday | xxx |
| Control Group | Tuesday | xxx |
| Treatment Group | Monday | xxx |
| ... | ... | ... |
第二步:用ggplot绘制分组条形图
现在数据格式符合要求了,直接调用ggplot就能画出你想要的「每个日期对应两个条形」的图:
ggplot(df_tidy, aes(x = day, y = conversion_rate, fill = category)) + geom_bar(stat = "identity", position = position_dodge(width = 0.8)) + # position_dodge让同日期的两个条形并排 labs( title = "Daily Conversion Rates: Control vs Treatment", x = "Day of Week", y = "Conversion Rate (%)", fill = "Group" ) + theme_minimal() + theme(axis.text.x = element_text(angle = 45, hjust = 1)) # 日期标签倾斜,避免重叠
额外优化:跳过宽格式,直接生成tidy数据
其实你完全可以跳过先创建宽格式数据框的步骤,直接用dplyr分组计算并生成符合要求的长格式数据,这样代码更简洁高效:
df_tidy <- rocketfuel %>% # 按星期几和测试组分组 group_by(mode_impr_day, test) %>% # 计算转化率 summarise( converted = sum(converted == 1), total = n(), conversion_rate = (converted / total) * 100, .groups = "drop" # 取消分组状态 ) %>% # 把数字编码的星期几和测试组转换成友好名称 mutate( day = case_when( mode_impr_day == 1 ~ "Monday", mode_impr_day == 2 ~ "Tuesday", mode_impr_day == 3 ~ "Wednesday", mode_impr_day == 4 ~ "Thursday", mode_impr_day == 5 ~ "Friday", mode_impr_day == 6 ~ "Saturday", mode_impr_day == 7 ~ "Sunday" ), category = case_when( test == 0 ~ "Control Group", test == 1 ~ "Treatment Group" ) ) %>% # 只保留我们需要的列 select(day, category, conversion_rate)
这样你直接用这个df_tidy去绘图就可以了,省去了中间转换的步骤~
内容的提问来源于stack exchange,提问作者Max Fisher
相关产品推荐
相关产品推荐

