Búsqueda vectorizada en un dataframe de pandas

Tengo dos cuadros de datos. . .

df1 es una tabla de la que necesito extraer valores utilizando índices, pares de columnas recuperados de varias columnas en df2.

Veo que hay una función get_value que funciona perfectamente cuando se le da un valor de índice y columna, pero al intentar vectorizar esta función para crear una nueva columna, estoy fallando …

 df1 = pd.DataFrame(np.arange(20).reshape((4, 5))) df1.columns = list('abcde') df1.index = ['cat', 'dog', 'fish', 'bird'] abcde cat 0 1 2 3 4 dog 5 6 7 8 9 fish 10 11 12 13 14 bird 15 16 17 18 19 df1.get_value('bird, 'c') 17 

Ahora, lo que debo hacer es crear una nueva columna completa en df2 : al indexar df1 según el índice, los pares de columnas del animal , las columnas de letter especificadas en df2 vectorizan de manera efectiva la función pd.get_value anterior.

 df2 = pd.DataFrame(np.arange(20).reshape((4, 5))) df2['animal'] = ['cat', 'dog', 'fish', 'bird'] df2['letter'] = list('abcd') 0 1 2 3 4 animal letter 0 0 1 2 3 4 cat a 1 5 6 7 8 9 dog b 2 10 11 12 13 14 fish c 3 15 16 17 18 19 bird d 

Resultando en . . .

  0 1 2 3 4 animal letter looked_up 0 0 1 2 3 4 cat a 0 1 5 6 7 8 9 dog b 6 2 10 11 12 13 14 fish c 12 3 15 16 17 18 19 bird d 18 

Hay una función llamada lookup que hace exactamente esto.

 df2['looked_up'] = df1.lookup(df2.animal, df2.letter) df2 0 1 2 3 4 animal letter looked_up 0 0 1 2 3 4 cat a 0 1 5 6 7 8 9 dog b 6 2 10 11 12 13 14 fish c 12 3 15 16 17 18 19 bird d 18 

Si busca un enfoque un poco más rápido, zip ayudará en caso de un pequeño dataframe, es decir

 k = list(zip(df2['animal'].values,df2['letter'].values)) df2['looked_up'] = [df1.get_value(*i) for i in k] 

Salida:

    0 1 2 3 4 animal letter look_up
 0 0 1 2 3 4 cat a 0
 1 5 6 7 8 9 perro b 6
 2 10 11 12 13 14 peces c 12
 3 15 16 17 18 19 ave d 18

Como John sugirió, puedes simplificar el código, que será mucho más rápido.

  df2['looked_up'] = [df1.get_value(r, c) for r, c in zip(df2.animal, df2.letter)] 

En caso de falta de uso de datos en caso contrario

 df2['looked_up'] = [df1.get_value(r, c) if not pd.isnull(c) | pd.isnull(r) else pd.np.nan for r, c in zip(df2.animal, df2.letter) ] 

Para pequeños marcos de datos

 %%timeit df2['looked_up'] = df1.lookup(df2.animal, df2.letter) 1000 loops, best of 3: 801 µs per loop k = list(zip(df2['animal'].values,df2['letter'].values)) df2['looked_up'] = [df1.get_value(*i) for i in k] 1000 loops, best of 3: 399 µs per loop [df1.get_value(r, c) for r, c in zip(df2.animal, df2.letter)] 10000 loops, best of 3: 87.5 µs per loop 

Para grandes marcos de datos

 df3 = pd.concat([df2]*10000) %%timeit k = list(zip(df3['animal'].values,df3['letter'].values)) df2['looked_up'] = [df1.get_value(*i) for i in k] 1 loop, best of 3: 185 ms per loop df2['looked_up'] = [df1.get_value(r, c) for r, c in zip(df3.animal, df3.letter)] 1 loop, best of 3: 165 ms per loop df2['looked_up'] = df1.lookup(df3.animal, df3.letter) 100 loops, best of 3: 8.82 ms per loop 

lookup y get_value son excelentes respuestas si sus valores existen en el dataframe de búsqueda.

Sin embargo, si tiene pares (fila, columna) que no están presentes en el dataframe de búsqueda, y desea que el valor de búsqueda sea NaNmerge y stack es una forma de hacerlo

 In [206]: df2.merge(df1.stack().reset_index().rename(columns={0: 'looked_up'}), left_on=['animal', 'letter'], right_on=['level_0', 'level_1'], how='left').drop(['level_0', 'level_1'], 1) Out[206]: 0 1 2 3 4 animal letter looked_up 0 0 1 2 3 4 cat a 0 1 5 6 7 8 9 dog b 6 2 10 11 12 13 14 fish c 12 3 15 16 17 18 19 bird d 18 

Prueba con la adición de un par no existente (animal, letra)

 In [207]: df22 Out[207]: 0 1 2 3 4 animal letter 0 0.0 1.0 2.0 3.0 4.0 cat a 1 5.0 6.0 7.0 8.0 9.0 dog b 2 10.0 11.0 12.0 13.0 14.0 fish c 3 15.0 16.0 17.0 18.0 19.0 bird d 4 NaN NaN NaN NaN NaN dummy NaN In [208]: df22.merge(df1.stack().reset_index().rename(columns={0: 'looked_up'}), left_on=['animal', 'letter'], right_on=['level_0', 'level_1'], how='left').drop(['level_0', 'level_1'], 1) Out[208]: 0 1 2 3 4 animal letter looked_up 0 0.0 1.0 2.0 3.0 4.0 cat a 0.0 1 5.0 6.0 7.0 8.0 9.0 dog b 6.0 2 10.0 11.0 12.0 13.0 14.0 fish c 12.0 3 15.0 16.0 17.0 18.0 19.0 bird d 18.0 4 NaN NaN NaN NaN NaN dummy NaN NaN