Skip to content

Commit 722e0ae

Browse files
committed
ENH Add MultiIndex.from_product convenience function
FIX typo in from_iterables docstring ENH Rename from_iterables to from_product TST rework from_product test to compare against from_tuples DOC Add notes on from_product to release notes and indexing docs DOC clean from_product examples in docs DOC Further clarify from_product docs
1 parent c1b7ac0 commit 722e0ae

File tree

4 files changed

+78
-2
lines changed

4 files changed

+78
-2
lines changed

doc/source/indexing.rst

+11-2
Original file line numberDiff line numberDiff line change
@@ -1539,8 +1539,9 @@ The ``MultiIndex`` object is the hierarchical analogue of the standard
15391539
``Index`` object which typically stores the axis labels in pandas objects. You
15401540
can think of ``MultiIndex`` an array of tuples where each tuple is unique. A
15411541
``MultiIndex`` can be created from a list of arrays (using
1542-
``MultiIndex.from_arrays``) or an array of tuples (using
1543-
``MultiIndex.from_tuples``).
1542+
``MultiIndex.from_arrays``), an array of tuples (using
1543+
``MultiIndex.from_tuples``), or a crossed set of iterables (using
1544+
``MultiIndex.from_product``).
15441545

15451546
.. ipython:: python
15461547
@@ -1552,6 +1553,14 @@ can think of ``MultiIndex`` an array of tuples where each tuple is unique. A
15521553
s = Series(randn(8), index=index)
15531554
s
15541555
1556+
When you want every pairing of the elements in two iterables, it can be easier
1557+
to use the ``MultiIndex.from_product`` function:
1558+
1559+
.. ipython:: python
1560+
1561+
iterables = [['bar', 'baz', 'foo', 'qux'], ['one', 'two']]
1562+
MultiIndex.from_product(iterables, names=['first', 'second'])
1563+
15551564
As a convenience, you can pass a list of arrays directly into Series or
15561565
DataFrame to construct a MultiIndex automatically:
15571566

doc/source/v0.13.1.txt

+10
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ Enhancements
7373
improves parsing perf in many cases. Thanks to @lexual for suggesting and @danbirken
7474
for rapidly implementing. (:issue:`5490`, :issue:`6021`)
7575

76+
- ``MultiIndex.from_product`` convenience function for creating a MultiIndex from
77+
the cartesian product of a set of iterables (:issue:`6055`):
78+
79+
.. ipython:: python
80+
81+
shades = ['light', 'dark']
82+
colors = ['red', 'green', 'blue']
83+
84+
MultiIndex.from_product([shades, colors], names=['shade', 'color'])
85+
7686
- The ``ArrayFormatter`` for ``datetime`` and ``timedelta64`` now intelligently
7787
limit precision based on the values in the array (:issue:`3401`)
7888

pandas/core/index.py

+43
Original file line numberDiff line numberDiff line change
@@ -2491,6 +2491,8 @@ def from_arrays(cls, arrays, sortorder=None, names=None):
24912491
See Also
24922492
--------
24932493
MultiIndex.from_tuples : Convert list of tuples to MultiIndex
2494+
MultiIndex.from_product : Make a MultiIndex from cartesian product
2495+
of iterables
24942496
"""
24952497
from pandas.core.categorical import Categorical
24962498

@@ -2534,6 +2536,8 @@ def from_tuples(cls, tuples, sortorder=None, names=None):
25342536
See Also
25352537
--------
25362538
MultiIndex.from_arrays : Convert list of arrays to MultiIndex
2539+
MultiIndex.from_product : Make a MultiIndex from cartesian product
2540+
of iterables
25372541
"""
25382542
if len(tuples) == 0:
25392543
# I think this is right? Not quite sure...
@@ -2552,6 +2556,45 @@ def from_tuples(cls, tuples, sortorder=None, names=None):
25522556
return MultiIndex.from_arrays(arrays, sortorder=sortorder,
25532557
names=names)
25542558

2559+
@classmethod
2560+
def from_product(cls, iterables, sortorder=None, names=None):
2561+
"""
2562+
Make a MultiIndex from the cartesian product of multiple iterables
2563+
2564+
Parameters
2565+
----------
2566+
iterables : list / sequence of iterables
2567+
Each iterable has unique labels for each level of the index.
2568+
sortorder : int or None
2569+
Level of sortedness (must be lexicographically sorted by that
2570+
level).
2571+
names : list / sequence of strings or None
2572+
Names for the levels in the index.
2573+
2574+
Returns
2575+
-------
2576+
index : MultiIndex
2577+
2578+
Examples
2579+
--------
2580+
>>> numbers = [0, 1, 2]
2581+
>>> colors = [u'green', u'purple']
2582+
>>> MultiIndex.from_product([numbers, colors],
2583+
names=['number', 'color'])
2584+
MultiIndex(levels=[[0, 1, 2], [u'green', u'purple']],
2585+
labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]],
2586+
names=[u'number', u'color'])
2587+
2588+
See Also
2589+
--------
2590+
MultiIndex.from_arrays : Convert list of arrays to MultiIndex
2591+
MultiIndex.from_tuples : Convert list of tuples to MultiIndex
2592+
"""
2593+
from pandas.tools.util import cartesian_product
2594+
product = cartesian_product(iterables)
2595+
return MultiIndex.from_arrays(product, sortorder=sortorder,
2596+
names=names)
2597+
25552598
@property
25562599
def nlevels(self):
25572600
return len(self.levels)

pandas/tests/test_index.py

+14
Original file line numberDiff line numberDiff line change
@@ -1561,6 +1561,20 @@ def test_from_arrays(self):
15611561
result = MultiIndex.from_arrays(arrays)
15621562
self.assertEquals(list(result), list(self.index))
15631563

1564+
def test_from_product(self):
1565+
first = ['foo', 'bar', 'buz']
1566+
second = ['a', 'b', 'c']
1567+
names = ['first', 'second']
1568+
result = MultiIndex.from_product([first, second], names=names)
1569+
1570+
tuples = [('foo', 'a'), ('foo', 'b'), ('foo', 'c'),
1571+
('bar', 'a'), ('bar', 'b'), ('bar', 'c'),
1572+
('buz', 'a'), ('buz', 'b'), ('buz', 'c')]
1573+
expected = MultiIndex.from_tuples(tuples, names=names)
1574+
1575+
assert_array_equal(result, expected)
1576+
self.assertEquals(result.names, names)
1577+
15641578
def test_append(self):
15651579
result = self.index[:3].append(self.index[3:])
15661580
self.assert_(result.equals(self.index))

0 commit comments

Comments
 (0)