diff --git a/bigframes/core/indexes/base.py b/bigframes/core/indexes/base.py index 41b32d99e4..998f7c754c 100644 --- a/bigframes/core/indexes/base.py +++ b/bigframes/core/indexes/base.py @@ -533,6 +533,16 @@ def value_counts( return series.Series(block) + def isna(self) -> Index: + return self._apply_unary_op(ops.isnull_op) + + isnull = isna + + def notna(self) -> Index: + return self._apply_unary_op(ops.notnull_op) + + notnull = notna + def fillna(self, value=None) -> Index: if self.nlevels > 1: raise TypeError("Multiindex does not support 'fillna'") diff --git a/tests/system/small/test_index.py b/tests/system/small/test_index.py index 0ec1fb6143..849589f4ab 100644 --- a/tests/system/small/test_index.py +++ b/tests/system/small/test_index.py @@ -300,6 +300,20 @@ def test_index_fillna(scalars_df_index, scalars_pandas_df_index): pd.testing.assert_index_equal(bf_result, pd_result) +def test_index_isna(scalars_df_index, scalars_pandas_df_index): + bf_result = scalars_df_index.set_index("int64_col").index.isna().to_pandas() + pd_result = scalars_pandas_df_index.set_index("int64_col").index.isna() + + pd.testing.assert_index_equal(bf_result, pd.Index(pd_result)) + + +def test_index_notna(scalars_df_index, scalars_pandas_df_index): + bf_result = scalars_df_index.set_index("float64_col").index.notna().to_pandas() + pd_result = scalars_pandas_df_index.set_index("float64_col").index.notna() + + pd.testing.assert_index_equal(bf_result, pd.Index(pd_result)) + + def test_index_drop(scalars_df_index, scalars_pandas_df_index): bf_result = ( scalars_df_index.set_index("int64_col").index.drop([2, 314159]).to_pandas() diff --git a/third_party/bigframes_vendored/pandas/core/indexes/base.py b/third_party/bigframes_vendored/pandas/core/indexes/base.py index d21056a8cf..f01dcca52b 100644 --- a/third_party/bigframes_vendored/pandas/core/indexes/base.py +++ b/third_party/bigframes_vendored/pandas/core/indexes/base.py @@ -962,6 +962,38 @@ def fillna(self, value) -> Index: """ raise NotImplementedError(constants.ABSTRACT_METHOD_ERROR_MESSAGE) + def isna(self): + """ + Detect missing values. + + Return a boolean same-sized object indicating if the values are NA. + NA values, such as ``None``, :attr:`numpy.NaN` or :attr:`pd.NaT`, get + mapped to ``True`` values. + Everything else get mapped to ``False`` values. Characters such as + empty strings `''` or :attr:`numpy.inf` are not considered NA values. + + Returns: + Index: + Boolean index to indicate which entries are NA. + """ + raise NotImplementedError(constants.ABSTRACT_METHOD_ERROR_MESSAGE) + + def notna(self): + """ + Detect existing (non-missing) values. + + Return a boolean same-sized object indicating if the values are not NA. + Non-missing values get mapped to ``True``. Characters such as empty + strings ``''`` or :attr:`numpy.inf` are not considered NA values. + NA values, such as None or :attr:`numpy.NaN`, get mapped to ``False`` + values. + + Returns: + Index: + Boolean index to indicate which entries are not NA. + """ + raise NotImplementedError(constants.ABSTRACT_METHOD_ERROR_MESSAGE) + def rename(self, name, *, inplace): """ Alter Index or MultiIndex name.