Skip to content

MultiIndexed unstack with tuple names fails with KeyError #19966

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
TomAugspurger opened this issue Mar 2, 2018 · 3 comments · Fixed by #30943
Closed

MultiIndexed unstack with tuple names fails with KeyError #19966

TomAugspurger opened this issue Mar 2, 2018 · 3 comments · Fixed by #30943
Labels
MultiIndex Reshaping Concat, Merge/Join, Stack/Unstack, Explode
Milestone

Comments

@TomAugspurger
Copy link
Contributor

In [8]: idx = pd.MultiIndex.from_product([['a', 'b', 'c'], [1, 2, 3]], names=[('A', 'a'), ('B', 'b')])

In [9]: s = pd.Series(1, index=idx)

In [10]: s
Out[10]:
(A, a)  (B, b)
a       1         1
        2         1
        3         1
b       1         1
        2         1
        3         1
c       1         1
        2         1
        3         1
dtype: int64

In [11]: s.unstack(("A", "a"))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/Envs/pandas-dev/lib/python3.6/site-packages/pandas/pandas/core/indexes/multi.py in _get_level_number(self, level)
    749                                  'level number' % level)
--> 750             level = self.names.index(level)
    751         except ValueError:

ValueError: 'A' is not in list

During handling of the above exception, another exception occurred:

KeyError                                  Traceback (most recent call last)
<ipython-input-11-1ce241b42d82> in <module>()
----> 1 s.unstack(("A", "a"))

~/Envs/pandas-dev/lib/python3.6/site-packages/pandas/pandas/core/series.py in unstack(self, level, fill_value)
   2231         """
   2232         from pandas.core.reshape.reshape import unstack
-> 2233         return unstack(self, level, fill_value)
   2234
   2235     # ----------------------------------------------------------------------

~/Envs/pandas-dev/lib/python3.6/site-packages/pandas/pandas/core/reshape/reshape.py in unstack(obj, level, fill_value)
    481             # _unstack_multiple only handles MultiIndexes,
    482             # and isn't needed for a single level
--> 483             return _unstack_multiple(obj, level, fill_value=fill_value)
    484         else:
    485             level = level[0]

~/Envs/pandas-dev/lib/python3.6/site-packages/pandas/pandas/core/reshape/reshape.py in _unstack_multiple(data, clocs, fill_value)
    315     index = data.index
    316
--> 317     clocs = [index._get_level_number(i) for i in clocs]
    318
    319     rlocs = [i for i in range(index.nlevels) if i not in clocs]

~/Envs/pandas-dev/lib/python3.6/site-packages/pandas/pandas/core/reshape/reshape.py in <listcomp>(.0)
    315     index = data.index
    316
--> 317     clocs = [index._get_level_number(i) for i in clocs]
    318
    319     rlocs = [i for i in range(index.nlevels) if i not in clocs]

~/Envs/pandas-dev/lib/python3.6/site-packages/pandas/pandas/core/indexes/multi.py in _get_level_number(self, level)
    751         except ValueError:
    752             if not isinstance(level, int):
--> 753                 raise KeyError('Level %s not found' % str(level))
    754             elif level < 0:
    755                 level += self.nlevels

KeyError: 'Level A not found'

cc @ibrahimsharaf, @toobaz does this look difficult?

@TomAugspurger TomAugspurger added Reshaping Concat, Merge/Join, Stack/Unstack, Explode MultiIndex labels Mar 2, 2018
@TomAugspurger TomAugspurger added this to the Next Major Release milestone Mar 2, 2018
@toobaz
Copy link
Member

toobaz commented Mar 2, 2018

Reminds me of #18321 probably unrelated, and probably simpler... one of these cases in which we probably only need to tell unstack that tuples are not lists.

@ibrahimsharaf
Copy link
Contributor

Hi @TomAugspurger, I'm willing to help here, do you have any initial ideas on how to fix this? (before I dive in the code)

@TomAugspurger
Copy link
Contributor Author

in reshape/reshape, the line here

--> 317 clocs = [index._get_level_number(i) for i in clocs]

is incorrect. It's assuming that all iterables are referring to multiple levels. In this case, we have a single level whose name happens to be an iterable. We want to do

In [8]: s.index._get_level_number(('A', 'a'))
Out[8]: 0

but there may be other problems later on. You'll probably run into ambiguous situations as well (e.g. the index names are [('A', 'a'), 'A', 'a']. Not sure how best to handle those.

@jreback jreback modified the milestones: Contributions Welcome, 1.1 Jan 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
MultiIndex Reshaping Concat, Merge/Join, Stack/Unstack, Explode
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants