-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
DEPR: remove Panel-specific parts of core.indexing #25567
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
Changes from 9 commits
c47d36f
6e485bd
348c595
451a967
63495a6
cc22e5f
bc505bc
f39a75f
c1c200e
fac9442
be19f78
26f2ac2
1de10b5
8d2ab43
496ab7d
29cde25
eaf161b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,7 @@ | |
from pandas.core.dtypes.common import ( | ||
ensure_platform_int, is_float, is_integer, is_integer_dtype, is_iterator, | ||
is_list_like, is_scalar, is_sequence, is_sparse) | ||
from pandas.core.dtypes.generic import ABCDataFrame, ABCPanel, ABCSeries | ||
from pandas.core.dtypes.generic import ABCDataFrame, ABCSeries | ||
from pandas.core.dtypes.missing import _infer_fill_value, isna | ||
|
||
import pandas.core.common as com | ||
|
@@ -453,10 +453,6 @@ def _setitem_with_indexer(self, indexer, value): | |
self.obj._maybe_update_cacher(clear=True) | ||
return self.obj | ||
|
||
# set using setitem (Panel and > dims) | ||
elif self.ndim >= 3: | ||
return self.obj.__setitem__(indexer, value) | ||
|
||
# set | ||
item_labels = self.obj._get_axis(info_axis) | ||
|
||
|
@@ -645,9 +641,6 @@ def can_do_equal_len(): | |
elif isinstance(value, ABCDataFrame): | ||
value = self._align_frame(indexer, value) | ||
|
||
if isinstance(value, ABCPanel): | ||
value = self._align_panel(indexer, value) | ||
|
||
# check for chained assignment | ||
self.obj._check_is_chained_assignment_possible() | ||
|
||
|
@@ -693,7 +686,6 @@ def ravel(i): | |
sum_aligners = sum(aligners) | ||
single_aligner = sum_aligners == 1 | ||
is_frame = self.obj.ndim == 2 | ||
is_panel = self.obj.ndim >= 3 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we are going to need a new error if self.obj.ndim.ndim > 2 (e.g. a numpy array); need to check both for setting & getting (it *might be already there but not sure about tests) |
||
obj = self.obj | ||
|
||
# are we a single alignable value on a non-primary | ||
|
@@ -705,11 +697,6 @@ def ravel(i): | |
if is_frame: | ||
single_aligner = single_aligner and aligners[0] | ||
|
||
# panel | ||
elif is_panel: | ||
single_aligner = (single_aligner and | ||
(aligners[1] or aligners[2])) | ||
|
||
# we have a frame, with multiple indexers on both axes; and a | ||
# series, so need to broadcast (see GH5206) | ||
if (sum_aligners == self.ndim and | ||
|
@@ -741,38 +728,14 @@ def ravel(i): | |
return ser.reindex(new_ix)._values | ||
|
||
# 2 dims | ||
elif single_aligner and is_frame: | ||
elif single_aligner: | ||
|
||
# reindex along index | ||
ax = self.obj.axes[1] | ||
if ser.index.equals(ax) or not len(ax): | ||
return ser._values.copy() | ||
return ser.reindex(ax)._values | ||
|
||
# >2 dims | ||
elif single_aligner: | ||
|
||
broadcast = [] | ||
for n, labels in enumerate(self.obj._get_plane_axes(i)): | ||
|
||
# reindex along the matching dimensions | ||
if len(labels & ser.index): | ||
ser = ser.reindex(labels) | ||
else: | ||
broadcast.append((n, len(labels))) | ||
|
||
# broadcast along other dims | ||
ser = ser._values.copy() | ||
for (axis, l) in broadcast: | ||
shape = [-1] * (len(broadcast) + 1) | ||
shape[axis] = l | ||
ser = np.tile(ser, l).reshape(shape) | ||
|
||
if self.obj.ndim == 3: | ||
ser = ser.T | ||
|
||
return ser | ||
|
||
elif is_scalar(indexer): | ||
ax = self.obj._get_axis(1) | ||
|
||
|
@@ -785,7 +748,6 @@ def ravel(i): | |
|
||
def _align_frame(self, indexer, df): | ||
is_frame = self.obj.ndim == 2 | ||
is_panel = self.obj.ndim >= 3 | ||
|
||
if isinstance(indexer, tuple): | ||
|
||
|
@@ -805,21 +767,6 @@ def _align_frame(self, indexer, df): | |
else: | ||
sindexers.append(i) | ||
|
||
# panel | ||
if is_panel: | ||
|
||
# need to conform to the convention | ||
# as we are not selecting on the items axis | ||
# and we have a single indexer | ||
# GH 7763 | ||
if len(sindexers) == 1 and sindexers[0] != 0: | ||
df = df.T | ||
|
||
if idx is None: | ||
idx = df.index | ||
if cols is None: | ||
cols = df.columns | ||
|
||
if idx is not None and cols is not None: | ||
|
||
if df.index.equals(idx) and df.columns.equals(cols): | ||
|
@@ -846,24 +793,8 @@ def _align_frame(self, indexer, df): | |
val = df.reindex(index=ax)._values | ||
return val | ||
|
||
elif is_scalar(indexer) and is_panel: | ||
idx = self.obj.axes[1] | ||
cols = self.obj.axes[2] | ||
|
||
# by definition we are indexing on the 0th axis | ||
# a passed in dataframe which is actually a transpose | ||
# of what is needed | ||
if idx.equals(df.index) and cols.equals(df.columns): | ||
return df.copy()._values | ||
|
||
return df.reindex(idx, columns=cols)._values | ||
|
||
raise ValueError('Incompatible indexer with DataFrame') | ||
|
||
def _align_panel(self, indexer, df): | ||
raise NotImplementedError("cannot set using an indexer with a Panel " | ||
"yet!") | ||
|
||
def _getitem_tuple(self, tup): | ||
try: | ||
return self._getitem_lowerdim(tup) | ||
|
@@ -1056,13 +987,6 @@ def _getitem_nested_tuple(self, tup): | |
# has the dim of the obj changed? | ||
# GH 7199 | ||
if obj.ndim < current_ndim: | ||
|
||
# GH 7516 | ||
# if had a 3 dim and are going to a 2d | ||
# axes are reversed on a DataFrame | ||
if i >= 1 and current_ndim == 3 and obj.ndim == 2: | ||
obj = obj.T | ||
|
||
axis -= 1 | ||
|
||
return obj | ||
|
@@ -1559,8 +1483,8 @@ class _LocIndexer(_LocationIndexer): | |
|
||
- A boolean array of the same length as the axis being sliced, | ||
e.g. ``[True, False, True]``. | ||
- A ``callable`` function with one argument (the calling Series, DataFrame | ||
or Panel) and that returns valid output for indexing (one of the above) | ||
- A ``callable`` function with one argument (the calling Series or | ||
DataFrame) and that returns valid output for indexing (one of the above) | ||
|
||
See more at :ref:`Selection by Label <indexing.label>` | ||
|
||
|
@@ -1929,8 +1853,8 @@ class _iLocIndexer(_LocationIndexer): | |
- A list or array of integers, e.g. ``[4, 3, 0]``. | ||
- A slice object with ints, e.g. ``1:7``. | ||
- A boolean array. | ||
- A ``callable`` function with one argument (the calling Series, DataFrame | ||
or Panel) and that returns valid output for indexing (one of the above). | ||
- A ``callable`` function with one argument (the calling Series or | ||
DataFrame) and that returns valid output for indexing (one of the above). | ||
This is useful in method chains, when you don't have a reference to the | ||
calling object, but would like to base your selection on some value. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,8 @@ | |
from pandas.tests.indexing.common import Base, _mklbl | ||
import pandas.util.testing as tm | ||
|
||
ignore_ix = pytest.mark.filterwarnings("ignore:\\n.ix:DeprecationWarning") | ||
|
||
# ------------------------------------------------------------------------ | ||
# Indexing test cases | ||
|
||
|
@@ -58,6 +60,93 @@ def test_setitem_ndarray_1d(self): | |
with pytest.raises(ValueError): | ||
df[2:5] = np.arange(1, 4) * 1j | ||
|
||
@pytest.mark.parametrize('index', tm.all_index_generator(5), | ||
ids=lambda x: type(x).__name__) | ||
@pytest.mark.parametrize('obj', [ | ||
lambda i: Series(np.arange(len(i)), index=i), | ||
lambda i: DataFrame( | ||
np.random.randn(len(i), len(i)), index=i, columns=i) | ||
], ids=['Series', 'DataFrame']) | ||
@pytest.mark.parametrize('idxr, idxr_id', [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. might be worth making these a fixture at somepoint (the iteration over indexers) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
yeah. i appreciate we have duplication of parameterization at the moment, and fixtures may be of use. didn't carry on down that route at the moment as i wasn't sure if these tests were what was required. separately for iteration over the indexes: xref #25748 (comment). There is a |
||
(lambda x: x, 'getitem'), | ||
(lambda x: x.loc, 'loc'), | ||
(lambda x: x.iloc, 'iloc'), | ||
pytest.param(lambda x: x.ix, 'ix', marks=ignore_ix) | ||
]) | ||
def test_getitem_ndarray_3d(self, index, obj, idxr, idxr_id): | ||
# GH 25567 | ||
obj = obj(index) | ||
idxr = idxr(obj) | ||
nd3 = np.random.randint(5, size=(2, 2, 2)) | ||
|
||
msg = (r"Buffer has wrong number of dimensions \(expected 1," | ||
r" got 3\)|" | ||
"The truth value of an array with more than one element is" | ||
" ambiguous|" | ||
"Cannot index with multidimensional key|" | ||
r"Wrong number of dimensions. values.ndim != ndim \[3 != 1\]|" | ||
"unhashable type: 'numpy.ndarray'" # TypeError | ||
) | ||
|
||
if (isinstance(obj, Series) and idxr_id == 'getitem' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ugg this is why getitem is so complicated. |
||
and index.inferred_type in [ | ||
'string', 'datetime64', 'period', 'timedelta64', | ||
'boolean', 'categorical']): | ||
idxr[nd3] | ||
else: | ||
if (isinstance(obj, DataFrame) and idxr_id == 'getitem' | ||
and index.inferred_type == 'boolean'): | ||
error = TypeError | ||
else: | ||
error = ValueError | ||
|
||
with pytest.raises(error, match=msg): | ||
idxr[nd3] | ||
|
||
@pytest.mark.parametrize('index', tm.all_index_generator(5), | ||
ids=lambda x: type(x).__name__) | ||
@pytest.mark.parametrize('obj', [ | ||
lambda i: Series(np.arange(len(i)), index=i), | ||
lambda i: DataFrame( | ||
np.random.randn(len(i), len(i)), index=i, columns=i) | ||
], ids=['Series', 'DataFrame']) | ||
@pytest.mark.parametrize('idxr, idxr_id', [ | ||
(lambda x: x, 'setitem'), | ||
(lambda x: x.loc, 'loc'), | ||
(lambda x: x.iloc, 'iloc'), | ||
pytest.param(lambda x: x.ix, 'ix', marks=ignore_ix) | ||
]) | ||
def test_setitem_ndarray_3d(self, index, obj, idxr, idxr_id): | ||
# GH 25567 | ||
obj = obj(index) | ||
idxr = idxr(obj) | ||
nd3 = np.random.randint(5, size=(2, 2, 2)) | ||
|
||
msg = (r"Buffer has wrong number of dimensions \(expected 1," | ||
r" got 3\)|" | ||
"The truth value of an array with more than one element is" | ||
" ambiguous|" | ||
"Only 1-dimensional input arrays are supported|" | ||
"'pandas._libs.interval.IntervalTree' object has no attribute" | ||
" 'set_value'|" # AttributeError | ||
"unhashable type: 'numpy.ndarray'|" # TypeError | ||
r"^\[\[\[" # pandas.core.indexing.IndexingError | ||
) | ||
|
||
if ((idxr_id == 'iloc') | ||
or ((isinstance(obj, Series) and idxr_id == 'setitem' | ||
and index.inferred_type in [ | ||
'floating', 'string', 'datetime64', 'period', 'timedelta64', | ||
'boolean', 'categorical'])) | ||
or (idxr_id == 'ix' and index.inferred_type in [ | ||
'string', 'datetime64', 'period', 'boolean'])): | ||
idxr[nd3] = 0 | ||
else: | ||
with pytest.raises( | ||
(ValueError, AttributeError, TypeError, | ||
pd.core.indexing.IndexingError), match=msg): | ||
idxr[nd3] = 0 | ||
|
||
def test_inf_upcast(self): | ||
# GH 16957 | ||
# We should be able to use np.inf as a key | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this ever raised in user code? what happens when a 3-d indexer is passed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add some sort of test for this (also this should raise a ValueError if its user code)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added some tests for 3d indexing (integer ndarray only at the moment). not sure if this was what was required. tests is messy with mixture of some getting and setting not raising and those that raise produce a range of error messages.
will look into this next.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since NDFrame is not part of the API, i'm not sure how this can be raised from user code. (other than Panel)
i've added a test for NDFrame initialized with 3d array, but it only raises this exception with
.ix