Pandas: ускорить df.loc на основе значений повторного индекса

У меня есть панды DataFrame

import pandas as pd import numpy as np df = pd.DataFrame({ 'x': ['a', 'b', 'c'], 'y': [1, 2, 2], 'z': ['f', 's', 's'] }).set_index('x') 

из которого я хотел бы выбрать строки на основе значений индекса ( x ) в массиве выбора

 selection = ['a', 'c', 'b', 'b', 'c', 'a'] 

Правильный вывод можно получить, используя df.loc следующим образом

 out = df.loc[selection] 

Проблема, с которой я df.loc – это df.loc работает довольно медленно на больших DataFrames (2-7 миллионов строк). Есть ли способ ускорить эту операцию? Я просмотрел eval() , но, похоже, это не относится к жестко закодированным спискам значений индекса, подобных этому. Я также думал об использовании pd.DataFrame.isin , но это пропускает значения повторения (только возвращает строку для каждого уникального элемента при selection ).

Вы можете получить приличное ускорение, используя reindex вместо loc :

 df.reindex(selection) 

Сроки (версия 0.17.0):

 >>> selection2 = selection * 100 # a larger list of labels >>> %timeit df.loc[selection2] 100 loops, best of 3: 2.54 ms per loop >>> %timeit df.reindex(selection2) 1000 loops, best of 3: 833 µs per loop 

Эти два метода принимают разные пути (следовательно, разность скоростей).

loc создает новый DataFrame, обращаясь к get_indexer_non_unique который обязательно более сложный, чем простой get_indexer (используется для уникальных значений).

С другой стороны, тяжелая работа в reindex , по-видимому, выполняется с помощью функций take_* в generate.pyx . Эти функции выглядят быстрее с целью создания нового DataFrame.

Вы можете попробовать merge :

 df = pd.DataFrame({ 'x': ['a', 'b', 'c'], 'y': [1, 2, 2], 'z': ['f', 's', 's'] }) df1 = pd.DataFrame({'x':selection}) In [21]: pd.merge(df1,df,on='x', how='left') Out[21]: xyz 0 a 1 f 1 c 2 s 2 b 2 s 3 b 2 s 4 c 2 s 5 a 1 f