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

如何用Polars原生with_columns方法拆分字段并展开行?

问题:用Polars原生方法实现按规则拆分product字段并保留原字段

现有代码通过遍历DataFrame行的方式,将每行的product字段按规则拆分为多个product_split项,同时保留qty、price等其他字段。现希望使用Polars原生的with_columns类方法实现相同功能,避免行遍历。

原始实现代码:

import polars as pl
import datetime as dt
from dateutil.relativedelta import relativedelta

def get_3_month_splits(product: str) -> list[str]:
    front, start_dt, total_m = product.rsplit('.', 2)
    start_dt = dt.datetime.strptime(start_dt, '%Y%m')
    total_m  = int(total_m)
    return [f'{front}.{(start_dt+relativedelta(months=m)).strftime("%Y%m")}.3' for m in range(0, total_m, 3)]

df = pl.DataFrame({
    'product': ['CHECK.GB.202403.12', 'CHECK.DE.202506.6', 'CASH.US.202509.12'],
    'qty':     [3, 6, -3],
    'price':   [100, 102, 95],
})
print(df)

df2 = pl.DataFrame([{'product_split': split} | d
    for d in df.iter_rows(named=True) for split in get_3_month_splits(d['product'])
])
print(df2)

原生Polars实现方案

可以通过Polars的字符串拆分、日期处理、列表生成和explode方法实现完全原生的处理,无需行遍历或依赖第三方库,性能更优:

分步实现版本(可读性强)

import polars as pl

df = pl.DataFrame({
    'product': ['CHECK.GB.202403.12', 'CHECK.DE.202506.6', 'CASH.US.202509.12'],
    'qty':     [3, 6, -3],
    'price':   [100, 102, 95],
})

df2 = (
    df
    # 拆分product为前缀、起始年月、总月份数
    .with_columns(pl.col("product").str.rsplit(".", 2).alias("parts"))
    .with_columns(
        front=pl.col("parts").list[0],
        start_dt=pl.col("parts").list[1].str.to_date("%Y%m"),
        total_m=pl.col("parts").list[2].cast(pl.Int32)
    )
    # 生成每个3月间隔的product_split列表
    .with_columns(
        product_split=pl.struct("front", "start_dt", "total_m").map_elements(
            lambda x: [
                f"{x['front']}.{(x['start_dt'] + pl.duration(months=m)).strftime('%Y%m')}.3"
                for m in range(0, x['total_m'], 3)
            ],
            return_dtype=pl.List(pl.String)
        )
    )
    # 展开列表为多行,保留所有原字段
    .explode("product_split")
    # 清理临时辅助列
    .drop("parts", "front", "start_dt", "total_m")
)

print(df2)

简洁实现版本(代码更紧凑)

import polars as pl

df = pl.DataFrame({
    'product': ['CHECK.GB.202403.12', 'CHECK.DE.202506.6', 'CASH.US.202509.12'],
    'qty':     [3, 6, -3],
    'price':   [100, 102, 95],
})

df2 = (
    df
    .with_columns(
        product_split=pl.col("product").map_elements(
            lambda p: [
                f"{front}.{(start_dt + pl.duration(months=m)).strftime('%Y%m')}.3"
                for m in range(0, total_m, 3)
                for front, start_dt_str, total_m_str in [p.rsplit(".", 2)]
                for start_dt in [pl.date(year=int(start_dt_str[:4]), month=int(start_dt_str[4:]), day=1)]
                for total_m in [int(total_m_str)]
            ],
            return_dtype=pl.List(pl.String)
        )
    )
    .explode("product_split")
)

print(df2)

方案优势

  • 原生API支持:完全使用Polars内置方法,避免Python层面的行遍历,大数据量下性能提升明显
  • 无第三方依赖:替换dateutil.relativedelta为Polars原生的pl.duration,减少外部依赖
  • 向量化操作:利用Polars的向量化处理能力,比循环遍历效率更高

内容的提问来源于stack exchange,提问作者Phil-ZXX

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 01:00:08