Repository: pandas-dev/pandas

Issue:
API: add ignore_index keyword to dropna() and other similar functions
#### Code Sample

**Before**

```python
df = pd.DataFrame({'A': [0, pd.NA, 1]})
df.dropna().reset_index(drop=True)
```

**After**

```python
df = pd.DataFrame({'A': [0, pd.NA, 1]})
df.dropna(ignore_index=True)
```
#### Problem description

I have noticed a lot of dataframe reshaping functions acquiring the `ignore_index` keyword. (e.g. #30114). I think `df.dropna()` is a good candidate for this keyword, as are any other functions which change the index from being a consecutive sequence of integers

#### Expected Output
```python
In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'A': [0, pd.NA, 1]})

In [3]: df
Out[3]:
      A
0     0
1  <NA>
2     1

In [4]: df.dropna().reset_index(drop=True)
Out[4]:
   A
0  0
1  1

In [5]: df.dropna(ignore_index=True) 
Out[5]:
   A
0  0
1  1
```


Discussion:

Patch:
diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst
index 76aa426cc1cee..378a24016c9b0 100644
--- a/doc/source/whatsnew/v2.0.0.rst
+++ b/doc/source/whatsnew/v2.0.0.rst
@@ -183,6 +183,7 @@ Other enhancements
 - Added ``copy`` parameter to :meth:`Series.infer_objects` and :meth:`DataFrame.infer_objects`, passing ``False`` will avoid making copies for series or columns that are already non-object or where no better dtype can be inferred (:issue:`50096`)
 - :meth:`DataFrame.plot.hist` now recognizes ``xlabel`` and ``ylabel`` arguments (:issue:`49793`)
 - :meth:`Series.drop_duplicates` has gained ``ignore_index`` keyword to reset index (:issue:`48304`)
+- :meth:`Series.dropna` and :meth:`DataFrame.dropna` has gained ``ignore_index`` keyword to reset index (:issue:`31725`)
 - Improved error message in :func:`to_datetime` for non-ISO8601 formats, informing users about the position of the first error (:issue:`50361`)
 - Improved error message when trying to align :class:`DataFrame` objects (for example, in :func:`DataFrame.compare`) to clarify that "identically labelled" refers to both index and columns (:issue:`50083`)
 - Added :meth:`DatetimeIndex.as_unit` and :meth:`TimedeltaIndex.as_unit` to convert to different resolutions; supported resolutions are "s", "ms", "us", and "ns" (:issue:`50616`)
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
index 685ed9f972a32..b9225b341a71f 100644
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -6211,6 +6211,7 @@ def dropna(
         thresh: int | NoDefault = ...,
         subset: IndexLabel = ...,
         inplace: Literal[False] = ...,
+        ignore_index: bool = ...,
     ) -> DataFrame:
         ...
 
@@ -6223,6 +6224,7 @@ def dropna(
         thresh: int | NoDefault = ...,
         subset: IndexLabel = ...,
         inplace: Literal[True],
+        ignore_index: bool = ...,
     ) -> None:
         ...
 
@@ -6234,6 +6236,7 @@ def dropna(
         thresh: int | NoDefault = no_default,
         subset: IndexLabel = None,
         inplace: bool = False,
+        ignore_index: bool = False,
     ) -> DataFrame | None:
         """
         Remove missing values.
@@ -6269,6 +6272,10 @@ def dropna(
             these would be a list of columns to include.
         inplace : bool, default False
             Whether to modify the DataFrame rather than creating a new one.
+        ignore_index : bool, default ``False``
+            If ``True``, the resulting axis will be labeled 0, 1, …, n - 1.
+
+            .. versionadded:: 2.0.0
 
         Returns
         -------
@@ -6383,6 +6390,9 @@ def dropna(
         else:
             result = self.loc(axis=axis)[mask]
 
+        if ignore_index:
+            result.index = default_index(len(result))
+
         if not inplace:
             return result
         self._update_inplace(result)
diff --git a/pandas/core/series.py b/pandas/core/series.py
index 106cf166acd14..845bc9b173392 100644
--- a/pandas/core/series.py
+++ b/pandas/core/series.py
@@ -5515,6 +5515,7 @@ def dropna(
         axis: Axis = ...,
         inplace: Literal[False] = ...,
         how: AnyAll | None = ...,
+        ignore_index: bool = ...,
     ) -> Series:
         ...
 
@@ -5525,6 +5526,7 @@ def dropna(
         axis: Axis = ...,
         inplace: Literal[True],
         how: AnyAll | None = ...,
+        ignore_index: bool = ...,
     ) -> None:
         ...
 
@@ -5534,6 +5536,7 @@ def dropna(
         axis: Axis = 0,
         inplace: bool = False,
         how: AnyAll | None = None,
+        ignore_index: bool = False,
     ) -> Series | None:
         """
         Return a new Series with missing values removed.
@@ -5549,6 +5552,10 @@ def dropna(
             If True, do operation inplace and return None.
         how : str, optional
             Not in use. Kept for compatibility.
+        ignore_index : bool, default ``False``
+            If ``True``, the resulting axis will be labeled 0, 1, …, n - 1.
+
+            .. versionadded:: 2.0.0
 
         Returns
         -------
@@ -5606,19 +5613,25 @@ def dropna(
         dtype: object
         """
         inplace = validate_bool_kwarg(inplace, "inplace")
+        ignore_index = validate_bool_kwarg(ignore_index, "ignore_index")
         # Validate the axis parameter
         self._get_axis_number(axis or 0)
 
         if self._can_hold_na:
             result = remove_na_arraylike(self)
-            if inplace:
-                self._update_inplace(result)
-            else:
-                return result
         else:
             if not inplace:
-                return self.copy(deep=None)
-        return None
+                result = self.copy(deep=None)
+            else:
+                result = self
+
+        if ignore_index:
+            result.index = default_index(len(result))
+
+        if inplace:
+            return self._update_inplace(result)
+        else:
+            return result
 
     # ----------------------------------------------------------------------
     # Time series-oriented methods


Test patch:
diff --git a/pandas/tests/frame/methods/test_dropna.py b/pandas/tests/frame/methods/test_dropna.py
index f072cd04f49e1..d6e54559da7e3 100644
--- a/pandas/tests/frame/methods/test_dropna.py
+++ b/pandas/tests/frame/methods/test_dropna.py
@@ -272,3 +272,14 @@ def test_how_thresh_param_incompatible(self):
 
         with pytest.raises(TypeError, match=msg):
             df.dropna(how=None, thresh=None)
+
+    @pytest.mark.parametrize("val", [1, 1.5])
+    def test_dropna_ignore_index(self, val):
+        # GH#31725
+        df = DataFrame({"a": [1, 2, val]}, index=[3, 2, 1])
+        result = df.dropna(ignore_index=True)
+        expected = DataFrame({"a": [1, 2, val]})
+        tm.assert_frame_equal(result, expected)
+
+        df.dropna(ignore_index=True, inplace=True)
+        tm.assert_frame_equal(df, expected)
diff --git a/pandas/tests/series/methods/test_dropna.py b/pandas/tests/series/methods/test_dropna.py
index 5bff7306fac33..ba2dd8f830bb1 100644
--- a/pandas/tests/series/methods/test_dropna.py
+++ b/pandas/tests/series/methods/test_dropna.py
@@ -101,3 +101,14 @@ def test_datetime64_tz_dropna(self):
         )
         assert result.dtype == "datetime64[ns, Asia/Tokyo]"
         tm.assert_series_equal(result, expected)
+
+    @pytest.mark.parametrize("val", [1, 1.5])
+    def test_dropna_ignore_index(self, val):
+        # GH#31725
+        ser = Series([1, 2, val], index=[3, 2, 1])
+        result = ser.dropna(ignore_index=True)
+        expected = Series([1, 2, val])
+        tm.assert_series_equal(result, expected)
+
+        ser.dropna(ignore_index=True, inplace=True)
+        tm.assert_series_equal(ser, expected)