From 721eaaf134daef7a411c53c9b6107a20d422c0c2 Mon Sep 17 00:00:00 2001 From: Chang She Date: Mon, 21 May 2012 21:59:59 -0400 Subject: [PATCH] ENH: pct change for Series and DataFrame #1271 --- pandas/core/generic.py | 27 +++++++++++++++++++++++++++ pandas/core/series.py | 2 +- pandas/tests/test_frame.py | 17 +++++++++++++++++ pandas/tests/test_series.py | 16 ++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 1ce05f852dedd..ffb608bed7885 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -367,6 +367,33 @@ def tshift(self, periods=1, freq=None, **kwds): return self.shift(periods, freq, **kwds) + def pct_change(self, periods=1, fill_method='pad', limit=None, freq=None, + **kwds): + """ + Percent change over given number of periods + + Parameters + ---------- + periods : int, default 1 + Periods to shift for forming percent change + fill_method : str, default 'pad' + How to handle NAs before computing percent changes + limit : int, default None + The number of consecutive NAs to fill before stopping + freq : DateOffset, timedelta, or offset alias string, optional + Increment to use from time series API (e.g. 'M' or BDay()) + + Returns + ------- + chg : Series or DataFrame + """ + if fill_method is None: + data = self + else: + data = self.fillna(method=fill_method, limit=limit) + rs = data / data.shift(periods=periods, freq=freq, **kwds) - 1 + return rs + class NDFrame(PandasObject): """ diff --git a/pandas/core/series.py b/pandas/core/series.py index d50b74f518b19..46122cf018023 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -2345,7 +2345,7 @@ def shift(self, periods=1, freq=None, **kwds): ---------- periods : int Number of periods to move, can be positive or negative - freq : DateOffset, timedelta, or time rule string, optional + freq : DateOffset, timedelta, or offset alias string, optional Increment to use from datetools module or time rule (e.g. 'EOM') Returns diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 23c380396ddf7..8dc82b5936fde 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -4116,6 +4116,23 @@ def test_diff(self): assert_series_equal(the_diff['A'], self.tsframe['A'] - self.tsframe['A'].shift(1)) + def test_pct_change(self): + rs = self.tsframe.pct_change(fill_method=None) + assert_frame_equal(rs, self.tsframe / self.tsframe.shift(1) - 1) + + rs = self.tsframe.pct_change(2) + filled = self.tsframe.fillna(method='pad') + assert_frame_equal(rs, filled / filled.shift(2) - 1) + + rs = self.tsframe.pct_change(fill_method='bfill', limit=1) + filled = self.tsframe.fillna(method='bfill', limit=1) + assert_frame_equal(rs, filled / filled.shift(1) - 1) + + rs = self.tsframe.pct_change(freq='M') + filled = self.tsframe.fillna(method='pad') + assert_frame_equal(rs, filled / filled.shift(freq='M') - 1) + + def test_shift(self): # naive shift shiftedFrame = self.tsframe.shift(5) diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index 011bd0de9932c..6a9f262720d5e 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -2596,6 +2596,22 @@ def test_diff(self): # Just run the function self.ts.diff() + def test_pct_change(self): + rs = self.ts.pct_change(fill_method=None) + assert_series_equal(rs, self.ts / self.ts.shift(1) - 1) + + rs = self.ts.pct_change(2) + filled = self.ts.fillna(method='pad') + assert_series_equal(rs, filled / filled.shift(2) - 1) + + rs = self.ts.pct_change(fill_method='bfill', limit=1) + filled = self.ts.fillna(method='bfill', limit=1) + assert_series_equal(rs, filled / filled.shift(1) - 1) + + rs = self.ts.pct_change(freq='M') + filled = self.ts.fillna(method='pad') + assert_series_equal(rs, filled / filled.shift(freq='M') - 1) + def test_autocorr(self): # Just run the function self.ts.autocorr()