From e4502bfdb525207e625bfb5df1566164d7f9710c Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Fri, 3 Feb 2017 13:18:56 -0500 Subject: [PATCH 1/2] ENH: .isnull and .notnull have been added as methods to Index to make this more consistent with the Series API --- doc/source/api.rst | 8 ++++++++ doc/source/whatsnew/v0.20.0.txt | 2 +- pandas/indexes/base.py | 32 ++++++++++++++++++++++++++++++++ pandas/tests/indexes/common.py | 27 ++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/doc/source/api.rst b/doc/source/api.rst index 92f290b5ee0a9..6c4a3cff5b4cf 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1356,8 +1356,16 @@ Modifying and Computations Index.unique Index.nunique Index.value_counts + +Missing Values +~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + Index.fillna Index.dropna + Index.isnull + Index.notnull Conversion ~~~~~~~~~~ diff --git a/doc/source/whatsnew/v0.20.0.txt b/doc/source/whatsnew/v0.20.0.txt index d76a78c68fb73..c6d757c6884d0 100644 --- a/doc/source/whatsnew/v0.20.0.txt +++ b/doc/source/whatsnew/v0.20.0.txt @@ -125,7 +125,7 @@ Other enhancements - ``pd.read_excel`` now preserves sheet order when using ``sheetname=None`` (:issue:`9930`) - Multiple offset aliases with decimal points are now supported (e.g. '0.5min' is parsed as '30s') (:issue:`8419`) - +- ``.isnull()`` and ``.notnull()`` have been added to ``Index`` object to make them more consistent with the ``Series`` API (:issue:`15300`) - ``pd.read_gbq`` method now allows query configuration preferences (:issue:`14742`) - New ``UnsortedIndexError`` (subclass of ``KeyError``) raised when indexing/slicing into an diff --git a/pandas/indexes/base.py b/pandas/indexes/base.py index bc2dce4e97e5b..f219d83f7a92e 100644 --- a/pandas/indexes/base.py +++ b/pandas/indexes/base.py @@ -1662,6 +1662,38 @@ def hasnans(self): else: return False + def isnull(self): + """ + Detect missing values + + .. versionadded:: 0.20.0 + + Returns + ------- + a boolean array of whether my values are null + + See also + -------- + pandas.isnull : pandas version + """ + return self._isnan + + def notnull(self): + """ + Reverse of isnull + + .. versionadded:: 0.20.0 + + Returns + ------- + a boolean array of whether my values are not null + + See also + -------- + pandas.notnull : pandas version + """ + return ~self.isnull() + def putmask(self, mask, value): """ return a new Index of the values set with the mask diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/common.py index 5a482acf403cd..81ad0524807f3 100644 --- a/pandas/tests/indexes/common.py +++ b/pandas/tests/indexes/common.py @@ -7,7 +7,7 @@ from pandas import (Series, Index, Float64Index, Int64Index, UInt64Index, RangeIndex, MultiIndex, CategoricalIndex, DatetimeIndex, - TimedeltaIndex, PeriodIndex, notnull) + TimedeltaIndex, PeriodIndex, notnull, isnull) from pandas.types.common import needs_i8_conversion from pandas.util.testing import assertRaisesRegexp @@ -879,3 +879,28 @@ def test_fillna(self): expected[1] = True self.assert_numpy_array_equal(idx._isnan, expected) self.assertTrue(idx.hasnans) + + def test_nulls(self): + # this is really a smoke test for the methods + # as these are adequantely tested for function elsewhere + + for name, index in self.indices.items(): + if len(index) == 0: + self.assert_numpy_array_equal( + index.isnull(), np.array([], dtype=bool)) + elif isinstance(index, MultiIndex): + idx = index.copy() + msg = "isnull is not defined for MultiIndex" + with self.assertRaisesRegexp(NotImplementedError, msg): + idx.isnull() + else: + + if not index.hasnans: + self.assert_numpy_array_equal( + index.isnull(), np.zeros(len(index), dtype=bool)) + self.assert_numpy_array_equal( + index.notnull(), np.ones(len(index), dtype=bool)) + else: + result = isnull(index) + self.assert_numpy_array_equal(index.isnull(), result) + self.assert_numpy_array_equal(index.notnull(), ~result) From 8c35656f7911e1aaa5d11a3902939f29d722c34a Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Fri, 3 Feb 2017 15:18:15 -0500 Subject: [PATCH 2/2] DOC: move Index.where to shared_docs --- pandas/indexes/base.py | 6 ++++-- pandas/indexes/category.py | 13 +------------ pandas/tseries/base.py | 13 +------------ 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/pandas/indexes/base.py b/pandas/indexes/base.py index f219d83f7a92e..dcd565ee5f0e9 100644 --- a/pandas/indexes/base.py +++ b/pandas/indexes/base.py @@ -564,8 +564,7 @@ def repeat(self, repeats, *args, **kwargs): nv.validate_repeat(args, kwargs) return self._shallow_copy(self._values.repeat(repeats)) - def where(self, cond, other=None): - """ + _index_shared_docs['where'] = """ .. versionadded:: 0.19.0 Return an Index of same shape as self and whose corresponding @@ -577,6 +576,9 @@ def where(self, cond, other=None): cond : boolean same length as self other : scalar, or array-like """ + + @Appender(_index_shared_docs['where']) + def where(self, cond, other=None): if other is None: other = self._na_value values = np.where(cond, self.values, other) diff --git a/pandas/indexes/category.py b/pandas/indexes/category.py index e3ffa40f5f94a..e2e0fd056b111 100644 --- a/pandas/indexes/category.py +++ b/pandas/indexes/category.py @@ -332,19 +332,8 @@ def _can_reindex(self, indexer): """ always allow reindexing """ pass + @Appender(_index_shared_docs['where']) def where(self, cond, other=None): - """ - .. versionadded:: 0.19.0 - - Return an Index of same shape as self and whose corresponding - entries are from self where cond is True and otherwise are from - other. - - Parameters - ---------- - cond : boolean same length as self - other : scalar, or array-like - """ if other is None: other = self._na_value values = np.where(cond, self.values, other) diff --git a/pandas/tseries/base.py b/pandas/tseries/base.py index a8dd2238c2063..ee9234d6c8237 100644 --- a/pandas/tseries/base.py +++ b/pandas/tseries/base.py @@ -786,19 +786,8 @@ def repeat(self, repeats, *args, **kwargs): return self._shallow_copy(self.asi8.repeat(repeats), freq=freq) + @Appender(_index_shared_docs['where']) def where(self, cond, other=None): - """ - .. versionadded:: 0.19.0 - - Return an Index of same shape as self and whose corresponding - entries are from self where cond is True and otherwise are from - other. - - Parameters - ---------- - cond : boolean same length as self - other : scalar, or array-like - """ other = _ensure_datetimelike_to_i8(other) values = _ensure_datetimelike_to_i8(self) result = np.where(cond, values, other).astype('i8')