Skip to content

Commit 95ff747

Browse files
committed
Merge pull-request #4642 from prossahl/AHLRAP-3063-01
BUG/ER: Stricter testing of 'monotocity' when reindexing with ffill (GH4483)
2 parents 2aa52c9 + 58a0fc3 commit 95ff747

File tree

6 files changed

+40
-8
lines changed

6 files changed

+40
-8
lines changed

doc/source/basics.rst

+4-3
Original file line numberDiff line numberDiff line change
@@ -781,16 +781,17 @@ We illustrate these fill methods on a simple TimeSeries:
781781
ts2.reindex(ts.index, method='ffill')
782782
ts2.reindex(ts.index, method='bfill')
783783
784+
Note these methods require that the indexes are **order increasing**.
785+
784786
Note the same result could have been achieved using :ref:`fillna
785787
<missing_data.fillna>`:
786788

787789
.. ipython:: python
788790
789791
ts2.reindex(ts.index).fillna(method='ffill')
790792
791-
Note these methods generally assume that the indexes are **sorted**. They may
792-
be modified in the future to be a bit more flexible but as time series data is
793-
ordered most of the time anyway, this has not been a major priority.
793+
Note that ``reindex`` will raise a ValueError if the index is not
794+
monotonic. ``fillna`` will not make any checks on the order of the index.
794795

795796
.. _basics.drop:
796797

doc/source/missing_data.rst

+6
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ To remind you, these are the available filling methods:
205205
With time series data, using pad/ffill is extremely common so that the "last
206206
known value" is available at every time point.
207207

208+
The ``ffill()`` function is equivalent to ``fillna(method='ffill')``
209+
and ``bfill()`` is equivalent to ``fillna(method='bfill')``
210+
211+
.. _missing_data.PandasObject:
212+
208213
Filling with a PandasObject
209214
~~~~~~~~~~~~~~~~~~~~~~~~~~~
210215

@@ -234,6 +239,7 @@ a Series in this case.
234239
235240
dff.where(notnull(dff),dff.mean(),axis='columns')
236241
242+
237243
.. _missing_data.dropna:
238244

239245
Dropping axis labels with missing data: dropna

doc/source/release.rst

+2
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ Improvements to existing features
124124
API Changes
125125
~~~~~~~~~~~
126126

127+
- ``DataFrame.reindex()`` and forward/backward filling now raises ValueError
128+
if either index is not monotonic (:issue: `4483`, :issue: `4484`).
127129
- ``pandas`` now is Python 2/3 compatible without the need for 2to3 thanks to
128130
@jtratner. As a result, pandas now uses iterators more extensively. This
129131
also led to the introduction of substantive parts of the Benjamin

pandas/core/index.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -924,12 +924,12 @@ def get_indexer(self, target, method=None, limit=None):
924924
' valued Index objects')
925925

926926
if method == 'pad':
927-
if not self.is_monotonic:
928-
raise AssertionError('Must be monotonic for forward fill')
927+
if not self.is_monotonic or not target.is_monotonic:
928+
raise ValueError('Must be monotonic for forward fill')
929929
indexer = self._engine.get_pad_indexer(target.values, limit)
930930
elif method == 'backfill':
931-
if not self.is_monotonic:
932-
raise AssertionError('Must be monotonic for backward fill')
931+
if not self.is_monotonic or not target.is_monotonic:
932+
raise ValueError('Must be monotonic for backward fill')
933933
indexer = self._engine.get_backfill_indexer(target.values, limit)
934934
elif method is None:
935935
indexer = self._engine.get_indexer(target.values)

pandas/tests/test_frame.py

+23
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,29 @@ def test_nested_exception(self):
16821682
except Exception as e:
16831683
self.assertNotEqual(type(e), UnboundLocalError)
16841684

1685+
def test_reverse_reindex_ffill_raises(self):
1686+
dr = pd.date_range('2013-08-01', periods=6, freq='B')
1687+
data = np.random.randn(6,1)
1688+
df = pd.DataFrame(data, index=dr, columns=list('A'))
1689+
df['A'][3] = np.nan
1690+
df_rev = pd.DataFrame(data, index=dr[::-1], columns=list('A'))
1691+
# Reverse index is not 'monotonic'
1692+
self.assertRaises(ValueError, df_rev.reindex, df.index, method='pad')
1693+
self.assertRaises(ValueError, df_rev.reindex, df.index, method='ffill')
1694+
self.assertRaises(ValueError, df_rev.reindex, df.index, method='bfill')
1695+
1696+
def test_reversed_reindex_ffill_raises(self):
1697+
dr = pd.date_range('2013-08-01', periods=6, freq='B')
1698+
data = np.random.randn(6,1)
1699+
df = pd.DataFrame(data, index=dr, columns=list('A'))
1700+
df['A'][3] = np.nan
1701+
df = pd.DataFrame(data, index=dr, columns=list('A'))
1702+
# Reversed reindex is not 'monotonic'
1703+
self.assertRaises(ValueError, df.reindex, dr[::-1], method='pad')
1704+
self.assertRaises(ValueError, df.reindex, dr[::-1], method='ffill')
1705+
self.assertRaises(ValueError, df.reindex, dr[::-1], method='bfill')
1706+
1707+
16851708
_seriesd = tm.getSeriesData()
16861709
_tsd = tm.getTimeSeriesData()
16871710

pandas/tseries/tests/test_timeseries.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ def test_pad_require_monotonicity(self):
549549

550550
rng2 = rng[::2][::-1]
551551

552-
self.assertRaises(AssertionError, rng2.get_indexer, rng,
552+
self.assertRaises(ValueError, rng2.get_indexer, rng,
553553
method='pad')
554554

555555
def test_frame_ctor_datetime64_column(self):

0 commit comments

Comments
 (0)