Siuba – A Dplyr Port to Python
github.com
github.com
However many things are possible with vanilla pandas. I use it a lot for data munging, usually with the fluent interface (method chaining) style [1], e.g.:
df.loc[lambda f: ...].groupby(...).agg(["mean", "count"])
It also plays nicely with the black autoformatter.
Anonymous functions are verbose and limited in Python, but you can still do many things and use a regular function when a lambda won't do.
I guess one of the thing I need the most when doing data analysis is column name autocompletion, inside groupby, lambdas, for column selection...
I wonder if one could do it in IPython, similar to the string autocompletion of file/directory paths. Basically a parsing of dataframe column names in order to autocomplete strings.
[0]: https://fastcore.fast.ai/basics.html#Self-(with-an-uppercase...
One motivation for developing siuba is that the grouped agg you show requires users specify only one operation on one column.
E.g.
1. Calculate mean of x
However, common operations like demeaning a column are multiple operations:
1. Calculate mean of x
2. Subtract result of (1) from x
In siuba you can just write mutate(res = _.x -_.x.mean()). This isn't possible from something like gdf.x.agg("mean"), and from what I can tell deeply confusing to analysts :/.
In vanilla pandas I really like to use the chaining method you laid out, and siuba to me is mostly a utility library for making the approach a little more succinct / performant[1].
siuba has experimental autocompletion (thanks to Tim Mastny!), and there's a pretty hefty technical write up on how it uses IPython machinery for that in siuba's architectural desicion record folder[2].
[1]: https://siuba.readthedocs.io/en/latest/developer/pandas-grou...
[2]: https://github.com/machow/siuba/blob/master/examples/archite...
I know that isn't how dplyr works, but it feels more Pythonic, and this solution isn't entirely analogous to dplyr anyway.
This approach seems a little complicated, though I'm sure with some use I could learn to enjoy it.
Right now, a compromise I've been exploring is just attaching siuba's DF functions to a pandas DataFrame, e.g. df.siu_mutate(...). This seems to be what pandas wants people to do [1]! One obstacle here is that the DataFrame has 300+ methods, which can be overwhelming to learners.
I've spent a lot of time wondering whether the piping syntax feels like too much vs chaining. It's still an open question in my mind, so it's really helpful to hear what feels most natural!
https://pandas.pydata.org/pandas-docs/stable/development/ext...
Edit: oh that's pretty much what the linked decorators do.
I think I agree. Pandas has a lot of overhead/baggage that I don't want 90% of the time. Being able to chain _simple_ verbs on a data frame would be great -- something like mtcars.groupby(cyl).summarize(avg_hp = hp.mean())
from siuba import _
from siuba.data import mtcars
# mtcars is a pandas DataFrame
mtcars \
.groupby("cyl") \
.siu_summarize(avg_hp=_.hp.mean())One piece of context I try to bring into discussions is that the way I test and develop siuba is by livecoding data analyses for an hour [1]. I encounter a lot of arguments like "X is possible with pandas", but when I sit down with analysts in realistic settings (e.g. time constrained) it turns out X works in more limited ways then they thought [2][3].
I'm a big fan of pandas though. It's what siuba is built on!
[1]: https://m.youtube.com/c/chowthedog
[2]: https://mchow.com/posts/2020-02-11-dplyr-in-python/
[3]: https://siuba.readthedocs.io/en/latest/developer/pandas-grou...
Since siuba functions just run on pandas DataFrames, you can always hand tune for performance, but imo most of the time pandas code runs slow it's because of something like .agg(lambda ...) somewhere.
There's an example with timings here:
https://siuba.readthedocs.io/en/latest/developer/pandas-grou...
Python however has static analysis tools that are unavailable in R. I wonder if there is a data manipulation library in python that takes advantage of this. Looking at this library, it doesn't appear to use type hints. Other libraries, like pandas, have some basic support for typings but they are still far from being fully typed.
For example, siuba allows users to create custom functions using a thin wrapper around functools.singledispatch.
When deciding how to run...
df >> filter(my_custom_func(_.x))
It requires that the return type be compatible with the backend being run (e.g. pandas, a SQL dialect).Would be super interesting to try and lay out what would be needed to do static analysis via mypy. I think it'd require some plugins for singledispatch at least, probably some reworking things in ways myoy expects.
https://nbviewer.jupyter.org/github/machow/siuba/blob/master...
Everyone thinks this is a good idea until they discover that SQL is not actually very portable, and any attempt to make it so neutralizes whatever benefits your SQL DB has.
E.g. if you have a Postgres db, that has tons of excellent features that you actually want to use, sticking to a lowest-common-denominator flavor of SQL basically nukes all that.
In general, this actually looks like the best dplyr port I've seen, and may actually get me to do some exploratory analysis in Python.
Thanks for bringing this up--the docs could be clearer here
I know pipes split opinion; I'm definitely in the 'pro' camp. Chaining ops in a dataflow pipeline fits my mental model well.
I use method chaining as the composing notation.
The architecture necessary to pull off executing either pandas or SQL also makes it very extensible (e.g. to spark or dask in the future :).