Skip to content

Commit a2f670c

Browse files
jbrockmendelquintusdias
authored andcommitted
CLN: Prune unnecessary indexing code (pandas-dev#27576)
1 parent 8b676fb commit a2f670c

File tree

6 files changed

+99
-97
lines changed

6 files changed

+99
-97
lines changed

pandas/core/frame.py

+3-7
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,9 @@
9494
)
9595
from pandas.core.indexes import base as ibase
9696
from pandas.core.indexes.datetimes import DatetimeIndex
97+
from pandas.core.indexes.multi import maybe_droplevels
9798
from pandas.core.indexes.period import PeriodIndex
98-
from pandas.core.indexing import (
99-
check_bool_indexer,
100-
convert_to_index_sliceable,
101-
maybe_droplevels,
102-
)
99+
from pandas.core.indexing import check_bool_indexer, convert_to_index_sliceable
103100
from pandas.core.internals import BlockManager
104101
from pandas.core.internals.construction import (
105102
arrays_to_mgr,
@@ -2794,8 +2791,6 @@ def _ixs(self, i: int, axis: int = 0):
27942791
if axis == 0:
27952792
label = self.index[i]
27962793
new_values = self._data.fast_xs(i)
2797-
if is_scalar(new_values):
2798-
return new_values
27992794

28002795
# if we are a copy, mark as such
28012796
copy = isinstance(new_values, np.ndarray) and new_values.base is None
@@ -2906,6 +2901,7 @@ def _getitem_bool_array(self, key):
29062901
return self.take(indexer, axis=0)
29072902

29082903
def _getitem_multilevel(self, key):
2904+
# self.columns is a MultiIndex
29092905
loc = self.columns.get_loc(key)
29102906
if isinstance(loc, (slice, Series, np.ndarray, Index)):
29112907
new_columns = self.columns[loc]

pandas/core/generic.py

+22-25
Original file line numberDiff line numberDiff line change
@@ -3296,11 +3296,8 @@ def _maybe_update_cacher(self, clear=False, verify_is_copy=True):
32963296
if clear:
32973297
self._clear_item_cache()
32983298

3299-
def _clear_item_cache(self, i=None):
3300-
if i is not None:
3301-
self._item_cache.pop(i, None)
3302-
else:
3303-
self._item_cache.clear()
3299+
def _clear_item_cache(self):
3300+
self._item_cache.clear()
33043301

33053302
# ----------------------------------------------------------------------
33063303
# Indexing Methods
@@ -3559,27 +3556,8 @@ class animal locomotion
35593556

35603557
_xs = xs # type: Callable
35613558

3562-
def get(self, key, default=None):
3563-
"""
3564-
Get item from object for given key (ex: DataFrame column).
3565-
3566-
Returns default value if not found.
3567-
3568-
Parameters
3569-
----------
3570-
key : object
3571-
3572-
Returns
3573-
-------
3574-
value : same type as items contained in object
3575-
"""
3576-
try:
3577-
return self[key]
3578-
except (KeyError, ValueError, IndexError):
3579-
return default
3580-
35813559
def __getitem__(self, item):
3582-
return self._get_item_cache(item)
3560+
raise AbstractMethodError(self)
35833561

35843562
def _get_item_cache(self, item):
35853563
"""Return the cached item, item represents a label indexer."""
@@ -3770,6 +3748,25 @@ def __delitem__(self, key):
37703748
# ----------------------------------------------------------------------
37713749
# Unsorted
37723750

3751+
def get(self, key, default=None):
3752+
"""
3753+
Get item from object for given key (ex: DataFrame column).
3754+
3755+
Returns default value if not found.
3756+
3757+
Parameters
3758+
----------
3759+
key : object
3760+
3761+
Returns
3762+
-------
3763+
value : same type as items contained in object
3764+
"""
3765+
try:
3766+
return self[key]
3767+
except (KeyError, ValueError, IndexError):
3768+
return default
3769+
37733770
@property
37743771
def _is_view(self):
37753772
"""Return boolean indicating if self is view of another array """

pandas/core/indexes/multi.py

+39-10
Original file line numberDiff line numberDiff line change
@@ -1470,9 +1470,6 @@ def dropna(self, how="any"):
14701470
return self.copy(codes=new_codes, deep=True)
14711471

14721472
def get_value(self, series, key):
1473-
# somewhat broken encapsulation
1474-
from pandas.core.indexing import maybe_droplevels
1475-
14761473
# Label-based
14771474
s = com.values_from_object(series)
14781475
k = com.values_from_object(key)
@@ -2709,7 +2706,7 @@ def _maybe_to_slice(loc):
27092706

27102707
return _maybe_to_slice(loc) if len(loc) != stop - start else slice(start, stop)
27112708

2712-
def get_loc_level(self, key, level=0, drop_level=True):
2709+
def get_loc_level(self, key, level=0, drop_level: bool = True):
27132710
"""
27142711
Get both the location for the requested label(s) and the
27152712
resulting sliced index.
@@ -2750,7 +2747,8 @@ def get_loc_level(self, key, level=0, drop_level=True):
27502747
(1, None)
27512748
"""
27522749

2753-
def maybe_droplevels(indexer, levels, drop_level):
2750+
# different name to distinguish from maybe_droplevels
2751+
def maybe_mi_droplevels(indexer, levels, drop_level: bool):
27542752
if not drop_level:
27552753
return self[indexer]
27562754
# kludgearound
@@ -2780,7 +2778,7 @@ def maybe_droplevels(indexer, levels, drop_level):
27802778

27812779
result = loc if result is None else result & loc
27822780

2783-
return result, maybe_droplevels(result, level, drop_level)
2781+
return result, maybe_mi_droplevels(result, level, drop_level)
27842782

27852783
level = self._get_level_number(level)
27862784

@@ -2793,7 +2791,7 @@ def maybe_droplevels(indexer, levels, drop_level):
27932791
try:
27942792
if key in self.levels[0]:
27952793
indexer = self._get_level_indexer(key, level=level)
2796-
new_index = maybe_droplevels(indexer, [0], drop_level)
2794+
new_index = maybe_mi_droplevels(indexer, [0], drop_level)
27972795
return indexer, new_index
27982796
except TypeError:
27992797
pass
@@ -2808,7 +2806,7 @@ def partial_selection(key, indexer=None):
28082806
ilevels = [
28092807
i for i in range(len(key)) if key[i] != slice(None, None)
28102808
]
2811-
return indexer, maybe_droplevels(indexer, ilevels, drop_level)
2809+
return indexer, maybe_mi_droplevels(indexer, ilevels, drop_level)
28122810

28132811
if len(key) == self.nlevels and self.is_unique:
28142812
# Complete key in unique index -> standard get_loc
@@ -2843,10 +2841,10 @@ def partial_selection(key, indexer=None):
28432841
if indexer is None:
28442842
indexer = slice(None, None)
28452843
ilevels = [i for i in range(len(key)) if key[i] != slice(None, None)]
2846-
return indexer, maybe_droplevels(indexer, ilevels, drop_level)
2844+
return indexer, maybe_mi_droplevels(indexer, ilevels, drop_level)
28472845
else:
28482846
indexer = self._get_level_indexer(key, level=level)
2849-
return indexer, maybe_droplevels(indexer, [level], drop_level)
2847+
return indexer, maybe_mi_droplevels(indexer, [level], drop_level)
28502848

28512849
def _get_level_indexer(self, key, level=0, indexer=None):
28522850
# return an indexer, boolean array or a slice showing where the key is
@@ -3464,3 +3462,34 @@ def _sparsify(label_list, start=0, sentinel=""):
34643462

34653463
def _get_na_rep(dtype):
34663464
return {np.datetime64: "NaT", np.timedelta64: "NaT"}.get(dtype, "NaN")
3465+
3466+
3467+
def maybe_droplevels(index, key):
3468+
"""
3469+
Attempt to drop level or levels from the given index.
3470+
3471+
Parameters
3472+
----------
3473+
index: Index
3474+
key : scalar or tuple
3475+
3476+
Returns
3477+
-------
3478+
Index
3479+
"""
3480+
# drop levels
3481+
original_index = index
3482+
if isinstance(key, tuple):
3483+
for _ in key:
3484+
try:
3485+
index = index.droplevel(0)
3486+
except ValueError:
3487+
# we have dropped too much, so back out
3488+
return original_index
3489+
else:
3490+
try:
3491+
index = index.droplevel(0)
3492+
except ValueError:
3493+
pass
3494+
3495+
return index

pandas/core/indexing.py

+32-38
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def _validate_key(self, key, axis: int):
226226
def _has_valid_tuple(self, key: Tuple):
227227
""" check the key for valid keys across my indexer """
228228
for i, k in enumerate(key):
229-
if i >= self.obj.ndim:
229+
if i >= self.ndim:
230230
raise IndexingError("Too many indexers")
231231
try:
232232
self._validate_key(k, i)
@@ -254,7 +254,7 @@ def _convert_tuple(self, key, is_setter: bool = False):
254254
keyidx.append(slice(None))
255255
else:
256256
for i, k in enumerate(key):
257-
if i >= self.obj.ndim:
257+
if i >= self.ndim:
258258
raise IndexingError("Too many indexers")
259259
idx = self._convert_to_indexer(k, axis=i, is_setter=is_setter)
260260
keyidx.append(idx)
@@ -286,7 +286,7 @@ def _has_valid_positional_setitem_indexer(self, indexer):
286286
raise IndexError("{0} cannot enlarge its target object".format(self.name))
287287
else:
288288
if not isinstance(indexer, tuple):
289-
indexer = self._tuplify(indexer)
289+
indexer = _tuplify(self.ndim, indexer)
290290
for ax, i in zip(self.obj.axes, indexer):
291291
if isinstance(i, slice):
292292
# should check the stop slice?
@@ -401,7 +401,7 @@ def _setitem_with_indexer(self, indexer, value):
401401
assert info_axis == 1
402402

403403
if not isinstance(indexer, tuple):
404-
indexer = self._tuplify(indexer)
404+
indexer = _tuplify(self.ndim, indexer)
405405

406406
if isinstance(value, ABCSeries):
407407
value = self._align_series(indexer, value)
@@ -670,7 +670,7 @@ def ravel(i):
670670
aligners = [not com.is_null_slice(idx) for idx in indexer]
671671
sum_aligners = sum(aligners)
672672
single_aligner = sum_aligners == 1
673-
is_frame = self.obj.ndim == 2
673+
is_frame = self.ndim == 2
674674
obj = self.obj
675675

676676
# are we a single alignable value on a non-primary
@@ -731,7 +731,7 @@ def ravel(i):
731731
raise ValueError("Incompatible indexer with Series")
732732

733733
def _align_frame(self, indexer, df: ABCDataFrame):
734-
is_frame = self.obj.ndim == 2
734+
is_frame = self.ndim == 2
735735

736736
if isinstance(indexer, tuple):
737737

@@ -867,7 +867,7 @@ def _handle_lowerdim_multi_index_axis0(self, tup: Tuple):
867867
except KeyError as ek:
868868
# raise KeyError if number of indexers match
869869
# else IndexingError will be raised
870-
if len(tup) <= self.obj.index.nlevels and len(tup) > self.obj.ndim:
870+
if len(tup) <= self.obj.index.nlevels and len(tup) > self.ndim:
871871
raise ek
872872
except Exception as e1:
873873
if isinstance(tup[0], (slice, Index)):
@@ -900,7 +900,7 @@ def _getitem_lowerdim(self, tup: Tuple):
900900
if result is not None:
901901
return result
902902

903-
if len(tup) > self.obj.ndim:
903+
if len(tup) > self.ndim:
904904
raise IndexingError("Too many indexers. handle elsewhere")
905905

906906
# to avoid wasted computation
@@ -1274,11 +1274,6 @@ def _convert_to_indexer(
12741274
return {"key": obj}
12751275
raise
12761276

1277-
def _tuplify(self, loc):
1278-
tup = [slice(None, None) for _ in range(self.ndim)]
1279-
tup[0] = loc
1280-
return tuple(tup)
1281-
12821277
def _get_slice_axis(self, slice_obj: slice, axis: int):
12831278
# caller is responsible for ensuring non-None axis
12841279
obj = self.obj
@@ -2077,6 +2072,8 @@ def _getitem_tuple(self, tup: Tuple):
20772072

20782073
# if the dim was reduced, then pass a lower-dim the next time
20792074
if retval.ndim < self.ndim:
2075+
# TODO: this is never reached in tests; can we confirm that
2076+
# it is impossible?
20802077
axis -= 1
20812078

20822079
# try to get for the next axis
@@ -2152,7 +2149,7 @@ def _convert_to_indexer(
21522149
)
21532150

21542151

2155-
class _ScalarAccessIndexer(_NDFrameIndexer):
2152+
class _ScalarAccessIndexer(_NDFrameIndexerBase):
21562153
""" access scalars quickly """
21572154

21582155
def _convert_key(self, key, is_setter: bool = False):
@@ -2178,8 +2175,8 @@ def __setitem__(self, key, value):
21782175
key = com.apply_if_callable(key, self.obj)
21792176

21802177
if not isinstance(key, tuple):
2181-
key = self._tuplify(key)
2182-
if len(key) != self.obj.ndim:
2178+
key = _tuplify(self.ndim, key)
2179+
if len(key) != self.ndim:
21832180
raise ValueError("Not enough indexers for scalar access (setting)!")
21842181
key = list(self._convert_key(key, is_setter=True))
21852182
key.append(value)
@@ -2309,9 +2306,6 @@ class _iAtIndexer(_ScalarAccessIndexer):
23092306

23102307
_takeable = True
23112308

2312-
def _has_valid_setitem_indexer(self, indexer):
2313-
self._has_valid_positional_setitem_indexer(indexer)
2314-
23152309
def _convert_key(self, key, is_setter: bool = False):
23162310
""" require integer args (and convert to label arguments) """
23172311
for a, i in zip(self.obj.axes, key):
@@ -2320,6 +2314,25 @@ def _convert_key(self, key, is_setter: bool = False):
23202314
return key
23212315

23222316

2317+
def _tuplify(ndim: int, loc) -> tuple:
2318+
"""
2319+
Given an indexer for the first dimension, create an equivalent tuple
2320+
for indexing over all dimensions.
2321+
2322+
Parameters
2323+
----------
2324+
ndim : int
2325+
loc : object
2326+
2327+
Returns
2328+
-------
2329+
tuple
2330+
"""
2331+
tup = [slice(None, None) for _ in range(ndim)]
2332+
tup[0] = loc
2333+
return tuple(tup)
2334+
2335+
23232336
def convert_to_index_sliceable(obj, key):
23242337
"""
23252338
if we are index sliceable, then return my slicer, otherwise return None
@@ -2469,25 +2482,6 @@ def need_slice(obj):
24692482
)
24702483

24712484

2472-
def maybe_droplevels(index, key):
2473-
# drop levels
2474-
original_index = index
2475-
if isinstance(key, tuple):
2476-
for _ in key:
2477-
try:
2478-
index = index.droplevel(0)
2479-
except ValueError:
2480-
# we have dropped too much, so back out
2481-
return original_index
2482-
else:
2483-
try:
2484-
index = index.droplevel(0)
2485-
except ValueError:
2486-
pass
2487-
2488-
return index
2489-
2490-
24912485
def _non_reducing_slice(slice_):
24922486
"""
24932487
Ensurse that a slice doesn't reduce to a Series or Scalar.

0 commit comments

Comments
 (0)