web-dev-qa-db-fra.com

Quel est l'impact sur les performances des index non uniques chez les pandas?

D'après la documentation pandas, j'ai rassemblé que les indices à valeur unique rendent certaines opérations efficaces et que les indices non uniques sont parfois tolérés.

De l'extérieur, il ne semble pas que les indices non uniques soient exploités de quelque manière que ce soit. Par exemple, la requête ix suivante est suffisamment lente pour sembler analyser l'ensemble de la trame de données

In [23]: import numpy as np
In [24]: import pandas as pd
In [25]: x = np.random.randint(0, 10**7, 10**7)
In [26]: df1 = pd.DataFrame({'x':x})
In [27]: df2 = df1.set_index('x', drop=False)
In [28]: %timeit df2.ix[0]
1 loops, best of 3: 402 ms per loop
In [29]: %timeit df1.ix[0]
10000 loops, best of 3: 123 us per loop

(Je me rends compte que les deux requêtes ix ne retournent pas la même chose - c'est juste un exemple que les appels à ix sur un index non unique apparaissent beaucoup plus lentement)

Existe-t-il un moyen d'inciter pandas à utiliser des méthodes de recherche plus rapides comme la recherche binaire sur des indices non uniques et/ou triés?

39
ChrisB

Lorsque l'index est unique, pandas utilisez une table de hachage pour mapper la clé à la valeur O (1). Lorsque l'index n'est pas unique et trié, pandas utilisez la recherche binaire) O (logN), lorsque l'index est aléatoire pandas doivent vérifier toutes les clés de l'index O (N).

Tu peux appeler sort_index méthode:

import numpy as np
import pandas as pd
x = np.random.randint(0, 200, 10**6)
df1 = pd.DataFrame({'x':x})
df2 = df1.set_index('x', drop=False)
df3 = df2.sort_index()
%timeit df1.loc[100]
%timeit df2.loc[100]
%timeit df3.loc[100]

résultat:

10000 loops, best of 3: 71.2 µs per loop
10 loops, best of 3: 38.9 ms per loop
10000 loops, best of 3: 134 µs per loop
81
HYRY

@ HYRY l'a bien dit , mais rien ne le dit tout à fait comme un graphique coloré avec des timings.

enter image description here

Les tracés ont été générés en utilisant perfplot . Code, pour votre référence:

import pandas as pd
import perfplot

_rnd = np.random.RandomState(42)

def make_data(n):    
    x = _rnd.randint(0, 200, n)
    df1 = pd.DataFrame({'x':x})
    df2 = df1.set_index('x', drop=False)
    df3 = df2.sort_index()

    return df1, df2, df3

perfplot.show(
    setup=lambda n: make_data(n),
    kernels=[
        lambda dfs: dfs[0].loc[100],
        lambda dfs: dfs[1].loc[100],        
        lambda dfs: dfs[2].loc[100],
    ],
    labels=['Unique index', 'Non-unique, unsorted index', 'Non-unique, sorted index'],
    n_range=[2 ** k for k in range(8, 23)],
    xlabel='N',
    logx=True,
    logy=True,
    equality_check=False)
14
cs95