From 554ecd0ceaafc170abf769f66b91a749a5bd30d9 Mon Sep 17 00:00:00 2001 From: gfyoung Date: Sat, 7 Oct 2017 17:56:37 -0700 Subject: [PATCH] ENH: Add Index.to_frame method Closes gh-15230. --- doc/source/api.rst | 3 +++ doc/source/whatsnew/v0.21.0.txt | 1 + pandas/core/indexes/base.py | 23 +++++++++++++++++++ pandas/core/indexes/datetimes.py | 39 ++++++++++++++++++++++++++++++++ pandas/core/indexes/multi.py | 4 ++-- pandas/tests/indexes/common.py | 15 ++++++++++++ 6 files changed, 83 insertions(+), 2 deletions(-) diff --git a/doc/source/api.rst b/doc/source/api.rst index d98a18e6f7e363..646a28686bb063 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1376,6 +1376,7 @@ Conversion Index.tolist Index.to_datetime Index.to_series + Index.to_frame Sorting ~~~~~~~ @@ -1591,6 +1592,7 @@ Conversion DatetimeIndex.to_perioddelta DatetimeIndex.to_pydatetime DatetimeIndex.to_series + DatetimeIndex.to_frame TimedeltaIndex -------------- @@ -1623,6 +1625,7 @@ Conversion TimedeltaIndex.round TimedeltaIndex.floor TimedeltaIndex.ceil + TimedeltaIndex.to_frame .. currentmodule:: pandas diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 1e9c402dac73e6..2230941cdee894 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -31,6 +31,7 @@ New features - Added ``skipna`` parameter to :func:`~pandas.api.types.infer_dtype` to support type inference in the presence of missing values (:issue:`17059`). - :class:`~pandas.Resampler.nearest` is added to support nearest-neighbor upsampling (:issue:`17496`). +- :class:`~pandas.Index~` has added support for a ``to_frame`` method (:issue:`15230`) .. _whatsnew_0210.enhancements.infer_objects: diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 0a55559750d7c8..2210c1d628d7fa 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1005,6 +1005,29 @@ def to_series(self, **kwargs): index=self._shallow_copy(), name=self.name) + def to_frame(self, index=True): + """ + Create a DataFrame with a column containing the Index. + + .. versionadded:: 0.21.0 + + Parameters + ---------- + index : boolean, default True + Set the index of the returned DataFrame as self. + + Returns + ------- + DataFrame : a DataFrame containing the original Index data. + """ + + from pandas import DataFrame + result = DataFrame(self._shallow_copy(), columns=[self.name or 0]) + + if index: + result.index = self + return result + def _to_embed(self, keep_tz=False): """ *this is an internal non-public method* diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index 25897bee298458..e2e99627869d9d 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -915,6 +915,45 @@ def to_series(self, keep_tz=False): index=self._shallow_copy(), name=self.name) + def to_frame(self, index=True, keep_tz=False): + """ + Create a DataFrame with a column containing the DatetimeIndex. + + .. versionadded:: 0.21.0 + + Parameters + ---------- + index : boolean, default True + Set the index of the returned DataFrame as self. + + keep_tz : optional, defaults False. + return the data keeping the timezone. + + If keep_tz is True: + + If the timezone is not set, the resulting + Series will have a datetime64[ns] dtype. + + Otherwise the DataFrame will have an datetime64[ns, tz] dtype; + the tz will be preserved. + + If keep_tz is False: + + DataFrame will have a datetime64[ns] dtype. TZ aware + objects will have the tz removed. + + Returns + ------- + DataFrame : a DataFrame containing the original DatetimeIndex data. + """ + + from pandas import DataFrame + result = DataFrame(self._to_embed(keep_tz), columns=[self.name or 0]) + + if index: + result.index = self + return result + def _to_embed(self, keep_tz=False): """ return an array repr of this object, potentially casting to object diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 4b6e31133ba4b0..52c6804a55b020 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -1010,14 +1010,14 @@ def _to_safe_for_reshape(self): def to_frame(self, index=True): """ - Create a DataFrame with the columns the levels of the MultiIndex + Create a DataFrame with the levels of the MultiIndex as columns. .. versionadded:: 0.20.0 Parameters ---------- index : boolean, default True - return this MultiIndex as the index + Set the index of the returned DataFrame as self. Returns ------- diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/common.py index 970dd7b63225ab..456e5a9bd6439d 100644 --- a/pandas/tests/indexes/common.py +++ b/pandas/tests/indexes/common.py @@ -51,6 +51,21 @@ def test_to_series(self): assert s.index is not idx assert s.name == idx.name + def test_to_frame(self): + # see gh-15230 + idx = self.create_index() + name = idx.name or 0 + + df = idx.to_frame() + + assert df.index is idx + assert len(df.columns) == 1 + assert df.columns[0] == name + assert df[name].values is not idx.values + + df = idx.to_frame(index=False) + assert df.index is not idx + def test_shift(self): # GH8083 test the base class for shift