Skip to content

Commit

Permalink
DEPR: Panel deprecated
Browse files Browse the repository at this point in the history
  • Loading branch information
jreback committed Mar 7, 2017
1 parent a347ecb commit 6ceea8a
Show file tree
Hide file tree
Showing 8 changed files with 2,056 additions and 1,836 deletions.
28 changes: 28 additions & 0 deletions doc/source/whatsnew/v0.20.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Highlights include:

- Building pandas for development now requires ``cython >= 0.23`` (:issue:`14831`)
- The ``.ix`` indexer has been deprecated, see :ref:`here <whatsnew_0200.api_breaking.deprecate_ix>`
- ``Panel`` has been deprecated, see :ref:`here <whatsnew_0200.api_breaking.deprecate_panel>`
- Switched the test framework to `pytest`_ (:issue:`13097`)
- A new orient for JSON serialization, ``orient='table'``, that uses the Table Schema spec, see :ref: `here <whatsnew_0200.enhancements.table_schema>`

Expand Down Expand Up @@ -284,6 +285,33 @@ Using ``.iloc``. Here we will get the location of the 'A' column, then use *posi
df.iloc[[0, 2], df.columns.get_loc('A')]


.. _whatsnew_0200.api_breaking.deprecate_panel:

Deprecate Panel
^^^^^^^^^^^^^^^

- The ``Panel`` constructor is deprecated and will be removed in a future version. The recommended way to represent 3-D data are
with a ``MultiIndex``on a ``DataFrame`` via the :meth:`~Panel.to_frame` or with the `xarray package <http://xarray.pydata.org/en/stable/>`__. Pandas
provides a :meth:`~Panel.to_xarray` method to automate this conversion (:issue:`13563`).

.. ipython:: python
:okwarning:

p = tm.makePanel()
p

Convert to a MultiIndex DataFrame

.. ipython:: python

p.frame()

Convert to an xarray DataArray

.. ipython:: python

p.to_xarray()

.. _whatsnew.api_breaking.io_compat

Possible incompat for HDF5 formats for pandas < 0.13.0
Expand Down
12 changes: 12 additions & 0 deletions pandas/core/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@ def _constructor(self):

def __init__(self, data=None, items=None, major_axis=None, minor_axis=None,
copy=False, dtype=None):
# deprecation GH13563
warnings.warn("\nPanel is deprecated and will be removed in a "
"future version.\nThe recommended way to represent "
"these types of 3-dimensional data are with a "
"MultiIndex on a DataFrame, via the "
"Panel.to_frame() method\n"
"alternatively, you can use the `xarray package "
"<http://xarray.pydata.org/en/stable/>`__.\n"
"Pandas provides a `.to_xarray()` method to help "
"automate this conversion.\n",
FutureWarning, stacklevel=3)

self._init_data(data=data, items=items, major_axis=major_axis,
minor_axis=minor_axis, copy=copy, dtype=dtype)

Expand Down
171 changes: 95 additions & 76 deletions pandas/tests/test_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

from operator import methodcaller
from copy import copy, deepcopy
from warnings import catch_warnings

import pytest
import numpy as np
from numpy import nan
Expand Down Expand Up @@ -1570,17 +1572,18 @@ def test_to_xarray(self):
tm._skip_if_no_xarray()
from xarray import DataArray

p = tm.makePanel()
with catch_warnings(record=True):
p = tm.makePanel()

result = p.to_xarray()
self.assertIsInstance(result, DataArray)
self.assertEqual(len(result.coords), 3)
assert_almost_equal(list(result.coords.keys()),
['items', 'major_axis', 'minor_axis'])
self.assertEqual(len(result.dims), 3)
result = p.to_xarray()
self.assertIsInstance(result, DataArray)
self.assertEqual(len(result.coords), 3)
assert_almost_equal(list(result.coords.keys()),
['items', 'major_axis', 'minor_axis'])
self.assertEqual(len(result.dims), 3)

# idempotency
assert_panel_equal(result.to_pandas(), p)
# idempotency
assert_panel_equal(result.to_pandas(), p)


class TestPanel4D(tm.TestCase, Generic):
Expand All @@ -1590,15 +1593,12 @@ class TestPanel4D(tm.TestCase, Generic):
def test_sample(self):
pytest.skip("sample on Panel4D")

def test_copy_and_deepcopy(self):
pytest.skip("copy_and_deepcopy on Panel4D")

def test_to_xarray(self):

tm._skip_if_no_xarray()
from xarray import DataArray

with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
with catch_warnings(record=True):
p = tm.makePanel4D()

result = p.to_xarray()
Expand All @@ -1624,12 +1624,20 @@ def test_to_xarray(self):
'test_stat_unexpected_keyword', 'test_api_compat',
'test_stat_non_defaults_args',
'test_clip', 'test_truncate_out_of_bounds', 'test_numpy_clip',
'test_metadata_propagation']:
'test_metadata_propagation', 'test_copy_and_deepcopy',
'test_sample']:

def f():
def tester(self):
with catch_warnings(record=True):
return getattr(super(TestPanel, self), t)()
return tester

setattr(TestPanel, t, f())

def f():
def tester(self):
with tm.assert_produces_warning(FutureWarning,
check_stacklevel=False):
with catch_warnings(record=True):
return getattr(super(TestPanel4D, self), t)()
return tester

Expand Down Expand Up @@ -1660,10 +1668,11 @@ def test_sample(sel):
with tm.assertRaises(ValueError):
s.sample(n=3, weights='weight_column')

panel = pd.Panel(items=[0, 1, 2], major_axis=[2, 3, 4],
minor_axis=[3, 4, 5])
with tm.assertRaises(ValueError):
panel.sample(n=1, weights='weight_column')
with catch_warnings(record=True):
panel = Panel(items=[0, 1, 2], major_axis=[2, 3, 4],
minor_axis=[3, 4, 5])
with tm.assertRaises(ValueError):
panel.sample(n=1, weights='weight_column')

with tm.assertRaises(ValueError):
df.sample(n=1, weights='weight_column', axis=1)
Expand Down Expand Up @@ -1726,14 +1735,15 @@ def test_sample(sel):
assert_frame_equal(sample1, df[['colString']])

# Test default axes
p = pd.Panel(items=['a', 'b', 'c'], major_axis=[2, 4, 6],
minor_axis=[1, 3, 5])
assert_panel_equal(
p.sample(n=3, random_state=42), p.sample(n=3, axis=1,
random_state=42))
assert_frame_equal(
df.sample(n=3, random_state=42), df.sample(n=3, axis=0,
random_state=42))
with catch_warnings(record=True):
p = Panel(items=['a', 'b', 'c'], major_axis=[2, 4, 6],
minor_axis=[1, 3, 5])
assert_panel_equal(
p.sample(n=3, random_state=42), p.sample(n=3, axis=1,
random_state=42))
assert_frame_equal(
df.sample(n=3, random_state=42), df.sample(n=3, axis=0,
random_state=42))

# Test that function aligns weights with frame
df = DataFrame(
Expand Down Expand Up @@ -1763,34 +1773,37 @@ def test_squeeze(self):
tm.assert_series_equal(s.squeeze(), s)
for df in [tm.makeTimeDataFrame()]:
tm.assert_frame_equal(df.squeeze(), df)
for p in [tm.makePanel()]:
tm.assert_panel_equal(p.squeeze(), p)
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
with catch_warnings(record=True):
for p in [tm.makePanel()]:
tm.assert_panel_equal(p.squeeze(), p)
with catch_warnings(record=True):
for p4d in [tm.makePanel4D()]:
tm.assert_panel4d_equal(p4d.squeeze(), p4d)

# squeezing
df = tm.makeTimeDataFrame().reindex(columns=['A'])
tm.assert_series_equal(df.squeeze(), df['A'])

p = tm.makePanel().reindex(items=['ItemA'])
tm.assert_frame_equal(p.squeeze(), p['ItemA'])
with catch_warnings(record=True):
p = tm.makePanel().reindex(items=['ItemA'])
tm.assert_frame_equal(p.squeeze(), p['ItemA'])

p = tm.makePanel().reindex(items=['ItemA'], minor_axis=['A'])
tm.assert_series_equal(p.squeeze(), p.loc['ItemA', :, 'A'])
p = tm.makePanel().reindex(items=['ItemA'], minor_axis=['A'])
tm.assert_series_equal(p.squeeze(), p.loc['ItemA', :, 'A'])

with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
with catch_warnings(record=True):
p4d = tm.makePanel4D().reindex(labels=['label1'])
tm.assert_panel_equal(p4d.squeeze(), p4d['label1'])

with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
with catch_warnings(record=True):
p4d = tm.makePanel4D().reindex(labels=['label1'], items=['ItemA'])
tm.assert_frame_equal(p4d.squeeze(), p4d.loc['label1', 'ItemA'])

# don't fail with 0 length dimensions GH11229 & GH8999
empty_series = pd.Series([], name='five')
empty_frame = pd.DataFrame([empty_series])
empty_panel = pd.Panel({'six': empty_frame})
empty_series = Series([], name='five')
empty_frame = DataFrame([empty_series])
with catch_warnings(record=True):
empty_panel = Panel({'six': empty_frame})

[tm.assert_series_equal(empty_series, higher_dim.squeeze())
for higher_dim in [empty_series, empty_frame, empty_panel]]
Expand Down Expand Up @@ -1825,13 +1838,15 @@ def test_transpose(self):
tm.assert_series_equal(s.transpose(), s)
for df in [tm.makeTimeDataFrame()]:
tm.assert_frame_equal(df.transpose().transpose(), df)
for p in [tm.makePanel()]:
tm.assert_panel_equal(p.transpose(2, 0, 1)
.transpose(1, 2, 0), p)
tm.assertRaisesRegexp(TypeError, msg, p.transpose,
2, 0, 1, axes=(2, 0, 1))

with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
with catch_warnings(record=True):
for p in [tm.makePanel()]:
tm.assert_panel_equal(p.transpose(2, 0, 1)
.transpose(1, 2, 0), p)
tm.assertRaisesRegexp(TypeError, msg, p.transpose,
2, 0, 1, axes=(2, 0, 1))

with catch_warnings(record=True):
for p4d in [tm.makePanel4D()]:
tm.assert_panel4d_equal(p4d.transpose(2, 0, 3, 1)
.transpose(1, 3, 0, 2), p4d)
Expand All @@ -1853,12 +1868,13 @@ def test_numpy_transpose(self):
tm.assertRaisesRegexp(ValueError, msg,
np.transpose, df, axes=1)

p = tm.makePanel()
tm.assert_panel_equal(np.transpose(
np.transpose(p, axes=(2, 0, 1)),
axes=(1, 2, 0)), p)
with catch_warnings(record=True):
p = tm.makePanel()
tm.assert_panel_equal(np.transpose(
np.transpose(p, axes=(2, 0, 1)),
axes=(1, 2, 0)), p)

with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
with catch_warnings(record=True):
p4d = tm.makePanel4D()
tm.assert_panel4d_equal(np.transpose(
np.transpose(p4d, axes=(2, 0, 3, 1)),
Expand All @@ -1880,15 +1896,16 @@ def test_take(self):
tm.assert_frame_equal(out, expected)

indices = [-3, 2, 0, 1]
for p in [tm.makePanel()]:
out = p.take(indices)
expected = Panel(data=p.values.take(indices, axis=0),
items=p.items.take(indices),
major_axis=p.major_axis,
minor_axis=p.minor_axis)
tm.assert_panel_equal(out, expected)

with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
with catch_warnings(record=True):
for p in [tm.makePanel()]:
out = p.take(indices)
expected = Panel(data=p.values.take(indices, axis=0),
items=p.items.take(indices),
major_axis=p.major_axis,
minor_axis=p.minor_axis)
tm.assert_panel_equal(out, expected)

with catch_warnings(record=True):
for p4d in [tm.makePanel4D()]:
out = p4d.take(indices)
expected = Panel4D(data=p4d.values.take(indices, axis=0),
Expand All @@ -1902,9 +1919,9 @@ def test_take_invalid_kwargs(self):
indices = [-3, 2, 0, 1]
s = tm.makeFloatSeries()
df = tm.makeTimeDataFrame()
p = tm.makePanel()

with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
with catch_warnings(record=True):
p = tm.makePanel()
p4d = tm.makePanel4D()

for obj in (s, df, p, p4d):
Expand Down Expand Up @@ -2011,8 +2028,9 @@ def test_equals(self):
self.assertTrue(e.equals(f))

def test_describe_raises(self):
with tm.assertRaises(NotImplementedError):
tm.makePanel().describe()
with catch_warnings(record=True):
with tm.assertRaises(NotImplementedError):
tm.makePanel().describe()

def test_pipe(self):
df = DataFrame({'A': [1, 2, 3]})
Expand Down Expand Up @@ -2043,15 +2061,16 @@ def test_pipe_tuple_error(self):
df.A.pipe((f, 'y'), x=1, y=0)

def test_pipe_panel(self):
wp = Panel({'r1': DataFrame({"A": [1, 2, 3]})})
f = lambda x, y: x + y
result = wp.pipe(f, 2)
expected = wp + 2
assert_panel_equal(result, expected)

result = wp.pipe((f, 'y'), x=1)
expected = wp + 1
assert_panel_equal(result, expected)

with tm.assertRaises(ValueError):
result = wp.pipe((f, 'y'), x=1, y=1)
with catch_warnings(record=True):
wp = Panel({'r1': DataFrame({"A": [1, 2, 3]})})
f = lambda x, y: x + y
result = wp.pipe(f, 2)
expected = wp + 2
assert_panel_equal(result, expected)

result = wp.pipe((f, 'y'), x=1)
expected = wp + 1
assert_panel_equal(result, expected)

with tm.assertRaises(ValueError):
result = wp.pipe((f, 'y'), x=1, y=1)
Loading

0 comments on commit 6ceea8a

Please sign in to comment.