Saltar al contenido

pandas – encontrar la primera aparición

No olvides que en la informática cualquier problema casi siempere suele tener más de una soluciones, por lo tanto nosotros te mostramos la mejor y más eficiente.

Solución:

idxmax y argmax devolverá la posición del valor máximo o la primera posición si el valor máximo se produce más de una vez.

utilizar idxmax en df.A.ne('a')

df.A.ne('a').idxmax()

3

o la numpy equivalente

(df.A.values != 'a').argmax()

3

Sin embargo, si A ya ha sido ordenado, entonces podemos usar searchsorted

df.A.searchsorted('a', side='right')

array([3])

O la numpy equivalente

df.A.values.searchsorted('a', side='right')

3

Descubrí que hay una función first_valid_index para Pandas DataFrames que hará el trabajo, se podría usar de la siguiente manera:

df[df.A!='a'].first_valid_index()

3

Sin embargo, esta función parece ser muy lenta. Incluso tomar el primer índice del marco de datos filtrado es más rápido:

df.loc[df.A!='a','A'].index[0]

A continuación, comparo el tiempo total (seg) de repetir los cálculos 100 veces para estas dos opciones y todos los códigos anteriores:

                      total_time_sec    ratio wrt fastest algo
searchsorted numpy:        0.0007        1.00
argmax numpy:              0.0009        1.29
for loop:                  0.0045        6.43
searchsorted pandas:       0.0075       10.71
idxmax pandas:             0.0267       38.14
index[0]:                  0.0295       42.14
first_valid_index pandas:  0.1181      168.71

Observe que numpy’s searchsorted es el ganador y first_valid_index muestra el peor rendimiento. En general, los algoritmos numpy son más rápidos y el ciclo for no funciona tan mal, pero es solo porque el marco de datos tiene muy pocas entradas.

Para un marco de datos con 10 000 entradas donde las entradas deseadas están más cerca del final, los resultados son diferentes, y la búsqueda ordenada ofrece el mejor rendimiento:

                     total_time_sec ratio wrt fastest algo
searchsorted numpy:        0.0007       1.00
searchsorted pandas:       0.0076      10.86
argmax numpy:              0.0117      16.71
index[0]:                  0.0815     116.43
idxmax pandas:             0.0904     129.14
first_valid_index pandas:  0.1691     241.57
for loop:                  9.6504   13786.29

El código para producir estos resultados es el siguiente:

import timeit

# code snippet to be executed only once 
mysetup = '''import pandas as pd
import numpy as np
df = pd.DataFrame("A":['a','a','a','b','b'],"B":[1]*5)
'''

# code snippets whose execution time is to be measured   
mycode_set = ['''
df[df.A!='a'].first_valid_index()
''']
message = ["first_valid_index pandas:"]

mycode_set.append( '''df.loc[df.A!='a','A'].index[0]''')
message.append("index[0]: ")

mycode_set.append( '''df.A.ne('a').idxmax()''')
message.append("idxmax pandas: ")

mycode_set.append(  '''(df.A.values != 'a').argmax()''')
message.append("argmax numpy: ")

mycode_set.append( '''df.A.searchsorted('a', side='right')''')
message.append("searchsorted pandas: ")

mycode_set.append( '''df.A.values.searchsorted('a', side='right')''' )
message.append("searchsorted numpy: ")

mycode_set.append( '''for index in range(len(df['A'])):
    if df['A'][index] != 'a':
        ans = index
        break
        ''')
message.append("for loop: ")

total_time_in_sec = []
for i in range(len(mycode_set)):
    mycode = mycode_set[i]
    total_time_in_sec.append(np.round(timeit.timeit(setup = mysetup,
         stmt = mycode, number = 100),4))

output = pd.DataFrame(total_time_in_sec, index = message, 
                      columns = ['total_time_sec' ])
output["ratio wrt fastest algo"] = 
np.round(output.total_time_sec/output["total_time_sec"].min(),2)

output = output.sort_values(by = "total_time_sec")
display(output)

Para el marco de datos más grande:

mysetup = '''import pandas as pd
import numpy as np
n = 10000
lt = ['a' for _ in range(n)]
b = ['b' for _ in range(5)]
lt[-5:] = b
df = pd.DataFrame("A":lt,"B":[1]*n)
'''

Recuerda que puedes difundir esta sección si lograste el éxito.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *