
本文介绍使用 Polars 的 unpivot() 方法,将按月聚合的均值与中位数等多指标宽表快速转换为适合绘图的长格式数据,替代已弃用的 melt(),代码简洁、语义清晰、性能优异。
本文介绍使用 polars 的 `unpivot()` 方法,将按月聚合的均值与中位数等多指标宽表快速转换为适合绘图的长格式数据,替代已弃用的 `melt()`,代码简洁、语义清晰、性能优异。
在数据分析流程中,完成分组聚合(如按月份计算均值、中位数)后,常需将结果从宽格式(wide format)转换为长格式(long format),以便统一绘制多条折线、柱状图或使用 Altair/Plotly 等库进行分组着色可视化。Polars 提供了专为此类场景设计的 .unpivot() 方法——它比已弃用的 .melt() 更直观、更健壮,且在指定索引列时无需显式列出待展开的变量列。
以下是一个端到端示例:假设你已完成 Polars 聚合(注意原问题中误用了 pd.col,应为 pl.col):
import polars as pl
# 正确的 Polars 聚合(修正原始代码中的 pd.col → pl.col)
df = (
data.group_by("month_code")
.agg(
pl.col("value").mean().alias("avg"),
pl.col("value").median().alias("med")
)
.sort("month_code")
)
# 注意:若 data 是 LazyFrame,此处 .collect() 可选;若已为 DataFrame 则直接操作得到宽格式 DataFrame 后,仅需一行即可完成转换:
df_long = df.unpivot(
index="month_code", # 作为标识列(不展开),对应目标中的 'month'
variable_name="type", # 新列名,存储原列名(如 "avg", "med")
value_name="value" # 新列名,存储展开后的数值(默认为 "value",可省略)
)该调用自动将除 month_code 外的所有数值列“堆叠”为两列:type(原列名)和 value(对应值),完美匹配可视化所需的结构。
✅ 优势说明:
-
零冗余声明:无需手动列出
"avg","med"等列名,index参数隐式确定其余列为待展开变量; -
命名灵活:
variable_name和value_name支持自定义列名,与下游绘图库(如 Altair、Plotly 或 Polars 内置.plot())无缝衔接; -
类型安全:输出 DataFrame 自动推断并保持原始数值列的数据类型(如
f64),避免隐式转换风险; -
链式友好:可无缝嵌入 Polars 表达式链,例如:
df.group_by(...).agg(...).sort(...).unpivot(...).collect()。
⚠️ 注意事项:
-
unpivot()是 Polars 0.19.0+ 推荐方法,旧版本若使用.melt()需升级; - 若存在非数值列(如字符串辅助字段),请确保它们未被意外包含在
index中,或提前select()明确所需列; - 对于大规模数据,
unpivot()在惰性模式(LazyFrame)下同样高效,建议在collect()前完成转换以减少内存压力。
完成转换后,即可直接用于可视化(以 Altair 为例):
import altair as alt
chart = (
alt.Chart(df_long)
.mark_line(point=True)
.encode(
x=alt.X("month_code:N", title="Month"),
y=alt.Y("value:Q", title="Value"),
color="type:N",
tooltip=["month_code", "type", "value"]
)
.properties(width=400, height=350, title="Average vs Median by Month")
)
chart.display()综上,df.unpivot(index="month_code", variable_name="type") 是 Polars 中实现聚合结果可视化适配的最简、最规范、最推荐的方式——语义明确、代码极简、性能可靠。

















