Live data from Hacker News

Modern Pandas (Part 2): Method Chaining

tomaugspurger.github.io

41–50 of 72 posts

Re: Modern Pandas (Part 2): Method Chaining

#41

Earlier quoted context omitted.

My python is rusty but IIRC it allows functional stuff (except for expression-only lambdas, boo). From https://docs.python.org/3/howto/functional.html it's got map/filter/currying and plenty more, what's misting in your view?

pattern matching expressions, syntax for partial application and composition, a typing system which can express structural types, a generalised list comprehension

> pattern matching expressions

Available in 3.10: https://peps.python.org/pep-0636/

> syntax for partial application...

    from functools import partial

    somefunc_arg1_arg2 = partial(somefunc, arg1, arg2)
> ...and composition

A native compositional syntax would be nice.

> a typing system which can express structural types

    # mypy will typecheck this code and see `MyString()` has a `.read()` method, so it's a `Readable` even though it doesn't sub-class `Readable`

    from typing import Any, Protocol

    class Readable(Protocol):
        def read(self) -> Any: ...

    def read_something(something: Readable) -> Any:
        return something.read()

    class MyString:
        a_string: str = "something"
        def read(self) -> str:
            return self.a_string

    read_something(MyString())
> a generalised list comprehension

I agree this would be nice.

Re: Modern Pandas (Part 2): Method Chaining

#43
I don't see how this

( df.pipe(went_up, 'hill')

    .pipe(fetch, 'water')

    .pipe(fell_down, 'jack')

    .pipe(broke, 'crown')

    .pipe(tumble_after, 'jill')
)

is much better then something like that

df = went_up(df, 'hill')

df = fetch(df, 'water')

df = fell_down(df, 'jack')

df = broke(df, 'jack')

df = tumble_after(df, 'jill')

Would really like to hear an opinion about that.

Re: Modern Pandas (Part 2): Method Chaining

#44

I don't see how this ( df.pipe(went_up, 'hill') .pipe(fetch, 'water') .pipe(fell_down, 'jack') .pipe(broke, 'crown') .pipe(tumble_after, 'jill') ) is much better then something like that df = went_up(df, 'hill') df = fetch(df, 'water') df = fell_down(df, 'jack') df = broke(df, 'jack') df = tumble_after(df, 'jill') Would really like to hear an opinion about that.

A former coworker of mine was a huge fan of functional programming, and also deeply allergic to mutation. So if you reused variables like that you’d get an angry earful.

Though if you replaced each subsequent line with df1 and df2 and so on he wouldn’t mind as much.

I can’t opine as to whether one approach or the other is intrinsically better. But echoes of his tirades still ring when I see the same variable name redefined.

Re: Modern Pandas (Part 2): Method Chaining

#45

I don't see how this ( df.pipe(went_up, 'hill') .pipe(fetch, 'water') .pipe(fell_down, 'jack') .pipe(broke, 'crown') .pipe(tumble_after, 'jill') ) is much better then something like that df = went_up(df, 'hill') df = fetch(df, 'water') df = fell_down(df, 'jack') df = broke(df, 'jack') df = tumble_after(df, 'jill') Would really like to hear an opinion about that.

What about when the steps don't return a data frame object, like 'groupby'? Then, you will have to think about coming up a name other than 'df'. Save your mental energy for making comments. Here's an example...

    # Per store revenue for high price items   
    df_agg = (
      df1
      .query("unit_price > 400")
      .groupby('store_id','store_name')
      .agg({'revenue':     np.sum, 
            'customer_id': 'nunique'})
    )

Re: Modern Pandas (Part 2): Method Chaining

#46

I've always found pandas really hard to use or reason about. I eventually get there but I don't like the code. Obviously subjective. I've never used another "data science" language though so I've no experience beyond it.

If you are ready to stretch your mind and have time and energy to learn a new skill, I recommend this as "data science" language: APL Background: I first gained some experience with J, where I first learned to appreciate the advantages of array languages. The main advantage is actually having your own way of thinking about processing multidimensional data. Now, recently, I've gotten into the notation of APL, and it's…

APL and J are on my list of programming languages I'd like to learn. I've been listening to the Array Cast podcast for a while. I just need a place to start. I don't really learn a language until I use it for something, at the moment I have nothing to use APL for. Any recommendations of where to start would be welcome.

Re: Modern Pandas (Part 2): Method Chaining

#47

Pandas is something that I wish I could avoid at any cost but I can't. There is simply no design philosophy. API is as ugly as it gets. I find it greatly unintuitive. It feels like a giant missmash of hacks on top of other hacks. Sometime I wish designers of Numpy or scikit-learn should have developed Pandas.

I always see these type of complaints and, when I actually sit down with people to resolve their aversion, it ultimately comes back to they use Pandas incorrectly or simply are not able to grok documentation. The usual dead giveaway is "Pandas documentation is horrible". Anyone who has used more than one documentation would know that documentation rarely includes every function in the API let alone the argument, examples, and links to other related functions.

As this is the top comment, can you (and others) at least post the problems so that we can have an intellectual discussion? Maybe the Pandas devs might take a point or two.

Re: Modern Pandas (Part 2): Method Chaining

#49
post #45

I don't see how this ( df.pipe(went_up, 'hill') .pipe(fetch, 'water') .pipe(fell_down, 'jack') .pipe(broke, 'crown') .pipe(tumble_after, 'jill') ) is much better then something like that df = went_up(df, 'hill') df = fetch(df, 'water') df = fell_down(df, 'jack') df = broke(df, 'jack') df = tumble_after(df, 'jill') Would really like to hear an opinion about that.

What about when the steps don't return a data frame object, like 'groupby'? Then, you will have to think about coming up a name other than 'df'. Save your mental energy for making comments. Here's an example... # Per store revenue for high price items df_agg = ( df1 .query("unit_price > 400") .groupby('store_id','store_name') .agg({'revenue': np.sum, 'customer_id': 'nunique'}) )

Groupby agg is a bit of an exception. It’s returning something that is very different from the original. Not just a modification, but a different table that summarizes the original. You ought to be assigning it to a new variable.

Groupby->agg is a good one to chain because you don’t want the intermediary almost ever.

Edit: also, I never understand people who use query. That just seems like it’s begging for problems later on. .loc for life.

Post reply on HN