BUG: Passing multiple levels to stack when having mixed integer/string level names (#8584)

closes #8584 

Stacking should now work as expected for the cases described in the bug report (#8584). So we can pass a list of both ints and strs to `DataFrame.stack`, provided the ints are level names. Mixed ints and strs when the ints aren't level names raises `ValueError`, but that's unchanged.

I've added a new hidden method `_swaplevel_assume_numbers` since the main cause of the bug was
ambiguity between ints as names and ints as level numbers, and this allows us to make sure the
swap is done correctly once we reach that point. 

Another alternative would have been to add an `as_numbers=True` flag to the existing `swaplevel` method. We could keep existing behaviour intact by having the default be `as_numbers=False`. If that
seems like the better option now that you've seen the PR, let me know and it should be pretty easy
to switch.

```python
import pandas as pd
from pandas import DataFrame, MultiIndex
from numpy.random import randn

columns = MultiIndex.from_tuples([('A', 'cat', 'long'), ('B', 'cat', 'long'), ('A', 'dog', 'short'), ('B', 'dog', 'short')],
                                 names=['exp', 'animal', 'hair_length'])
df = DataFrame(randn(4, 4), columns=columns)

df.columns.names = ['exp', 'animal', 1]
print(df.stack(level=['animal', 1]))

# exp                    A         B
#   animal 1                        
# 0 cat    long   0.758850  0.327957
#   dog    short  0.429752  0.236901
# 1 cat    long   0.572633  1.057861
#   dog    short  0.802539  1.321191
# 2 cat    long   0.283352  0.088000
#   dog    short -0.814458 -1.688529
# 3 cat    long   2.009912 -1.738292
#   dog    short  1.272569 -0.133434

df.columns.names = ['exp', 'animal', 0]
print(df.stack(level=['animal', 0]))

# exp                    A         B
#   animal 0                        
# 0 cat    long   0.758850  0.327957
#   dog    short  0.429752  0.236901
# 1 cat    long   0.572633  1.057861
#   dog    short  0.802539  1.321191
# 2 cat    long   0.283352  0.088000
#   dog    short -0.814458 -1.688529
# 3 cat    long   2.009912 -1.738292
#   dog    short  1.272569 -0.133434
```
We could use the same `_convert_level_number()` function to make sure we get `names[0]` in case of a potential conflict, if that's what you mean. This is the section that was raising the lexsort depth error in the original bug report, which is sort of separate from stacking the wrong levels.

Want me to replace the if/else with the `_convert_level_number()` function?