Skip to content

Commit 2c83a97

Browse files
author
Tom Augspurger
committed
Merge pull request #6909 from TomAugspurger/panel_shift
ENH: Implement Panel pct_change
2 parents 8b2defa + ee61d65 commit 2c83a97

File tree

7 files changed

+85
-10
lines changed

7 files changed

+85
-10
lines changed

doc/source/computation.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ Statistical functions
2626
Percent Change
2727
~~~~~~~~~~~~~~
2828

29-
Both ``Series`` and ``DataFrame`` has a method ``pct_change`` to compute the
29+
``Series``, ``DataFrame``, and ``Panel`` all have a method ``pct_change`` to compute the
3030
percent change over a given number of periods (using ``fill_method`` to fill
31-
NA/null values).
31+
NA/null values *before* computing the percent change).
3232

3333
.. ipython:: python
3434

doc/source/release.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ New features
6363
noon, January 1, 4713 BC. Because nanoseconds are used to define the time
6464
in pandas the actual range of dates that you can use is 1678 AD to 2262 AD. (:issue:`4041`)
6565
- Added error bar support to the ``.plot`` method of ``DataFrame`` and ``Series`` (:issue:`3796`)
66-
66+
- Implemented ``Panel.pct_change`` (:issue:`6904`)
6767

6868
API Changes
6969
~~~~~~~~~~~

doc/source/v0.14.0.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ Enhancements
470470
- :ref:`Holidays Calendars<timeseries.holiday>` are now available and can be used with CustomBusinessDay (:issue:`6719`)
471471
- ``Float64Index`` is now backed by a ``float64`` dtype ndarray instead of an
472472
``object`` dtype array (:issue:`6471`).
473+
- Implemented ``Panel.pct_change`` (:issue:`6904`)
473474

474475
Performance
475476
~~~~~~~~~~~

pandas/core/generic.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3455,10 +3455,8 @@ def _convert_timedeltas(x):
34553455

34563456
return np.abs(self)
34573457

3458-
def pct_change(self, periods=1, fill_method='pad', limit=None, freq=None,
3459-
**kwds):
3460-
"""
3461-
Percent change over given number of periods
3458+
_shared_docs['pct_change'] = """
3459+
Percent change over given number of periods.
34623460
34633461
Parameters
34643462
----------
@@ -3473,14 +3471,27 @@ def pct_change(self, periods=1, fill_method='pad', limit=None, freq=None,
34733471
34743472
Returns
34753473
-------
3476-
chg : same type as caller
3474+
chg : %(klass)s
3475+
3476+
Notes
3477+
-----
3478+
3479+
By default, the percentage change is calculated along the stat
3480+
axis: 0, or ``Index``, for ``DataFrame`` and 1, or ``minor`` for
3481+
``Panel``. You can change this with the ``axis`` keyword argument.
34773482
"""
3483+
3484+
@Appender(_shared_docs['pct_change'] % _shared_doc_kwargs)
3485+
def pct_change(self, periods=1, fill_method='pad', limit=None, freq=None,
3486+
**kwds):
34783487
# TODO: Not sure if above is correct - need someone to confirm.
3488+
axis = self._get_axis_number(kwds.pop('axis', self._stat_axis_name))
34793489
if fill_method is None:
34803490
data = self
34813491
else:
34823492
data = self.fillna(method=fill_method, limit=limit)
3483-
rs = data / data.shift(periods=periods, freq=freq, **kwds) - 1
3493+
3494+
rs = data.div(data.shift(periods, freq=freq, axis=axis, **kwds)) - 1
34843495
if freq is None:
34853496
mask = com.isnull(_values_from_object(self))
34863497
np.putmask(rs.values, mask, np.nan)

pandas/core/panel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,7 @@ def count(self, axis='major'):
11161116

11171117
def shift(self, lags, freq=None, axis='major'):
11181118
"""
1119-
Shift major or minor axis by specified number of leads/lags.
1119+
Shift major or minor axis by specified number of leads/lags.
11201120
11211121
Parameters
11221122
----------

pandas/tests/test_panel.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,60 @@ def test_tshift(self):
16841684
no_freq = panel.ix[:, [0, 5, 7], :]
16851685
self.assertRaises(ValueError, no_freq.tshift)
16861686

1687+
def test_pct_change(self):
1688+
df1 = DataFrame({'c1': [1, 2, 5], 'c2': [3, 4, 6]})
1689+
df2 = df1 + 1
1690+
df3 = DataFrame({'c1': [3, 4, 7], 'c2': [5, 6, 8]})
1691+
wp = Panel({'i1': df1, 'i2': df2, 'i3': df3})
1692+
# major, 1
1693+
result = wp.pct_change() # axis='major'
1694+
expected = Panel({'i1': df1.pct_change(),
1695+
'i2': df2.pct_change(),
1696+
'i3': df3.pct_change()})
1697+
assert_panel_equal(result, expected)
1698+
result = wp.pct_change(axis=1)
1699+
assert_panel_equal(result, expected)
1700+
# major, 2
1701+
result = wp.pct_change(periods=2)
1702+
expected = Panel({'i1': df1.pct_change(2),
1703+
'i2': df2.pct_change(2),
1704+
'i3': df3.pct_change(2)})
1705+
assert_panel_equal(result, expected)
1706+
# minor, 1
1707+
result = wp.pct_change(axis='minor')
1708+
expected = Panel({'i1': df1.pct_change(axis=1),
1709+
'i2': df2.pct_change(axis=1),
1710+
'i3': df3.pct_change(axis=1)})
1711+
assert_panel_equal(result, expected)
1712+
result = wp.pct_change(axis=2)
1713+
assert_panel_equal(result, expected)
1714+
# minor, 2
1715+
result = wp.pct_change(periods=2, axis='minor')
1716+
expected = Panel({'i1': df1.pct_change(periods=2, axis=1),
1717+
'i2': df2.pct_change(periods=2, axis=1),
1718+
'i3': df3.pct_change(periods=2, axis=1)})
1719+
assert_panel_equal(result, expected)
1720+
# items, 1
1721+
result = wp.pct_change(axis='items')
1722+
expected = Panel({'i1': DataFrame({'c1': [np.nan, np.nan, np.nan],
1723+
'c2': [np.nan, np.nan, np.nan]}),
1724+
'i2': DataFrame({'c1': [1, 0.5, .2],
1725+
'c2': [1./3, 0.25, 1./6]}),
1726+
'i3': DataFrame({'c1': [.5, 1./3, 1./6],
1727+
'c2': [.25, .2, 1./7]})})
1728+
assert_panel_equal(result, expected)
1729+
result = wp.pct_change(axis=0)
1730+
assert_panel_equal(result, expected)
1731+
# items, 2
1732+
result = wp.pct_change(periods=2, axis='items')
1733+
expected = Panel({'i1': DataFrame({'c1': [np.nan, np.nan, np.nan],
1734+
'c2': [np.nan, np.nan, np.nan]}),
1735+
'i2': DataFrame({'c1': [np.nan, np.nan, np.nan],
1736+
'c2': [np.nan, np.nan, np.nan]}),
1737+
'i3': DataFrame({'c1': [2, 1, .4],
1738+
'c2': [2./3, .5, 1./3]})})
1739+
assert_panel_equal(result, expected)
1740+
16871741
def test_multiindex_get(self):
16881742
ind = MultiIndex.from_tuples([('a', 1), ('a', 2), ('b', 1), ('b', 2)],
16891743
names=['first', 'second'])

vb_suite/panel_methods.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,12 @@
1717

1818
panel_shift_minor = Benchmark('panel.shift(1, axis=minor)', setup,
1919
start_date=datetime(2012, 1, 12))
20+
21+
panel_pct_change_major = Benchmark('panel.pct_change(1, axis="major")', setup,
22+
start_date=datetime(2014, 4, 19))
23+
24+
panel_pct_change_minor = Benchmark('panel.pct_change(1, axis="minor")', setup,
25+
start_date=datetime(2014, 4, 19))
26+
27+
panel_pct_change_items = Benchmark('panel.pct_change(1, axis="items")', setup,
28+
start_date=datetime(2014, 4, 19))

0 commit comments

Comments
 (0)