DuckDB 与 Pandas/Polars

  • 自之前关于 DuckDB 的帖子后,一直在使用并享受 DuckDB。最近想分析和可视化一些金融 CSV 文件,包括合并几个文件,开始用 Polars 但觉得其语法令人困惑且繁琐。

    • 以解析Transactions.csv并按Category求和为例,Polars 代码如下:
    df = pl.read_csv("Transactions.csv")
    df = (
      df.select("Date", "Category", "Amount")
     .with_columns(
          pl.col("Date").str.to_date("%m/%d/%Y"),
          pl.col("Amount")
         .map_elements(lambda amount: amount.replace("$", ""))
         .str.to_decimal(),
      )
     .filter(pl.col("Date") > datetime.date(2024, 1, 1))
     .group_by("Category")
     .agg(pl.col("Amount").sum())
    )
    
    print(df)
    • 遇到的问题:选择和转换列的语法、解析日期列的方式、写 lambda 去除$(或许有更好方法)、df.pl.调用的混合等。
  • 相比之下,因日常写 SQL,觉得用 DuckDB 更易,可写更熟悉的 SQL 并结合 Python 代码:

    results = duckdb.sql(
      """
      select
          Category,
          sum(replace(Amount, '$', '')::decimal) as Amount
      from read_csv('Transactions.csv')
      where Date > '2024-01-01'
      group by Category
    """
    )
    results.show()

    且可通过 SQL 合并多个 CSV 文件并添加更复杂的WHERE条件:

    results = duckdb.sql(
      """
      select
          c.Group,
          sum(replace(t.Amount, '$', '')::decimal) as Amount
      from read_csv('Transactions.csv') t
      join read_csv('Categories.csv') c on c.Category = t.Category
      where t.Date > '2024-01-01'
      and c.Type in ('Income', 'Expense')
      group by c.Group
    """
    )
    results.show()

    注意 DuckDB 能自动解析日期列。

  • 更新:Reddit 评论展示了去除map_elements的方法:

    pl.col("Amount").str.replace("\\$", "").str.to_decimal()

    但认为双重使用.str对非频繁使用者较复杂。

  • 另一个 Reddit 评论展示了“更短(无中间步骤)且更高效(扫描)的版本”:

    df = (
      pl.scan_csv("Transactions.csv")
     .filter(pl.col("Date").str.to_date("%m/%d/%Y") > datetime.date(2024, 1, 1))
     .group_by("Category")
     .agg(pl.col("Amount").str.replace("\\$", "").str.to_decimal().sum())
     .collect()
    )
    
    print(df)
  • 有关于此帖的讨论,尤其是围绕 Polars/Pandas 增加的组合性与 SQL 对比以及更好写 Polars 代码的方式:

阅读 66
0 条评论