Closed jcrist closed 7 years ago
def f(x):
df = x[x.amount < 20]
return df.groupby(df.id).amount.count()
in your original function, you are passing x.id
which certainly can change as the filtered frame will be new, but the grouping index is the original. That is very unsafe in general (though pandas may take it)
I can't seem to reproduce it on my machine.
However, you are passing a grouper with a different shape. I actually didn't know that pandas is aligning the grouper. You can also pass the string: df.groupby('id').amount.count()
I think @jorisvandenbossche has it right.
.groupby
is aligning the group-and (x.id
). So this 'works', but I suspect this is in general an unsafe operation (from a thread point of view).
If you dont't align then this will be ok I think (IOW, if you pass in the group-and from the same frame).
certainly no guarantees :<
Yeah, I think this is why this didn't show up until now - I didn't know pandas supported unaligned indices passed to groupby. Showed up in a user bug https://github.com/dask/dask/issues/1876.
I can fix this in dask by manually aligning beforehand, but the threadsafe issue still stands. Out of curiousity, why does this fail only on the first call? Some index structure being built up and then cached on later calls?
The passed series (df.id
) gets reindexed (https://github.com/pandas-dev/pandas/blob/ba057443d1b69bb3735a4b18a18e4e4897231867/pandas/core/groupby.py#L2580), but that still shouldn't modify the original object?
Hmmm, well something is getting modified, as it only fails the first time.
its shouldn't ever modify the original object, only the groupby object itself has state, but that could be the problem. IOW, this is a cached_property, which I suppose could be interrupted and if the groupby object is shared......
This fails in the code above though, where only the original frame is shared (neither the groupby or the filtered frame is shared). But df.id
is the same object for all calls - could that be modified by the reindex? Or am I misunderstanding what's being cached here?
This seems to only fail if the index is longer than the grouped frame. Swapping the filter onto the index passes every time (not that this is recommended):
def f(x):
return x.groupby(x[x.amount < 20].id).amount.count()
xref #15338
Calling groupby with an unaligned index on the same frame in multiple threads can result in incorrect results. The following example demonstrates:
On my machine, running
python test.py
results in:A few notes:
build_frame
). To me this indicates that the groupby call sets up some state (that's cached) that may not be threadsafe. Also, the second call topool.map
always returns correct results, only the first calls fail.Tested with pandas master, as well as pandas 0.19.0 and up.