MultiIndex look up all indices that have a given value for a given level
<p>I am using a <code>pandas.Series</code> with a <code>MultiIndex</code> for a bidirectional weighted lookup. I thought it should be easy to also find the corresponding other levels for a given level using the MultiIndex, but I cannot find a simple function <code>other</code> that does something like the following:</p>

<pre><code>&gt;&gt;&gt; index=pandas.MultiIndex.from_tuples(
...                  [(0, 0),(1,2),(3,4),(5,6),(5,7),(8,0),(9,0)],
...                  names=["concept", "word"])
&gt;&gt;&gt; other(index, "word", 0)
{0, 8, 9}
&gt;&gt;&gt; other(index, "concept", 3)
{4}
&gt;&gt;&gt; other(index, "word", 6)
{5}
</code></pre>

<p>I'm happy to specify level numbers instead of level names and to get any iterable out, not necessarily a set. I only have a 2-level multi-index, so I don't care about how to generalize to a higher-level multi-indices, or even whether it does generalize.</p>

<p>I would be slightly unhappy if this involves iterating over all entries in the MultiIndex and comparing them, because I thought indices are somewhat like multi-key hash tables.</p>

<p><strong>Approach 1:</strong></p>

<p>You could build up a custom function using a vectorized approach as shown:</p>

<pre><code>def other(index, slicing, value):
    arr = np.column_stack(index.values.tolist())
    return (np.delete(arr, slicing, axis=0)[0][arr[slicing]==value])
</code></pre>

<p><em>Usage:</em></p>

<pre><code>other(index, slicing=index.names.index('word'), value=0)
# array([0, 8, 9])
</code></pre>

<p><em>Timings:</em></p>

<pre><code>%timeit other(index, slicing=index.names.index('word'), value=0)
10000 loops, best of 3: 43.9 Âµs per loop
</code></pre>

<hr>

<p><strong>Approach 2:</strong></p>

<p>If you want to use an inbuilt method which gives you the result by mere plugging in values to the respective args, you could opt for <a href="https://pandas-docs.github.io/pandas-docs-travis/generated/pandas.MultiIndex.get_loc_level.html#pandas.MultiIndex.get_loc_level" rel="nofollow"><code>get_loc_level</code></a> which gives you the integer location slice corresponding to a label, like so:</p>

<p><em>Demo:</em></p>

<pre><code>index.get_loc_level(key=3, level='concept')[1].ravel()
# array([4], dtype=int64)

index.get_loc_level(key=0, level='word')[1].ravel()
# array([0, 8, 9], dtype=int64)

index.get_loc_level(key=6, level='word')[1].ravel()
# array([5], dtype=int64)
</code></pre>

<p><em>Timings:</em></p>

<pre><code>%timeit index.get_loc_level(key=0, level='word')[1].ravel()
10000 loops, best of 3: 129 Âµs per loop
</code></pre>

<p>So, you get a 3x boost using a custom function rather than implementing using 
the built-in methods for the 2-level multi-index <code>DF</code> given.</p>

python pandas indexing multi-index