La situación

Estoy clasificando las filas en un DataFrame usando un determinado clasificador basado en los valores en una columna en particular. Mi objetivo es agregar los resultados a una nueva columna u otra dependiendo de ciertas condiciones. El código, tal como está, se parece a esto:

df = pd.DataFrame({'A': [list with classifier ids],  # Only 3 ids, One word strings
                   'B': [List of text to be classified],  # Millions of unique rows, lines of text around 5-25 words long
                   'C': [List of the old classes]}  # Hundreds of possible classes, four digit integers stored as strings

df.sort_values('A', inplace=True)

new_col1, new_col2 = [], []
for name, group in df.groupby('A', sort=False):
    classifier = classy_dict[name]
    vectors = vectorize(group.B.values)

    preds = classifier.predict(vectors)
    scores = classifier.decision_function(vectors)

    for tup in zip(preds, scores, group.C.values):
        if tup[2] == tup[0]:
            new_col1.append(np.nan)
            new_col2.append(tup[2])

        else:
            new_col1.append(str(classifier.classes_[tup[1].argsort()[-5:]]))
            new_col2.append(np.nan)

df['D'] = new_col1
df['E'] = new_col2

La cuestión

Me preocupa que groupby no se repita en orden de aparición de arriba hacia abajo como esperaba. Orden de iteración cuando sort=False no está cubierto en los documentos

Mis expectativas

Todo lo que busco aquí es alguna afirmación de que groupby('col', sort=False) itera en el orden de aparición de arriba hacia abajo que espero. Si hay una mejor manera de hacer que todo esto funcione, se agradecen las sugerencias.

Aquí está el código que usé para probar mi teoría en el orden de iteración sort=False:

from numpy.random import randint
import pandas as pd
from string import ascii_lowercase as lowers

df = pd.DataFrame({'A': [lowers[randint(3)] for _ in range(100)],
                   'B': randint(10, size=100)})

print(df.A.unique())  # unique values in order of appearance per the docs

for name, group in df.groupby('A', sort=False):
    print(name)

Editar: El código anterior hace que parezca como si actuara de la manera que espero, pero me gustaría alguna prueba más innegable, si está disponible.

4
Eric Ed Lohmar 8 nov. 2017 a las 20:20

2 respuestas

La mejor respuesta

Sí, cuando pasa sort=False se conserva el orden de la primera aparición. El código fuente de groupby es un poco opaco, pero hay una función groupby.ngroup que responde completamente a esta pregunta, ya que le indica directamente el orden en el que ocurre la iteración.

def ngroup(self, ascending=True):
    """
    Number each group from 0 to the number of groups - 1.
    This is the enumerative complement of cumcount.  Note that the
    numbers given to the groups match the order in which the groups
    would be seen when iterating over the groupby object, not the
    order they are first observed.
    ""

Datos de @coldspeed

df['sort=False'] = df.groupby('col', sort=False).ngroup()
df['sort=True'] = df.groupby('col', sort=True).ngroup()

Salida:

    col  sort=False  sort=True
0   16           0          7
1    1           1          0
2   10           2          5
3   20           3          8
4    3           4          2
5   13           5          6
6    2           6          1
7    5           7          3
8    7           8          4

Cuando sort=False itera basándose en la primera aparición, cuando sort=True ordena los grupos y luego itera.

5
ALollz 28 sep. 2018 a las 15:11

Hagamos una pequeña prueba empírica. Puede iterar sobre groupby y ver el orden en el que se repiten los grupos.

df

   col
0   16
1    1
2   10
3   20
4    3
5   13
6    2
7    5
8    7

for c, g in df.groupby('col', sort=False):
      print(c)  

16
1
10
20
3
13
2
5
7

Parece que el orden se conserva.

1
cs95 8 nov. 2017 a las 17:50