Skip to content

Allow aggregate funcs to return arrays in groupby #3805

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

Closed
wants to merge 3 commits into from

Conversation

jtratner
Copy link
Contributor

@jtratner jtratner commented Jun 7, 2013

fixes #3788

Please check out whether you like the error message for Performance Warning.

Also, I'm not sure whether this means that groupby fails under certain conditions and not others (like when trying Cython, etc.).

@hayd
Copy link
Contributor

hayd commented Jun 8, 2013

Thanks for putting that together. But, do you think we could:

warnings.warn("Function does not produce aggregated values. Will not be able to optimize.", PerformanceWarning)

rather than raise?

@hayd
Copy link
Contributor

hayd commented Jun 8, 2013

Hmmm, about the message, we could cover ourselves a bit more and say "Function does not produce aggregated values. Will not be able to optimize and may produce unexpected results."

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

What's the difference between raise and warnings.warn?

@hayd
Copy link
Contributor

hayd commented Jun 8, 2013

Oh, I thought that warnings.warn would give you a warning message but still let you do it. Raise kills it, raises an Exception, throws toys out of pram and gives no result. (I could be wrong... but I was hoping for the former :) )

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

@hayd maybe? I don't know. How do you test that the warning occurred? Also, how about we do even more couched:

Function does not produce aggregated values. Will not be able to optimize and may produce unexpected results. This is experimental and results are not guaranteed to stay the same between versions.

@hayd
Copy link
Contributor

hayd commented Jun 8, 2013

I think like this (or do you have it working?).

There are some PerformanceWarnings in test_pytables, but @jreback seems to ignore (?) them with:

warnings.filterwarnings('ignore', category=PerformanceWarning)

Also, I think we may as well include tests for the current results of those calculations. :)

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

I did add some tests like that with warnings.catch_warning. I'll try and
come back to this tomorrow.

@hayd
Copy link
Contributor

hayd commented Jun 8, 2013

(haha! I think the experimental bit... is a little OTT!)

The usual assertEqual(result, expected) tests :)

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

Given there are multiple interpretations of what it means to produce an
aggregate that's a sequence, I didn't want us to be stuck supporting this
edge case in the future. Your call.

On Fri, Jun 7, 2013 at 9:25 PM, Andy Hayden [email protected]:

(haha! I think the experimental bit... is a little OTT!)

The usual assertEqual(result, expected) tests :)


Reply to this email directly or view it on GitHubhttps://github.com//pull/3805#issuecomment-19140771
.

@jreback
Copy link
Contributor

jreback commented Jun 8, 2013

@hayd I ignore them so they won't print on the test display; if you don't silence they will...

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

Or if you use warnings.catch_warnings, you can change the warnings just
for the duration of the test.

@hayd
Copy link
Contributor

hayd commented Jun 8, 2013

Ah of course! Do you test the warnings appear?

Personally I think that saying "may produce unexpected results" is enough to say we're not really supporting it, and having those assertEquals tests would just highlight when there's a problem and we can then choose to break. :)

@jreback
Copy link
Contributor

jreback commented Jun 8, 2013

@jtratner that is the right way......I was ignoring them before I knew how to do that!

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

Yeah, I just need to fix the tests slightly.

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

Actually, I'd say that in general we should probably set the warning filter to error so that all errors are explicitly caught (right now Travis has two DeprecationWarning errors).

@jreback
Copy link
Contributor

jreback commented Jun 8, 2013

The issue is that some of these warnings we are explicity testing something in order to generate the warning (like here, the Performance issue).....so you would have to have a try except block around them which would mask an actual problem....

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

Well, if you're testing something to generate the warning, you can do a few things:

  1. Set to 'always' and then assert that the length of the catch_warnings object is greater than 1
  2. Use 'error' and assert that it causes the warning.

I guess 1 is actually better in general.

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

Also, @hayd I went with your warning message :)

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

@hayd @jreback does this look okay to you? Do you want me to make any other changes or updates?

@hayd
Copy link
Contributor

hayd commented Jun 8, 2013

The only thing I would mention is that we might as well add tests for the actual results of those two calls.

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

oh sorry! totally forgot. I'll add that.

On Sat, Jun 8, 2013 at 2:25 PM, Andy Hayden [email protected]:

The only thing I would mention is that we might as well add tests for the
actual results of those two calls.


Reply to this email directly or view it on GitHubhttps://github.com//pull/3805#issuecomment-19153076
.

@hayd
Copy link
Contributor

hayd commented Jun 8, 2013

Hmm an additional test to add is the example from the original issue, as I think that is a non ambiguous thing (and after all, it works fine with lists...).

Just going through them, none of the test returned ValueError('Function does not reduce'), can we think of a good/bad example of this, either that's bad or good? (Did you work out why that one was there?)

grouped.agg(lambda x: x.describe())
Exception: Must produce aggregated value
Intermediary output:
count    3.000000
mean     0.971312
std      1.130488
min     -0.330182
25%      0.602385
50%      1.534953
75%      1.622060
max      1.709167
dtype: float64
Now:
A
bar    [3.0, -0.704089998761, 0.619650989953, -1.0771...
foo    [5.0, 0.696226374171, 0.679933321298, 0.288482...
Name: C, dtype: object
grouped.agg(lambda x: x.index[:2])
Exception: Must produce aggregated value
Intermediary output:
Int64Index([1, 3], dtype=int64)
Now:
A
bar    [1, 3]
foo    [0, 2]
Name: C, dtype: object
grouped.aggregate, lambda x: x * 2
Exception: Must produce aggregated value
Intermediary output:
1    3.069905
3   -0.660364
5    3.418333
Name: bar, dtype: float64
Now:
A
bar    [-2.15438895675, -2.09254823116, 0.0223971953452]
foo    [3.78051447736, 0.576965254291, 0.687811502056...
Name: C, dtype: object

In the first example they "obviously" really want the result (and this would also work for the second in this instance):

pd.DataFrame([s for s in res], index=res.index)

I really have no idea what's going on in the third one... unexpected is correct lol.

All cases there is a better way I think.

I see now what you are saying about ambiguity. So maybe tests for these weird example aren't so important... :S

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

Yeah, and it makes the test cases really annoying, because they have to deal with truth values in numpy arrays...ugh.

I don't want to unintentionally force us to support weird edge case behavior with groupby. On the upside, this got me to write a nice little test utility to neatly check that something raises a warning.

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

Okay, so this now has test cases & such. I'd vote to remove jtratner@d1ce722 (which specifically tests the results), but I wanted to include it if you want it.

I also added a new test utility to check for warnings (jtratner@86d56ac ). Given that it is a wrapper around a context manager and that it explicitly changes warnings.simplefilter, I felt it made more sense to use as a context manager, especially because it means that you can add additional tests around the warning if you want.

Doctests on the test utility all pass as well. (not sure if that' s included with the Travis tests).

@hayd
Copy link
Contributor

hayd commented Jun 8, 2013

Yeah, you're right about removing jtratner@d1ce722 (sorry!).

assert_produces_warning looks whizzy!

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

Hahaha, I just finished fixing the test case from the SO question. Removing that forever and then pushing.

@jtratner
Copy link
Contributor Author

jtratner commented Jun 8, 2013

Okay, this should all pass + I added notes to RELEASE.rst for this.

@jtratner
Copy link
Contributor Author

jtratner commented Jun 9, 2013

Never mind. I'm wrong, needed to reset the warning filter each time in assert_produces_warnings.

@hayd
Copy link
Contributor

hayd commented Jun 9, 2013

Did you ever find any way of getting the previous ValueError('Function does not reduce') ?

@jtratner
Copy link
Contributor Author

jtratner commented Jun 9, 2013

@hayd Nope. Not at all - very weird.

@jreback
Copy link
Contributor

jreback commented Jun 9, 2013

can u post the example that works now (with the warning ) and that didn't work before
with what it outputs?

@hayd
Copy link
Contributor

hayd commented Jun 9, 2013

The example from #3788:

In [5]: df = pd.DataFrame([[1,np.array([10,20,30])],
   ...:                [1,np.array([40,50,60])],
   ...:                [2,np.array([20,30,40])],], columns=['category','arraydata'])

In [6]: g = df.groupby('category')

In [7]: g.agg(sum)
pandas/core/groupby.py:890: PerformanceWarning: Function does not produce aggregated values. Will not be able to optimize and may produce unexpected results.
  return self._aggregate_series_pure_python(obj, func)
Out[7]:
             arraydata
category
1         [50, 70, 90]
2         [20, 30, 40]

As an aside, I just threw in list to see what would happen (this is current behaviour in master):

In [8]: df = pd.DataFrame([[1,[10,20,30]],
               [1,[40,50,60]],
               [2,[20,30,40]],], columns=['category','arraydata'])

In [9]: g = df.groupby('category')

In [10]: g.agg(sum)
Out[10]:
                         arraydata
category
1         [10, 20, 30, 40, 50, 60]
2                     [20, 30, 40]

@hayd
Copy link
Contributor

hayd commented Jun 9, 2013

Maybe it should read "Function may not produce aggregated values." lol

@jtratner
Copy link
Contributor Author

jtratner commented Jun 9, 2013

I don't think it's worth it to change the list part, because to do it means adding additional isinstance calls in the middle of everything. It's really clear that something is going wrong when you do this, so I don't think it's a huge deal to just leave it like this. @jreback example previously raised an exception.

@hayd
Copy link
Contributor

hayd commented Jun 9, 2013

I still claim there's no ambiguity in either of those results, imo they both aggregate.

@wesm
Copy link
Member

wesm commented Jun 10, 2013

Looks like tests are failing? What to do here

@jtratner
Copy link
Contributor Author

@wesm not sure - occurred after I rebased on to the most recent master. Testing for warnings is really finicky.

@jtratner
Copy link
Contributor Author

Made the test function simpler, hopefully it will just work this time.

@hayd
Copy link
Contributor

hayd commented Jun 10, 2013

One test failing, and now needs a rebase (maybe worth squashing first).

@jtratner
Copy link
Contributor Author

Well, I've been trying a bunch of different ways to get it to work and none
of them are passing travis. But yeah, when I pull them back, I'll rebase it
and make it cleaner.

On Sun, Jun 9, 2013 at 11:58 PM, Andy Hayden [email protected]:

One test failing, and now needs a rebase (maybe worth squashing first).


Reply to this email directly or view it on GitHubhttps://github.com//pull/3805#issuecomment-19179986
.

jtratner added 2 commits June 10, 2013 00:31
…e a PerformanceWarning instead

warns that a non-aggregating function will result in degraded
performance

TST: Catch warnings in test_groupby
@jtratner
Copy link
Contributor Author

@hayd can you run this and see what you get? jtratner@dfb13e0 . I can't reproduce the error that Travis CI gets so it's difficult for me to fix it.

@hayd
Copy link
Contributor

hayd commented Jun 10, 2013

I can't reproduce either...

@jtratner
Copy link
Contributor Author

I'm thinking it's a Travis error (if you notice, a few other warnings
bubble up inapprorpiately)... Maybe if I change it to raise an error
instead, it will work.

On Mon, Jun 10, 2013 at 6:33 AM, Andy Hayden [email protected]:

I can't reproduce either...


Reply to this email directly or view it on GitHubhttps://github.com//pull/3805#issuecomment-19191223
.

@jtratner
Copy link
Contributor Author

I managed to reproduce this on my computer in 2.6! Now hopefully I can figure out why...

@jtratner
Copy link
Contributor Author

Update part 2: never mind, it happened two times on my system and then never failed again - I'm trying to rerun an old commit that worked and then see whether it fails when rebased onto the newest master.

@jreback
Copy link
Contributor

jreback commented Jun 12, 2013

@jtratner how's this coming?

@jtratner
Copy link
Contributor Author

@jreback I tried testing the failing example in travis on master - turns
out that it doesn't fail in all versions as expected (in other words, it
doesn't raise the Exception about not aggregating values). So I'm guessing
that something is going on where it goes down different code paths
depending on the version and/or something different about the environment
on Travis. I set up a build that (I think) will trace all the functions
executing in core/groupby, so I can see whether some patterns falls out...

On Wed, Jun 12, 2013 at 10:10 AM, jreback [email protected] wrote:

@jtratner https://github.com/jtratner how's this coming?


Reply to this email directly or view it on GitHubhttps://github.com//pull/3805#issuecomment-19327938
.

@jtratner
Copy link
Contributor Author

@jreback I've been watching the tracing and have learned some things: for example, the ValueError('Function does not reduce') actually gets caught within aggregate and needs to raise a ValueError, so you definitely shouldn't merge this as it stands now. Still can't figure out why there's different behavior in groupby for the motivating example in different environments.

@jreback
Copy link
Contributor

jreback commented Jun 13, 2013

ok....yeh lots of type inference operations that groupby needs....lmk

@jreback
Copy link
Contributor

jreback commented Jun 13, 2013

are we pushing this to 0.12 for consideratino?

@jtratner
Copy link
Contributor Author

That seems reasonable to me, it's relatively low importance and not worth being a blocker for the release.

@jtratner
Copy link
Contributor Author

If someone else wants to pick this up, go ahead. Going to close - I don't think it's worth the time for an edge case like this.

@jtratner jtratner closed this Oct 12, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Aggregating over arrays
4 participants