pola-rs / polars

Dataframes powered by a multithreaded, vectorized query engine, written in Rust
https://docs.pola.rs
Other
30.68k stars 1.99k forks source link

Support `round` for Decimal type #15151

Open Julian-J-S opened 8 months ago

Julian-J-S commented 8 months ago

Description

Currently the decimal type does not suport round. Imo this makes sense to implement for many financial calculation where you require the precision of a decimal but in the end need to round to some fixed value.

from decimal import Decimal as D
import polars as pl

pl.DataFrame({"x": [D("0.246")]}).with_columns(r=pl.col("x").round(decimals=2))

# InvalidOperationError: `round` operation not supported for dtype `decimal[*,3]`

Currently I can only truncate the decimal for example with .cast(pl.Decimal(scale=2)) but this ofc does NOT round.

DeflateAwning commented 3 months ago

This seems like an essential behaviour function to have when working with pl.Decimal type. Going to have to use int and keep track of the decimal place myself, I think.

lostmygithubaccount commented 3 months ago

just chiming in that this is still an issue in 1.5.0, though it looks like the error has slightly changed:

[ins] In [3]: customer.limit(5).collect()
Out[3]:
shape: (5, 8)
┌───────────┬────────────────────┬─────────────────────────────┬─────────────┬─────────────────┬───────────────┬──────────────┬────────────────────────────┐
│ c_custkey ┆ c_name             ┆ c_address                   ┆ c_nationkey ┆ c_phone         ┆ c_acctbal     ┆ c_mktsegment ┆ c_comment                  │
│ ---       ┆ ---                ┆ ---                         ┆ ---         ┆ ---             ┆ ---           ┆ ---          ┆ ---                        │
│ i64       ┆ str                ┆ str                         ┆ i32         ┆ str             ┆ decimal[15,2] ┆ str          ┆ str                        │
╞═══════════╪════════════════════╪═════════════════════════════╪═════════════╪═════════════════╪═══════════════╪══════════════╪════════════════════════════╡
│ 1         ┆ Customer#000000001 ┆ j5JsirBM9PsCy0O1m           ┆ 15          ┆ 25-989-741-2988 ┆ 711.56        ┆ BUILDING     ┆ y final requests wake      │
│           ┆                    ┆                             ┆             ┆                 ┆               ┆              ┆ slyly qu…                  │
│ 2         ┆ Customer#000000002 ┆ 487LW1dovn6Q4dMVymKwwLE9OKf ┆ 13          ┆ 23-768-687-3665 ┆ 121.65        ┆ AUTOMOBILE   ┆ y carefully regular foxes. │
│           ┆                    ┆ 3QG                         ┆             ┆                 ┆               ┆              ┆ sly…                       │
│ 3         ┆ Customer#000000003 ┆ fkRGN8nY4pkE                ┆ 1           ┆ 11-719-748-3364 ┆ 7498.12       ┆ AUTOMOBILE   ┆ fully. carefully silent    │
│           ┆                    ┆                             ┆             ┆                 ┆               ┆              ┆ instru…                    │
│ 4         ┆ Customer#000000004 ┆ 4u58h fqkyE                 ┆ 4           ┆ 14-128-190-5944 ┆ 2866.83       ┆ MACHINERY    ┆ sublate. fluffily even     │
│           ┆                    ┆                             ┆             ┆                 ┆               ┆              ┆ instru…                    │
│ 5         ┆ Customer#000000005 ┆ hwBtxkoBF qSW4KrIk5U        ┆ 3           ┆ 13-750-942-6364 ┆ 794.47        ┆ HOUSEHOLD    ┆ equests haggle furiously   │
│           ┆                    ┆ 2B1AU7H                     ┆             ┆                 ┆               ┆              ┆ again…                     │
└───────────┴────────────────────┴─────────────────────────────┴─────────────┴─────────────────┴───────────────┴──────────────┴────────────────────────────┘

[ins] In [4]: customer.select("c_acctbal").collect()["c_acctbal"].dtype
Out[4]: Decimal(precision=15, scale=2)

[ins] In [5]: customer.select("c_acctbal").collect()["c_acctbal"].dtype.is_numeric()
Out[5]: True

[ins] In [6]: customer.select(pl.col("c_acctbal").round(1)).limit(5).collect()
---------------------------------------------------------------------------
InvalidOperationError                     Traceback (most recent call last)
Cell In[6], line 1
----> 1 customer.select(pl.col("c_acctbal").round(1)).limit(5).collect()

File ~/repos/ibis-bench/.venv/lib/python3.11/site-packages/polars/lazyframe/frame.py:2027, in LazyFrame.collect(self, type_coercion, predicate_pushdown, projection_pushdown, simplify_expression, slice_pushdown, comm_subplan_elim, comm_subexpr_elim, cluster_with_columns, no_optimization, streaming, engine, background, _eager, **_kwargs)
   2025 # Only for testing purposes
   2026 callback = _kwargs.get("post_opt_callback", callback)
-> 2027 return wrap_df(ldf.collect(callback))

InvalidOperationError: round can only be used on numeric types