I have this isolated code snippet that should be self-explanatory:
import string
import itertools
import numpy as np
import timeit
index = list(itertools.product(range(100_000), string.ascii_uppercase))
df = pd.DataFrame(index, columns=['i', 'p'])
df['n'] = np.random.randn(len(df))
df_2 = df.set_index('i', drop=False)
df = df.set_index(['i', 'p'], drop=False)
print('One level multiindex loc', timeit.timeit(lambda: df.loc[1000], number=100))
print('Search by column', timeit.timeit(lambda: df[df.i == 1000], number=100))
print('Non unique index loc', timeit.timeit(lambda: df_2.loc[1000], number=100))
Results:
One level multiindex loc 0.8600521469925297
Search by column 0.23243567100143991
Non unique index loc 0.03276521500083618
I need to get group of rows by value of i (1000 in this example) and I am looking into different access patterns. What I absolutely don't get is why looking up by the first level of a MultiIndex is so slow? I understood the concept of the MultiIndex by it being fast if you are following the hierarchy.
Edit results vary significantly based on pandas version and now more looks like there is something broken with MultiIndex in pandas 1.1.0.
Here are results for 0.25:
print('One level multiindex loc 1', timeit.timeit(lambda: df.loc[1000], number=10000))
print('One level multiindex loc 2', timeit.timeit(lambda: df.loc[(1000, ), :], number=10000))
print('Search by column', timeit.timeit(lambda: df[df.i == 1000], number=10000))
print('Non unique index loc', timeit.timeit(lambda: df_2.loc[1000], number=10000))
One level multiindex loc 1 3.5869441789999996
One level multiindex loc 2 4.696559950999983
Search by column 26.05316364800001
Non unique index loc 2.409704655000013
To compare with 10000 repetitions with pandas==1.1.0:
One level multiindex loc 1 74.58197712
One level multiindex loc 2 74.65480156499996
Search by column 26.241522830999997
Non unique index loc 0.5789623329999927
pandas==1.0.5:
One level multiindex loc 1 75.16352942799999
One level multiindex loc 2 81.75229192099998
Search by column 25.121312993000004
Non unique index loc 2.481764503999983