Skip to content

REF: dont set ndarray.data in libreduction #34997

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 94 commits into from
Closed
Show file tree
Hide file tree
Changes from 92 commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
4c5eddd
REF: remove unnecesary try/except
jbrockmendel Aug 21, 2020
c632c9f
Merge branch 'master' of https://github.com/pandas-dev/pandas into re…
jbrockmendel Aug 21, 2020
9e64be3
Merge branch 'master' of https://github.com/pandas-dev/pandas into re…
jbrockmendel Aug 21, 2020
42649fb
TST: add test for agg on ordered categorical cols (#35630)
mathurk1 Aug 21, 2020
47121dd
TST: resample does not yield empty groups (#10603) (#35799)
tkmz-n Aug 21, 2020
1decb3e
revert accidental rebase
jbrockmendel Aug 22, 2020
57c5dd3
Merge branch 'master' of https://github.com/pandas-dev/pandas into ma…
jbrockmendel Aug 22, 2020
a358463
Merge branch 'master' of https://github.com/pandas-dev/pandas into ma…
jbrockmendel Aug 23, 2020
ffa7ad7
Merge branch 'master' of https://github.com/pandas-dev/pandas into ma…
jbrockmendel Aug 23, 2020
e5e98d4
Merge branch 'master' of https://github.com/pandas-dev/pandas into ma…
jbrockmendel Aug 24, 2020
408db5a
Merge branch 'master' of https://github.com/pandas-dev/pandas into ma…
jbrockmendel Aug 24, 2020
d3493cf
Merge branch 'master' of https://github.com/pandas-dev/pandas into ma…
jbrockmendel Aug 25, 2020
75a805a
Merge branch 'master' of https://github.com/pandas-dev/pandas into ma…
jbrockmendel Aug 25, 2020
9f61070
Merge branch 'master' of https://github.com/pandas-dev/pandas into ma…
jbrockmendel Aug 25, 2020
2d10f6e
Merge branch 'master' of https://github.com/pandas-dev/pandas into ma…
jbrockmendel Aug 26, 2020
3e20187
Merge branch 'master' of https://github.com/pandas-dev/pandas into ma…
jbrockmendel Aug 26, 2020
51205a5
REF/BUG: don't go through cython for EA indexes
jbrockmendel Aug 27, 2020
f453c5b
Implement _aggregate_maybe_named
jbrockmendel Aug 27, 2020
2ae2124
de-duplicate
jbrockmendel Aug 27, 2020
98a91a3
avoid passing RangeIndex to libreduction
jbrockmendel Aug 27, 2020
5f73b03
Merge branch 'master' of https://github.com/pandas-dev/pandas into ca…
jbrockmendel Aug 30, 2020
065fc69
Merge branch 'master' of https://github.com/pandas-dev/pandas into ca…
jbrockmendel Sep 1, 2020
c230f72
simplify
jbrockmendel Sep 2, 2020
bf2e171
Merge branch 'master' of https://github.com/pandas-dev/pandas into ca…
jbrockmendel Sep 5, 2020
ba48381
REF: dont set ndarray.data in libreduction
jbrockmendel Jun 25, 2020
e52db7d
less test failures
WillAyd Jul 22, 2020
972359f
port solution from #35417
jbrockmendel Aug 18, 2020
28f6ca5
dont pass Series with DTI to SeriesGrouper
jbrockmendel Sep 1, 2020
0aa2a54
De-privatize (#36130)
jbrockmendel Sep 5, 2020
0164b8a
TYP: misc fixes for numpy types (#36098)
simonjayhawkins Sep 5, 2020
48b5847
Comma cleanup (#36082)
JonathanShrek Sep 5, 2020
4abfaea
CLN: remove unused args/kwargs (#36129)
jbrockmendel Sep 5, 2020
3b4be02
BUG: Fix DataFrame.groupby().apply() for NaN groups with dropna=False…
cwkwong Sep 5, 2020
fb18f47
Bug 29764 groupby loses index name sometimes (#36121)
phofl Sep 5, 2020
d26090d
STY: add code check for use of builtin filter function (#36089)
simonjayhawkins Sep 5, 2020
97ed706
BUG: df.replace with numeric values and str to_replace (#36093)
jbrockmendel Sep 5, 2020
0569e29
CLN: resolve UserWarning in `pandas/plotting/_matplotlib/core.py` #35…
fangchenli Sep 5, 2020
7b2d437
add note about missing values to Categorical docstring (#36125)
arw2019 Sep 5, 2020
7e90686
CLN removing trailing commas (#36101)
Sep 5, 2020
0d2b936
Updated series documentation to close #35406 (#36139)
Sep 5, 2020
2bcc156
BUG: repair 'style' kwd handling in DataFrame.plot (#21003) (#33821)
joooeey Sep 5, 2020
55bdb16
BUG/ENH: to_pickle/read_pickle support compression for file ojects (#…
twoertwein Sep 5, 2020
40008d0
TYP: Check for use of Union[Series, DataFrame] instead of FrameOrSeri…
simonjayhawkins Sep 5, 2020
6f2ca92
TYP: remove string literals for type annotations in pandas\core\frame…
simonjayhawkins Sep 5, 2020
e766895
STY+CI: check for private function access across modules (#36144)
jbrockmendel Sep 5, 2020
65407bc
CLN: unused case in compare_or_regex_search (#36143)
jbrockmendel Sep 5, 2020
238de4c
REF: window/test_dtypes.py with pytest idioms (#35918)
mroeschke Sep 5, 2020
13c0dd3
DOC: add userwarning doc about mpl #35684 (#36145)
fangchenli Sep 5, 2020
435a1d0
BUG: item_cache invalidation in get_numeric_data (#35882)
jbrockmendel Sep 5, 2020
0d28752
Make MultiIndex.get_loc raise for unhashable type (#35914)
dsaxton Sep 5, 2020
29c0bc2
ENH: Make explode work for sets (#35637)
dsaxton Sep 5, 2020
c67b707
BUG: Don't raise when constructing Series from ordered set (#36054)
dsaxton Sep 5, 2020
b8181f4
REGR: append tz-aware DataFrame with tz-naive values (#36115)
jorisvandenbossche Sep 6, 2020
88b5e10
BUG: Respect errors="ignore" during extension astype (#35979)
dsaxton Sep 6, 2020
f9ce579
De-privatize imported names (#36156)
jbrockmendel Sep 6, 2020
911e997
REF: share more EA methods (#36154)
jbrockmendel Sep 6, 2020
4480b4a
CLN: Separate transform tests (#36146)
rhshadrach Sep 6, 2020
c2a0eac
CLN: _wrap_applied_output (#36160)
rhshadrach Sep 6, 2020
366f63c
BUG: allow missing values in Index when calling Index.sort_values (#3…
AlexKirko Sep 6, 2020
8631f2e
BUG: extra leading space in to_string when index=False (#36094)
onshek Sep 6, 2020
66b3b5a
BUG: shows correct package name when import_optional_dependency is ca…
hs2361 Sep 7, 2020
4550cf1
REF: simplify latex formatting (#35872)
ivanovmg Sep 7, 2020
7db9d22
Comma cleanup (#36168)
JonathanShrek Sep 7, 2020
172c626
TST: test_datetime64_factorize on 32bit (#36192)
simonjayhawkins Sep 7, 2020
f895c6a
TST: update test_series_factorize_na_sentinel_none for 32bit (#36191)
simonjayhawkins Sep 7, 2020
bb5b86a
DOC: move release note for #36155 (#36187)
simonjayhawkins Sep 7, 2020
de2a1dc
REF: use _validate_foo pattern in Categorical (#36181)
jbrockmendel Sep 7, 2020
d9de663
DTA/TDA/PA use self._data instead of self.asi8 for self._ndarray (#36…
jbrockmendel Sep 7, 2020
7cb1421
TST verify groupby doesn't alter unit64s to floats #30859 (#36164)
Sep 7, 2020
f796140
Fix compressed multiindex for output of groupby.rolling (#36152)
phofl Sep 7, 2020
c962e70
TST: DataFrame.replace: TypeError: Cannot compare types 'ndarray(dtyp…
phofl Sep 7, 2020
22b547b
REF: collect methods by topic (#36173)
jbrockmendel Sep 7, 2020
a155986
REF: implement Categorical._validate_setitem_value (#36180)
jbrockmendel Sep 7, 2020
5aa96dd
COMPAT: match numpy behavior for searchsorted on dt64/td64 (#36176)
jbrockmendel Sep 8, 2020
81c5802
pandas docs json_normalize example (#36194)
nzare Sep 8, 2020
a56c6af
BUG: GroupbyRolling with an empty frame (#36208)
mroeschke Sep 8, 2020
4a0152e
DOC: doc fix (#36205)
simonjayhawkins Sep 8, 2020
3aed293
DOC: release date for 1.1.2 (#36182)
simonjayhawkins Sep 8, 2020
4c9add8
Fixed pandas.json_normalize doctests errors` (#36207)
ylin00 Sep 8, 2020
11643bc
BUG: copying series into empty dataframe does not preserve dataframe …
Dr-Irv Sep 8, 2020
edd802f
CLN remove trailing commas (#36222)
tiagohonorato Sep 8, 2020
9339b80
CLN: remove unused return value in _create_blocks (#36196)
jbrockmendel Sep 8, 2020
070481c
Make to_numeric default to correct precision (#36149)
Dr-Irv Sep 8, 2020
e8d42b0
Merge branch 'master' of https://github.com/pandas-dev/pandas into re…
jbrockmendel Sep 14, 2020
c20f2cd
Merge branch 'master' of https://github.com/pandas-dev/pandas into re…
jbrockmendel Sep 14, 2020
9220944
Merge branch 'master' of https://github.com/pandas-dev/pandas into re…
jbrockmendel Sep 15, 2020
4193e03
post-rebase fixup
jbrockmendel Sep 15, 2020
816f2fc
revert whitespace mixup
jbrockmendel Sep 15, 2020
dfb3c10
Merge branch 'master' of https://github.com/pandas-dev/pandas into re…
jbrockmendel Sep 17, 2020
1a318ef
Merge branch 'master' of https://github.com/pandas-dev/pandas into re…
jbrockmendel Sep 17, 2020
4480c67
Merge branch 'master' of https://github.com/pandas-dev/pandas into re…
jbrockmendel Sep 17, 2020
865cb8b
Implement _can_use_libreduction
jbrockmendel Sep 17, 2020
a4d75da
Merge branch 'master' of https://github.com/pandas-dev/pandas into re…
jbrockmendel Sep 18, 2020
7939eae
Merge branch 'master' of https://github.com/pandas-dev/pandas into re…
jbrockmendel Sep 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 35 additions & 20 deletions pandas/_libs/reduction.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ cdef class _BaseGrouper:
# See the comment in indexes/base.py about _index_data.
# We need this for EA-backed indexes that have a reference
# to a 1-d ndarray like datetime / timedelta / period.
object.__setattr__(cached_ityp, '_index_data', islider.buf)
object.__setattr__(cached_ityp, '_data', islider.buf)
cached_ityp._engine.clear_mapping()
cached_ityp._cache.clear() # e.g. inferred_freq must go
object.__setattr__(cached_typ._mgr._block, 'values', vslider.buf)
Expand Down Expand Up @@ -296,7 +296,7 @@ cdef class Slider:
Only handles contiguous data for now
"""
cdef:
ndarray values, buf
ndarray values, buf, orig_buf
Py_ssize_t stride, orig_len, orig_stride
char *orig_data

Expand All @@ -308,28 +308,22 @@ cdef class Slider:
values = values.copy()

self.values = values
self.orig_buf = buf
self.buf = buf
self.stride = values.strides[0]

self.orig_data = self.buf.data
self.orig_len = self.buf.shape[0]
self.orig_stride = self.buf.strides[0]

self.buf.data = self.values.data
self.buf.strides[0] = self.stride

cdef move(self, int start, int end):
"""
For slicing
"""
self.buf.data = self.values.data + self.stride * start
self.buf.shape[0] = end - start
self.buf = self.values[start:end]

cdef reset(self):

self.buf.shape[0] = self.orig_len
self.buf.data = self.orig_data
self.buf.strides[0] = self.orig_stride
self.buf = self.orig_buf


class InvalidApply(Exception):
Expand Down Expand Up @@ -359,7 +353,7 @@ def apply_frame_axis0(object frame, object f, object names,
slider.move(starts[i], ends[i])

item_cache.clear() # ugh
chunk = slider.dummy
chunk = slider.frame[starts[i]:ends[i]]
object.__setattr__(chunk, 'name', names[i])

try:
Expand Down Expand Up @@ -406,7 +400,8 @@ cdef class BlockSlider:
object frame, dummy, index
int nblocks
Slider idx_slider
list blocks
list blocks, blk_values
ndarray orig_blklocs, orig_blknos

cdef:
char **base_ptrs
Expand All @@ -420,20 +415,27 @@ cdef class BlockSlider:
self.dummy = frame[:0]
self.index = self.dummy.index

self.blocks = [b.values for b in self.dummy._mgr.blocks]
# GH#35417 attributes we need to restore at each step in case
# the function modified them.
mgr = self.dummy._mgr
self.orig_blklocs = mgr.blklocs
self.orig_blknos = mgr.blknos
self.blocks = [x for x in self.dummy._mgr.blocks]

for x in self.blocks:
self.blk_values = [b.values for b in self.dummy._mgr.blocks]

for x in self.blk_values:
util.set_array_not_contiguous(x)

self.nblocks = len(self.blocks)
self.nblocks = len(self.blk_values)
# See the comment in indexes/base.py about _index_data.
# We need this for EA-backed indexes that have a reference to a 1-d
# ndarray like datetime / timedelta / period.
self.idx_slider = Slider(
self.frame.index._index_data, self.dummy.index._index_data)

self.base_ptrs = <char**>malloc(sizeof(char*) * len(self.blocks))
for i, block in enumerate(self.blocks):
self.base_ptrs = <char**>malloc(sizeof(char*) * len(self.blk_values))
for i, block in enumerate(self.blk_values):
self.base_ptrs[i] = (<ndarray>block).data

def __dealloc__(self):
Expand All @@ -444,9 +446,11 @@ cdef class BlockSlider:
ndarray arr
Py_ssize_t i

self._restore_blocks()

# move blocks
for i in range(self.nblocks):
arr = self.blocks[i]
arr = self.blk_values[i]

# axis=1 is the frame's axis=0
arr.data = self.base_ptrs[i] + arr.strides[1] * start
Expand All @@ -459,14 +463,25 @@ cdef class BlockSlider:
self.index._engine.clear_mapping()
self.index._cache.clear() # e.g. inferred_freq must go

cdef _restore_blocks(self):
"""
Ensure that we have the original blocks, blknos, and blklocs.
"""
mgr = self.dummy._mgr
mgr.blocks = self.blocks
mgr._blklocs = self.orig_blklocs
mgr._blknos = self.orig_blknos

cdef reset(self):
cdef:
ndarray arr
Py_ssize_t i

self._restore_blocks()

# reset blocks
for i in range(self.nblocks):
arr = self.blocks[i]
arr = self.blk_values[i]

# axis=1 is the frame's axis=0
arr.data = self.base_ptrs[i]
Expand Down
12 changes: 12 additions & 0 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,18 @@ def _data(self):
# e.g. fastparquet
return self._mgr

@property
def _can_use_libreduction(self) -> bool:
# groupby ops can only use libreduction fast-path if we are all-numpy
if self.index._has_complex_internals:
return False

is_invalid = lambda x: is_extension_array_dtype(x) or x.kind in ["m", "M"]
if self.ndim == 1:
return not is_invalid(self.dtype)
else:
return not self.dtypes.apply(is_invalid).any()

# ----------------------------------------------------------------------
# Axis
_stat_axis_number = 0
Expand Down
62 changes: 49 additions & 13 deletions pandas/core/groupby/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,14 @@
get_groupby,
group_selection_context,
)
from pandas.core.indexes.api import Index, MultiIndex, all_indexes_same
from pandas.core.indexes.api import (
DatetimeIndex,
Index,
MultiIndex,
PeriodIndex,
TimedeltaIndex,
all_indexes_same,
)
import pandas.core.indexes.base as ibase
from pandas.core.internals import BlockManager
from pandas.core.series import Series
Expand Down Expand Up @@ -256,16 +263,25 @@ def aggregate(self, func=None, *args, engine=None, engine_kwargs=None, **kwargs)
if self.grouper.nkeys > 1:
return self._python_agg_general(func, *args, **kwargs)

try:
return self._python_agg_general(func, *args, **kwargs)
except (ValueError, KeyError):
# TODO: KeyError is raised in _python_agg_general,
# see see test_groupby.test_basic
result = self._aggregate_named(func, *args, **kwargs)
if isinstance(
self._selected_obj.index, (DatetimeIndex, TimedeltaIndex, PeriodIndex)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the one place where i'm not using self._selected_obj._can_use_libreduction, as doing so would require 2.5 more kludges to get the tests passing:

  1. below on 283 after ret = create_series_with_explicit_dtype would need to do
            # Inference in the Series constructor may not infer
            #  custom EA dtypes, so try here
            ret = maybe_cast_result(ret._values, obj, numeric_only=True)
            ret = Series(ret, index=index, name=obj.name)

1.5) in create_series_with_explicit_dtype would need to change dtype_if_empty=object to dtype_if_empty=obj.dtype (which im not 100% sure about)

  1. The kludge here would have to be amended from and name in output.index to and (name in output.index or 0 in output.index)

):
# using _python_agg_general would end up incorrectly patching
# _index_data in reduction.pyx
result = self._aggregate_maybe_named(func, *args, **kwargs)
else:
try:
return self._python_agg_general(func, *args, **kwargs)
except (ValueError, KeyError):
# TODO: KeyError is raised in _python_agg_general,
# see see test_groupby.test_basic
result = self._aggregate_maybe_named(func, *args, **kwargs)

index = Index(sorted(result), name=self.grouper.names[0])
# name setting -> test_metadata_propagation_indiv
index = self.grouper.result_index
obj = self._selected_obj
ret = create_series_with_explicit_dtype(
result, index=index, dtype_if_empty=object
result, index=index, dtype_if_empty=object, name=obj.name
)

if not self.as_index: # pragma: no cover
Expand Down Expand Up @@ -469,14 +485,34 @@ def _get_index() -> Index:
)
return self._reindex_output(result)

def _aggregate_named(self, func, *args, **kwargs):
def _aggregate_maybe_named(self, func, *args, **kwargs):
"""
Try the named-aggregator first, then unnamed, which better matches
what libreduction does.
"""
try:
return self._aggregate_named(func, *args, named=True, **kwargs)
except KeyError:
return self._aggregate_named(func, *args, named=False, **kwargs)

def _aggregate_named(self, func, *args, named: bool = True, **kwargs):
result = {}

for name, group in self:
group.name = name
for name, group in self: # TODO: could we have duplicate names?
if named:
group.name = name

output = func(group, *args, **kwargs)
if isinstance(output, (Series, Index, np.ndarray)):
raise ValueError("Must produce aggregated value")
if (
isinstance(output, Series)
and len(output) == 1
and name in output.index
):
# FIXME: kludge for test_resampler_grouper.test_apply
output = output.iloc[0]
else:
raise ValueError("Must produce aggregated value")
result[name] = output

return result
Expand Down
18 changes: 4 additions & 14 deletions pandas/core/groupby/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,18 +156,13 @@ def apply(self, f: F, data: FrameOrSeries, axis: int = 0):
result_values = None

sdata: FrameOrSeries = splitter._get_sorted_data()
if sdata.ndim == 2 and np.any(sdata.dtypes.apply(is_extension_array_dtype)):
# calling splitter.fast_apply will raise TypeError via apply_frame_axis0
# if we pass EA instead of ndarray
# TODO: can we have a workaround for EAs backed by ndarray?
pass

elif (
if (
com.get_callable_name(f) not in base.plotting_methods
and isinstance(splitter, FrameSplitter)
and axis == 0
# fast_apply/libreduction doesn't allow non-numpy backed indexes
and not sdata.index._has_complex_internals
# or columns
and sdata._can_use_libreduction
):
try:
result_values, mutated = splitter.fast_apply(f, sdata, group_keys)
Expand Down Expand Up @@ -609,15 +604,10 @@ def agg_series(self, obj: Series, func: F):
# SeriesGrouper would raise if we were to call _aggregate_series_fast
return self._aggregate_series_pure_python(obj, func)

elif is_extension_array_dtype(obj.dtype):
elif not obj._can_use_libreduction:
# _aggregate_series_fast would raise TypeError when
# calling libreduction.Slider
# In the datetime64tz case it would incorrectly cast to tz-naive
# TODO: can we get a performant workaround for EAs backed by ndarray?
return self._aggregate_series_pure_python(obj, func)

elif obj.index._has_complex_internals:
# Preempt TypeError in _aggregate_series_fast
return self._aggregate_series_pure_python(obj, func)

try:
Expand Down
4 changes: 3 additions & 1 deletion pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4053,7 +4053,9 @@ def _has_complex_internals(self) -> bool:
Indicates if an index is not directly backed by a numpy array
"""
# used to avoid libreduction code paths, which raise or require conversion
return False
return isinstance(self, (ABCMultiIndex, ABCRangeIndex)) or not isinstance(
self._data, np.ndarray
)

def _is_memory_usage_qualified(self) -> bool:
"""
Expand Down
5 changes: 0 additions & 5 deletions pandas/core/indexes/category.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,6 @@ def values(self):
""" return the underlying data, which is a Categorical """
return self._data

@property
def _has_complex_internals(self) -> bool:
# used to avoid libreduction code paths, which raise or require conversion
return True

@doc(Index.__contains__)
def __contains__(self, key: Any) -> bool:
# if key is a NaN, check if any NaN is in self.
Expand Down
5 changes: 0 additions & 5 deletions pandas/core/indexes/interval.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,6 @@ def values(self) -> IntervalArray:
"""
return self._data

@property
def _has_complex_internals(self) -> bool:
# used to avoid libreduction code paths, which raise or require conversion
return True

def __array_wrap__(self, result, context=None):
# we don't want the superclass implementation
return result
Expand Down
5 changes: 0 additions & 5 deletions pandas/core/indexes/multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1508,11 +1508,6 @@ def _get_level_number(self, level) -> int:
) from err
return level

@property
def _has_complex_internals(self) -> bool:
# used to avoid libreduction code paths, which raise or require conversion
return True

@cache_readonly
def is_monotonic_increasing(self) -> bool:
"""
Expand Down
5 changes: 0 additions & 5 deletions pandas/core/indexes/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,6 @@ def _simple_new(cls, values: PeriodArray, name: Label = None):
def values(self):
return np.asarray(self)

@property
def _has_complex_internals(self):
# used to avoid libreduction code paths, which raise or require conversion
return True

def _shallow_copy(self, values=None, name: Label = no_default):
name = name if name is not no_default else self.name
cache = self._cache.copy() if values is None else {}
Expand Down
1 change: 0 additions & 1 deletion pandas/tests/groupby/test_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,6 @@ def test_apply_function_with_indexing_return_column():
tm.assert_frame_equal(result, expected)


@pytest.mark.xfail(reason="GH-34998")
def test_apply_with_timezones_aware():
# GH: 27212

Expand Down