Skip to content

Commit 5a9bc70

Browse files
committed
DEPR: deprecate .select() in favor of .loc(axis=)[]
closes #12401
1 parent 408ecd2 commit 5a9bc70

File tree

10 files changed

+232
-61
lines changed

10 files changed

+232
-61
lines changed

doc/source/whatsnew/v0.21.0.txt

+24
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,30 @@ These now coerce to ``object`` dtype.
415415
- Inconsistent behavior in ``.where()`` with datetimelikes which would raise rather than coerce to ``object`` (:issue:`16402`)
416416
- Bug in assignment against ``int64`` data with ``np.ndarray`` with ``float64`` dtype may keep ``int64`` dtype (:issue:`14001`)
417417

418+
.. _whatsnew_0210.api_breaking.select:
419+
420+
Select method is deprecated
421+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
422+
423+
The :meth:`Series.select` and :meth:`DataFrame.select` methods are deprecated in favor of using ``.loc[]`` (:issue:`12401`)
424+
425+
.. ipython:: python
426+
427+
df = DataFrame({'A': [1, 2, 3]}, index=['foo', 'bar', 'baz'])
428+
429+
.. code_block:: ipython
430+
431+
In [3]: df.select(lambda x: x in ['bar', 'baz'])
432+
FutureWarning: select is deprecated and will be removed in a future release. You can use .loc[crit] as a replacement
433+
Out[3]:
434+
A
435+
bar 2
436+
baz 3
437+
438+
.. ipython:: python
439+
440+
df.loc[lambda x: x in ['bar', 'baz']]
441+
418442
.. _whatsnew_0210.api.na_changes:
419443

420444
NA naming Changes

pandas/core/common.py

+47-2
Original file line numberDiff line numberDiff line change
@@ -441,13 +441,58 @@ def _get_callable_name(obj):
441441
return None
442442

443443

444-
def _apply_if_callable(maybe_callable, obj, **kwargs):
444+
def _apply_if_callable(maybe_callable, obj, axis=None, **kwargs):
445445
"""
446446
Evaluate possibly callable input using obj and kwargs if it is callable,
447447
otherwise return as it is
448+
449+
Parameters
450+
----------
451+
maybe_callable : possibly a callable
452+
obj : NDFrame
453+
axis : int, optional
454+
**kwargs
448455
"""
456+
449457
if callable(maybe_callable):
450-
return maybe_callable(obj, **kwargs)
458+
459+
# we are allowing a user callable, which can return
460+
# a result based on the object itself, e.g. a scalar / list
461+
# of labels, or a boolean result from evaluating the labels
462+
# on the specified axis
463+
464+
def try_on_axis():
465+
labels = obj._get_axis(axis or 0)
466+
return labels.map(maybe_callable, **kwargs).values
467+
468+
# act on object
469+
try:
470+
result = maybe_callable(obj, **kwargs)
471+
472+
# if we have asked for a specific axis
473+
# then we must be 1d
474+
if axis is not None:
475+
if getattr(result, 'ndim', 1) != 1:
476+
raise ValueError
477+
478+
return result
479+
except KeyError as e:
480+
# this is potentially a legitimate error
481+
# if we cannot work on the labels
482+
# we want to preserve the original KeyError
483+
try:
484+
return try_on_axis()
485+
except: # no pragma
486+
raise e
487+
except: # no pragma
488+
pass
489+
490+
# act on the axis
491+
try:
492+
return try_on_axis()
493+
except AttributeError:
494+
pass
495+
451496
return maybe_callable
452497

453498

pandas/core/generic.py

+23-13
Original file line numberDiff line numberDiff line change
@@ -2339,6 +2339,8 @@ def select(self, crit, axis=0):
23392339
"""
23402340
Return data corresponding to axis labels matching criteria
23412341
2342+
DEPRECATED: use .loc(axis=)[crit] to select via labels
2343+
23422344
Parameters
23432345
----------
23442346
crit : function
@@ -2349,6 +2351,11 @@ def select(self, crit, axis=0):
23492351
-------
23502352
selection : type of caller
23512353
"""
2354+
warnings.warn("select is deprecated and will be removed in a "
2355+
"future release. You can use "
2356+
".loc[crit] as a replacement",
2357+
FutureWarning, stacklevel=2)
2358+
23522359
axis = self._get_axis_number(axis)
23532360
axis_name = self._get_axis_name(axis)
23542361
axis_values = self._get_axis(axis)
@@ -3101,7 +3108,7 @@ def filter(self, items=None, like=None, regex=None, axis=None):
31013108
31023109
See Also
31033110
--------
3104-
pandas.DataFrame.select
3111+
pandas.DataFrame.loc
31053112
31063113
Notes
31073114
-----
@@ -3120,20 +3127,23 @@ def filter(self, items=None, like=None, regex=None, axis=None):
31203127

31213128
if axis is None:
31223129
axis = self._info_axis_name
3123-
axis_name = self._get_axis_name(axis)
3124-
axis_values = self._get_axis(axis_name)
3130+
labels = self._get_axis(axis)
31253131

31263132
if items is not None:
3127-
return self.reindex(**{axis_name:
3128-
[r for r in items if r in axis_values]})
3133+
name = self._get_axis_name(axis)
3134+
return self.reindex(
3135+
**{name: [r for r in items if r in labels]})
31293136
elif like:
3130-
matchf = lambda x: (like in x if isinstance(x, string_types) else
3131-
like in str(x))
3132-
return self.select(matchf, axis=axis_name)
3137+
def f(x):
3138+
if not isinstance(x, string_types):
3139+
x = str(x)
3140+
return like in x
3141+
values = labels.map(f)
3142+
return self.loc(axis=axis)[values.values]
31333143
elif regex:
31343144
matcher = re.compile(regex)
3135-
return self.select(lambda x: matcher.search(str(x)) is not None,
3136-
axis=axis_name)
3145+
values = labels.map(lambda x: matcher.search(str(x)) is not None)
3146+
return self.loc(axis=axis)[values.values]
31373147
else:
31383148
raise TypeError('Must pass either `items`, `like`, or `regex`')
31393149

@@ -5756,7 +5766,7 @@ def _where(self, cond, other=np.nan, inplace=False, axis=None, level=None,
57565766
inplace = validate_bool_kwarg(inplace, 'inplace')
57575767

57585768
# align the cond to same shape as myself
5759-
cond = com._apply_if_callable(cond, self)
5769+
cond = com._apply_if_callable(cond, self, axis=axis)
57605770
if isinstance(cond, NDFrame):
57615771
cond, _ = cond.align(self, join='right', broadcast_axis=1)
57625772
else:
@@ -5997,7 +6007,7 @@ def _where(self, cond, other=np.nan, inplace=False, axis=None, level=None,
59976007
def where(self, cond, other=np.nan, inplace=False, axis=None, level=None,
59986008
try_cast=False, raise_on_error=True):
59996009

6000-
other = com._apply_if_callable(other, self)
6010+
other = com._apply_if_callable(other, self, axis=axis)
60016011
return self._where(cond, other, inplace, axis, level, try_cast,
60026012
raise_on_error)
60036013

@@ -6008,7 +6018,7 @@ def mask(self, cond, other=np.nan, inplace=False, axis=None, level=None,
60086018
try_cast=False, raise_on_error=True):
60096019

60106020
inplace = validate_bool_kwarg(inplace, 'inplace')
6011-
cond = com._apply_if_callable(cond, self)
6021+
cond = com._apply_if_callable(cond, self, axis=axis)
60126022

60136023
return self.where(~cond, other=other, inplace=inplace, axis=axis,
60146024
level=level, try_cast=try_cast,

0 commit comments

Comments
 (0)