Skip to content

Commit 7643073

Browse files
WillAydtm9k1
authored andcommitted
Add to_flat_index method to MultiIndex (pandas-dev#22866)
1 parent 30850bb commit 7643073

File tree

6 files changed

+67
-0
lines changed

6 files changed

+67
-0
lines changed

doc/source/api.rst

+1
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,7 @@ MultiIndex Components
17241724
MultiIndex.set_levels
17251725
MultiIndex.set_labels
17261726
MultiIndex.to_hierarchical
1727+
MultiIndex.to_flat_index
17271728
MultiIndex.to_frame
17281729
MultiIndex.is_lexsorted
17291730
MultiIndex.sortlevel

doc/source/whatsnew/v0.24.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ Other Enhancements
238238
- :func:`~DataFrame.to_parquet` now supports writing a ``DataFrame`` as a directory of parquet files partitioned by a subset of the columns when ``engine = 'pyarrow'`` (:issue:`23283`)
239239
- :meth:`Timestamp.tz_localize`, :meth:`DatetimeIndex.tz_localize`, and :meth:`Series.tz_localize` have gained the ``nonexistent`` argument for alternative handling of nonexistent times. See :ref:`timeseries.timezone_nonexistent` (:issue:`8917`)
240240
- :meth:`read_excel()` now accepts ``usecols`` as a list of column names or callable (:issue:`18273`)
241+
- :meth:`MultiIndex.to_flat_index` has been added to flatten multiple levels into a single-level :class:`Index` object.
241242

242243
.. _whatsnew_0240.api_breaking:
243244

pandas/core/indexes/base.py

+20
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,26 @@ def _format_attrs(self):
11131113
"""
11141114
return format_object_attrs(self)
11151115

1116+
def to_flat_index(self):
1117+
"""
1118+
Identity method.
1119+
1120+
.. versionadded:: 0.24.0
1121+
1122+
This is implemented for compatability with subclass implementations
1123+
when chaining.
1124+
1125+
Returns
1126+
-------
1127+
pd.Index
1128+
Caller.
1129+
1130+
See Also
1131+
--------
1132+
MultiIndex.to_flat_index : Subclass implementation.
1133+
"""
1134+
return self
1135+
11161136
def to_series(self, index=None, name=None):
11171137
"""
11181138
Create a Series with both index and values equal to the index keys

pandas/core/indexes/multi.py

+29
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ class MultiIndex(Index):
193193
set_levels
194194
set_labels
195195
to_frame
196+
to_flat_index
196197
is_lexsorted
197198
sortlevel
198199
droplevel
@@ -1246,6 +1247,34 @@ def to_hierarchical(self, n_repeat, n_shuffle=1):
12461247
FutureWarning, stacklevel=2)
12471248
return MultiIndex(levels=levels, labels=labels, names=names)
12481249

1250+
def to_flat_index(self):
1251+
"""
1252+
Convert a MultiIndex to an Index of Tuples containing the level values.
1253+
1254+
.. versionadded:: 0.24.0
1255+
1256+
Returns
1257+
-------
1258+
pd.Index
1259+
Index with the MultiIndex data represented in Tuples.
1260+
1261+
Notes
1262+
-----
1263+
This method will simply return the caller if called by anything other
1264+
than a MultiIndex.
1265+
1266+
Examples
1267+
--------
1268+
>>> index = pd.MultiIndex.from_product(
1269+
... [['foo', 'bar'], ['baz', 'qux']],
1270+
... names=['a', 'b'])
1271+
>>> index.to_flat_index()
1272+
Index([('foo', 'baz'), ('foo', 'qux'),
1273+
('bar', 'baz'), ('bar', 'qux')],
1274+
dtype='object')
1275+
"""
1276+
return Index(self.values, tupleize_cols=False)
1277+
12491278
@property
12501279
def is_all_dates(self):
12511280
return False

pandas/tests/indexes/multi/test_conversion.py

+8
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,11 @@ def test_to_series_with_arguments(idx):
170170
assert s.values is not idx.values
171171
assert s.index is not idx
172172
assert s.name != idx.name
173+
174+
175+
def test_to_flat_index(idx):
176+
expected = pd.Index((('foo', 'one'), ('foo', 'two'), ('bar', 'one'),
177+
('baz', 'two'), ('qux', 'one'), ('qux', 'two')),
178+
tupleize_cols=False)
179+
result = idx.to_flat_index()
180+
tm.assert_index_equal(result, expected)

pandas/tests/indexes/test_base.py

+8
Original file line numberDiff line numberDiff line change
@@ -2266,6 +2266,14 @@ def test_tab_complete_warning(self, ip):
22662266
with provisionalcompleter('ignore'):
22672267
list(ip.Completer.completions('idx.', 4))
22682268

2269+
def test_to_flat_index(self, indices):
2270+
# 22866
2271+
if isinstance(indices, MultiIndex):
2272+
pytest.skip("Separate expectation for MultiIndex")
2273+
2274+
result = indices.to_flat_index()
2275+
tm.assert_index_equal(result, indices)
2276+
22692277

22702278
class TestMixedIntIndex(Base):
22712279
# Mostly the tests from common.py for which the results differ

0 commit comments

Comments
 (0)