ENH: support for removing unused levels of a MultiIndex (interally)
State: closed

on top of #15694
 
xref #2770

Here's an example of what we could do with this
```
In [1]: df = pd.DataFrame({'value': [1, 2, 3, 4]}, index=pd.MultiIndex(
   ...:              levels=[['a', 'b'], ['bb', 'aa']],
   ...:              labels=[[0, 0, 1, 1], [0, 1, 0, 1]]))

In [2]: df
Out[2]: 
      value
a bb      1
  aa      2
b bb      3
  aa      4

In [14]: df.index.is_lexsorted()
Out[14]: True

In [15]: df.index.is_monotonic
Out[15]: False
```

sorting makes this monotonic & usually lexsorted (but not always)
```
In [3]: df2 = df.sort_index()

In [4]: df2
Out[4]: 
      value
a aa      2
  bb      1
b aa      4
  bb      3

In [12]: df2.index.is_lexsorted()
Out[12]: False

In [13]: df2.index.is_monotonic
Out[13]: True
```

If we expose a method ``.remove_unused_labels()`` (or even just do this under the hood on certain operations.
```
In [5]: df3 = df2.copy()

In [6]: df3.index._reconstruct(sort=True)
Out[6]: 
MultiIndex(levels=[['a', 'b'], ['aa', 'bb']],
           labels=[[0, 0, 1, 1], [0, 1, 0, 1]])

In [7]: df3.index = df3.index._reconstruct(sort=True)

In [8]: df3
Out[8]: 
      value
a aa      2
  bb      1
b aa      4
  bb      3

In [9]: df3.index.is_lexsorted()
Out[9]: True
In [11]: df3.index.is_monotonic
```


Labels:
name: API Design
name: MultiIndex

Comments:
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/15700?src=pr&el=h1) Report
> Merging [#15700](https://codecov.io/gh/pandas-dev/pandas/pull/15700?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/94720d951b4e804bab72abc33dffeb2186ecb310?src=pr&el=desc) will **decrease** coverage by `<.01%`.
> The diff coverage is `91.66%`.


```diff
@@            Coverage Diff             @@
##           master   #15700      +/-   ##
==========================================
- Coverage   91.01%   91.01%   -0.01%     
==========================================
  Files         143      143              
  Lines       49400    49448      +48     
==========================================
+ Hits        44963    45006      +43     
- Misses       4437     4442       +5
```


| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/15700?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/groupby.py](https://codecov.io/gh/pandas-dev/pandas/compare/94720d951b4e804bab72abc33dffeb2186ecb310...f3ec8acdbbb3dc22b0274a949a714bcd5966373e?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ3JvdXBieS5weQ==) | `95.48% <100%> (+0.51%)` | :arrow_up: |
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/compare/94720d951b4e804bab72abc33dffeb2186ecb310...f3ec8acdbbb3dc22b0274a949a714bcd5966373e?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.86% <100%> (-0.1%)` | :arrow_down: |
| [pandas/core/reshape.py](https://codecov.io/gh/pandas-dev/pandas/compare/94720d951b4e804bab72abc33dffeb2186ecb310...f3ec8acdbbb3dc22b0274a949a714bcd5966373e?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvcmVzaGFwZS5weQ==) | `99.27% <100%> (-0.01%)` | :arrow_down: |
| [pandas/core/sorting.py](https://codecov.io/gh/pandas-dev/pandas/compare/94720d951b4e804bab72abc33dffeb2186ecb310...f3ec8acdbbb3dc22b0274a949a714bcd5966373e?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvc29ydGluZy5weQ==) | `97.81% <100%> (+0.03%)` | :arrow_up: |
| [pandas/core/series.py](https://codecov.io/gh/pandas-dev/pandas/compare/94720d951b4e804bab72abc33dffeb2186ecb310...f3ec8acdbbb3dc22b0274a949a714bcd5966373e?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvc2VyaWVzLnB5) | `94.79% <85.71%> (-0.08%)` | :arrow_down: |
| [pandas/indexes/multi.py](https://codecov.io/gh/pandas-dev/pandas/compare/94720d951b4e804bab72abc33dffeb2186ecb310...f3ec8acdbbb3dc22b0274a949a714bcd5966373e?src=pr&el=tree#diff-cGFuZGFzL2luZGV4ZXMvbXVsdGkucHk=) | `96.37% <90.69%> (-0.22%)` | :arrow_down: |
| [pandas/io/gbq.py](https://codecov.io/gh/pandas-dev/pandas/compare/94720d951b4e804bab72abc33dffeb2186ecb310...f3ec8acdbbb3dc22b0274a949a714bcd5966373e?src=pr&el=tree#diff-cGFuZGFzL2lvL2dicS5weQ==) | `25% <0%> (-58.34%)` | :arrow_down: |
| [pandas/indexes/base.py](https://codecov.io/gh/pandas-dev/pandas/compare/94720d951b4e804bab72abc33dffeb2186ecb310...f3ec8acdbbb3dc22b0274a949a714bcd5966373e?src=pr&el=tree#diff-cGFuZGFzL2luZGV4ZXMvYmFzZS5weQ==) | `96.08% <0%> (-0.06%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/15700?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/15700?src=pr&el=footer). Last update [94720d9...f3ec8ac](https://codecov.io/gh/pandas-dev/pandas/compare/94720d951b4e804bab72abc33dffeb2186ecb310...f3ec8acdbbb3dc22b0274a949a714bcd5966373e?src=pr&el=footer&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).
going to roll this into #15694