diff --git a/doc/source/api.rst b/doc/source/api.rst index d062512ac3a5b..8772b858de2cc 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -258,6 +258,8 @@ Conversion / Constructors Series.__init__ Series.astype Series.copy + Series.isnull + Series.notnull Indexing, iteration ~~~~~~~~~~~~~~~~~~~ @@ -472,6 +474,8 @@ Conversion / Constructors DataFrame.astype DataFrame.convert_objects DataFrame.copy + DataFrame.isnull + DataFrame.notnull Indexing, iteration ~~~~~~~~~~~~~~~~~~~ @@ -714,6 +718,8 @@ Conversion / Constructors Panel.__init__ Panel.astype Panel.copy + Panel.isnull + Panel.notnull Getting and setting ~~~~~~~~~~~~~~~~~~~ @@ -976,7 +982,7 @@ Time/Date Components * **week**: Same as weekofyear * **dayofweek**: (0=Monday, 6=Sunday) * **weekday**: (0=Monday, 6=Sunday) - * **dayofyear** + * **dayofyear** * **quarter** * **date**: Returns date component of Timestamps @@ -990,7 +996,7 @@ Selecting DatetimeIndex.indexer_at_time DatetimeIndex.indexer_between_time - + Time-specific operations ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/release.rst b/doc/source/release.rst index 85d9be1295e29..a1434c0bc927f 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -323,6 +323,7 @@ See :ref:`Internal Refactoring` - ``filter`` (also added axis argument to selectively filter on a different axis) - ``reindex,reindex_axis,take`` - ``truncate`` (moved to become part of ``NDFrame``) + - ``isnull/notnull`` now available on ``NDFrame`` objects - These are API changes which make ``Panel`` more consistent with ``DataFrame`` diff --git a/pandas/core/common.py b/pandas/core/common.py index 33df305a721a6..009de0395f361 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -182,7 +182,7 @@ def _use_inf_as_null(key): def _isnull_ndarraylike(obj): - values = obj + values = getattr(obj,'values',obj) dtype = values.dtype if dtype.kind in ('O', 'S', 'U'): @@ -198,22 +198,15 @@ def _isnull_ndarraylike(obj): elif dtype in _DATELIKE_DTYPES: # this is the NaT pattern - v = getattr(values, 'asi8', None) - if v is None: - v = values.view('i8') - result = v == tslib.iNaT + result = values.view('i8') == tslib.iNaT else: - result = np.isnan(obj) - - if isinstance(obj, ABCSeries): - from pandas import Series - result = Series(result, index=obj.index, copy=False) + result = np.isnan(values) return result def _isnull_ndarraylike_old(obj): - values = obj + values = getattr(obj,'values',obj) dtype = values.dtype if dtype.kind in ('O', 'S', 'U'): @@ -229,16 +222,9 @@ def _isnull_ndarraylike_old(obj): elif dtype in _DATELIKE_DTYPES: # this is the NaT pattern - v = getattr(values, 'asi8', None) - if v is None: - v = values.view('i8') - result = v == tslib.iNaT + result = values.view('i8') == tslib.iNaT else: - result = -np.isfinite(obj) - - if isinstance(obj, ABCSeries): - from pandas import Series - result = Series(result, index=obj.index, copy=False) + result = -np.isfinite(values) return result diff --git a/pandas/core/generic.py b/pandas/core/generic.py index bb47709532523..9dadeb4ef6e97 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2019,6 +2019,18 @@ def interpolate(self, to_replace, method='pad', axis=0, inplace=False, #---------------------------------------------------------------------- # Action Methods + def isnull(self): + """ + Return a boolean same-sized object indicating if the values are null + """ + return self.__class__(isnull(self),**self._construct_axes_dict())._propogate_attributes(self) + + def notnull(self): + """ + Return a boolean same-sized object indicating if the values are not null + """ + return self.__class__(notnull(self),**self._construct_axes_dict())._propogate_attributes(self) + def clip(self, lower=None, upper=None, out=None): """ Trim values at input threshold(s) diff --git a/pandas/core/ops.py b/pandas/core/ops.py index a10f3582bfe45..17d524978158b 100644 --- a/pandas/core/ops.py +++ b/pandas/core/ops.py @@ -539,7 +539,7 @@ def wrapper(self, other): # mask out the invalids if mask.any(): - res[mask.values] = masker + res[mask] = masker return res return wrapper diff --git a/pandas/core/series.py b/pandas/core/series.py index ddbb67cc0c323..d185939d6abc9 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -2174,9 +2174,6 @@ def dropna(self): valid = lambda self: self.dropna() - isnull = isnull - notnull = notnull - def first_valid_index(self): """ Return label for first non-NA/null value diff --git a/pandas/tests/test_common.py b/pandas/tests/test_common.py index 740e3d0821cd7..5efc22ef927d5 100644 --- a/pandas/tests/test_common.py +++ b/pandas/tests/test_common.py @@ -64,11 +64,9 @@ def test_notnull(): assert result.sum() == 2 with cf.option_context("mode.use_inf_as_null", False): - float_series = Series(np.random.randn(5)) - obj_series = Series(np.random.randn(5), dtype=object) - assert(isinstance(notnull(float_series), Series)) - assert(isinstance(notnull(obj_series), Series)) - + for s in [tm.makeFloatSeries(),tm.makeStringSeries(), + tm.makeObjectSeries(),tm.makeTimeSeries(),tm.makePeriodSeries()]: + assert(isinstance(isnull(s), np.ndarray)) def test_isnull(): assert not isnull(1.) @@ -77,10 +75,9 @@ def test_isnull(): assert not isnull(np.inf) assert not isnull(-np.inf) - float_series = Series(np.random.randn(5)) - obj_series = Series(np.random.randn(5), dtype=object) - assert(isinstance(isnull(float_series), Series)) - assert(isinstance(isnull(obj_series), Series)) + for s in [tm.makeFloatSeries(),tm.makeStringSeries(), + tm.makeObjectSeries(),tm.makeTimeSeries(),tm.makePeriodSeries()]: + assert(isinstance(isnull(s), np.ndarray)) # call on DataFrame df = DataFrame(np.random.randn(10, 5)) diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 2e386a7e2816a..64a45d344f2a9 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -1546,7 +1546,7 @@ def test_set_value_resize(self): res = self.frame.copy() res3 = res.set_value('foobar', 'baz', 5) self.assert_(com.is_float_dtype(res3['baz'])) - self.assert_(isnull(res3['baz'].drop(['foobar'])).values.all()) + self.assert_(isnull(res3['baz'].drop(['foobar'])).all()) self.assertRaises(ValueError, res3.set_value, 'foobar', 'baz', 'sam') def test_set_value_with_index_dtype_change(self): diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index 7f3ea130259dc..8abc068fd6d24 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -3667,17 +3667,17 @@ def test_valid(self): def test_isnull(self): ser = Series([0, 5.4, 3, nan, -0.001]) - assert_series_equal( - ser.isnull(), Series([False, False, False, True, False])) + np.array_equal( + ser.isnull(), Series([False, False, False, True, False]).values) ser = Series(["hi", "", nan]) - assert_series_equal(ser.isnull(), Series([False, False, True])) + np.array_equal(ser.isnull(), Series([False, False, True]).values) def test_notnull(self): ser = Series([0, 5.4, 3, nan, -0.001]) - assert_series_equal( - ser.notnull(), Series([True, True, True, False, True])) + np.array_equal( + ser.notnull(), Series([True, True, True, False, True]).values) ser = Series(["hi", "", nan]) - assert_series_equal(ser.notnull(), Series([True, True, False])) + np.array_equal(ser.notnull(), Series([True, True, False]).values) def test_shift(self): shifted = self.ts.shift(1)