From a9daf353857d7ca1a71acdaa7a0a67ab463f2982 Mon Sep 17 00:00:00 2001 From: gfyoung Date: Mon, 9 Oct 2017 05:17:04 -0700 Subject: [PATCH] ENH: Add Index.to_frame method (#17815) 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 | 40 ++++++++++++++++++++++++++++++++ pandas/core/indexes/multi.py | 6 ++--- pandas/tests/indexes/common.py | 15 ++++++++++++ 6 files changed, 85 insertions(+), 3 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..595fab9e18ea4f 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..df0e963e7628d6 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 the original Index. + + 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..dae62176722e1e 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -915,6 +915,46 @@ 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 the original DatetimeIndex. + + 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..06b208b4d174e5 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -1010,18 +1010,18 @@ 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 the original MultiIndex. Returns ------- - DataFrame + DataFrame : a DataFrame containing the original MultiIndex data. """ from pandas import DataFrame 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