Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Way to calculate cumulative product over window #10542

Open
1 task done
PtrBld opened this issue Nov 28, 2024 · 2 comments
Open
1 task done

feat: Way to calculate cumulative product over window #10542

PtrBld opened this issue Nov 28, 2024 · 2 comments
Labels
feature Features or general enhancements

Comments

@PtrBld
Copy link

PtrBld commented Nov 28, 2024

Is your feature request related to a problem?

I am trying to calculate the cumulative product over a window and can not figure out how I would do this in ibis.
In pandas you would have this: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.cumprod.html

What is the motivation behind your request?

No response

Describe the solution you'd like

Similar to the cumsum functionality:
cumulative_col=.col.cumsum().over(ibis.window(order_by="date", group_by=["grouper"]))
I would expect something similar for products:
cumulative_col=
.col.cumprod().over(ibis.window(order_by="date", group_by=["grouper"]))

What version of ibis are you running?

9.5.0

What backend(s) are you using, if any?

DuckDB

Code of Conduct

  • I agree to follow this project's Code of Conduct
@PtrBld PtrBld added the feature Features or general enhancements label Nov 28, 2024
@gforsyth
Copy link
Member

Thanks for raising this @PtrBld !

So it's a bit odd, but most SQL engines don't implement a product function which is why Ibis doesn't have one. DuckDB does have a product function, but generally we don't expose functionality unless it's useful in at least two of our backends. We probably could implement product using sum, exp and the natural log for a few of our backends, but that also seems like a potential footgun if a column has a 0 in it.

Anyway, for a temporary workaround (only for DuckDB) that is a bit awkward, but does work, you can do something like this:

[nav] In [1]: import ibis
         ...: ibis.options.interactive = True
         ...: t = ibis.memtable(
         ...:     {
         ...:         "id": [1, 2, 3, 4, 5, 6],
         ...:         "grouper": ["a", "a", "a", "b", "b", "c"],
         ...:         "values": [3, 2, 1, 2, 3, 2],
         ...:     }
         ...: )

[ins] In [2]: t
Out[2]: 
┏━━━━━━━┳━━━━━━━━━┳━━━━━━━━┓
┃ idgroupervalues ┃
┡━━━━━━━╇━━━━━━━━━╇━━━━━━━━┩
│ int64stringint64  │
├───────┼─────────┼────────┤
│     1a3 │
│     2a2 │
│     3a1 │
│     4b2 │
│     5b3 │
│     6c2 │
└───────┴─────────┴────────┘

[ins] In [3]: import ibis.expr.datatypes as dt

[ins] In [4]: @ibis.udf.agg.builtin
         ...: def product(x) -> dt.float64:
         ...:     ...
         ...: 

[ins] In [5]: t.mutate(cumprod=product(t.values).over(ibis.cumulative_window(order_by
         ...: ="id", group_by="grouper"))).order_by("id")
Out[5]: 
┏━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━┓
┃ idgroupervaluescumprod ┃
┡━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━┩
│ int64stringint64float64 │
├───────┼─────────┼────────┼─────────┤
│     1a33.0 │
│     2a26.0 │
│     3a16.0 │
│     4b22.0 │
│     5b36.0 │
│     6c22.0 │
└───────┴─────────┴────────┴─────────┘

@PtrBld
Copy link
Author

PtrBld commented Nov 30, 2024

Thanks @gforsyth for your quick response! I already knew it was kind of a odd request, but I think there is value in maintaining similar API capabilities to pandas. But I probably agree that it is not really maintainable especially with the range of available backends.

For the moment I have solved the issue in a similar fashion to your suggestion. Works for now...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Features or general enhancements
Projects
Status: backlog
Development

No branches or pull requests

2 participants