Estoy trabajando en un marco de datos de tamaño mediano y después de mucha manipulación de datos termino con el siguiente DataFrame:

        id_1   id_2  flag_1  flag_2  flag_3
0       000d  5d238       0       0       0
1       001v  5cdd4       0       0       0
2       001v  5d36e       1       1       1
3       001v  5d53c       1       1       1
4       001c  5cc1a       1       0       0
...      ...    ...     ...     ...     ...
124809  003n  5d89f       0       0       0
124810  003n  5d8a6       1       0       0
124811  003n  5d8b1       1       1       0
124812  003n  5d8b3       1       1       1
124813  003n  5d8cc       1       1       1

Aquí está el código que puede usar para recrear el marco de datos:

import pandas as pd
a = {'id_1':['000d','001v','001v','001v','001c','003n','003n','003n','003n','003n'],'id_2':['5d238','5cdd4','5d36e','5d35c','5cc1a','5d89f','5d8a6','5d8b1','5d8b3','5d8cc'],'flag_1':[0,0,1,1,1,0,1,1,1,1],'flag_2':[0,0,1,1,0,0,0,1,1,1],'flag_3':[0,0,1,1,0,0,0,0,1,1]}
pd.DataFrame(a)

Estoy tratando de crear una condición para que cada vez que aparezca un 1 en la columna, todas las filas posteriores sean obligatorias a ser 0, para cada id_1 único y para cada columna de forma independiente. Intenté usar groupby('id_1')['flag_1'].max() para crear un marco de datos adicional y luego agregarlo, pero no funciona (o lo más probable es que esté haciendo algo mal). También intenté crear una lista de valores únicos de id_1 y luego iterar sobre cada uno de ellos para encontrar la primera fila con el valor 1 y forzar a todos los demás a 0, y luego repetir el ciclo para el otras columnas, pero resulta muy ineficiente y consume mucho tiempo. Mi salida esperada es:

        id_1   id_2  flag_1  flag_2  flag_3
0       000d  5d238       0       0       0
1       001v  5cdd4       0       0       0
2       001v  5d36e       1       1       1
3       001v  5d53c       0       0       0
4       001c  5cc1a       1       0       0
...      ...    ...     ...     ...     ...
124809  003n  5d89f       0       0       0
124810  003n  5d8a6       1       0       0
124811  003n  5d8b1       0       1       0
124812  003n  5d8b3       0       0       1
124813  003n  5d8cc       0       0       0
1
Celius Stingher 30 sep. 2019 a las 18:19

3 respuestas

La mejor respuesta

Puedes probar esto:

df.assign(**df.groupby('id_1')[cols].apply(lambda x: x.ne(1).shift().cumprod() * x).fillna(df))

Salida:

   id_1   id_2 flag_1 flag_2 flag_3
0   00d  5d238      0      0      0
1  001v  5cdd4      0      0      0
2  001v  5d36e      1      1      1
3  001v  5d35c      0      0      0
4  001c  5cc1a      1      0      0
5  003N  5d89f      0      0      0
6  003N  5d8a6      1      0      0
7  003N  5d8b1      0      1      0
8  003N  5d8b3      0      0      1
9  003N  5d8cc      0      0      0

Básicamente, usando ne y cumprod en cada grupo. Cuando flag = 1, ne (1) devuelve cero y usa cumprod para mantener cero.

3
Scott Boston 30 sep. 2019 a las 15:30

Puede usar DataFrame.groupby con aplicar :

df.groupby('id_1',as_index=False)['flag_1','flag_2','flag_3'].apply(lambda x:  (x.eq(1))&(x.shift(1).eq(0)) ).astype(int)
print(df)

   id_1   id_2  flag_1  flag_2  flag_3
0   00d  5d238       0       0       0
1  001v  5cdd4       0       0       0
2  001v  5d36e       1       1       1
3  001v  5d35c       0       0       0
4  001c  5cc1a       0       0       0
5  003N  5d89f       0       0       0
6  003N  5d8a6       1       0       0
7  003N  5d8b1       0       1       0
8  003N  5d8b3       0       0       1
9  003N  5d8cc       0       0       0
2
ansev 30 sep. 2019 a las 15:47

Aquí hay una manera:

# the flag columns
# can be df.filter(like='flag')
flags = df.iloc[:,2:]

# find the first 1.0 rows for each group
maxidx = flags.where(flags.eq(1)).groupby(df['id_1']).transform('idxmax')

# mask these rows with 1 else 0
df.iloc[:,2:] = np.where(flags.index.values[:,None] == maxidx, 1, 0)

Salida:

   id_1   id_2  flag_1  flag_2  flag_3
0   00d  5d238       0       0       0
1  001v  5cdd4       0       0       0
2  001v  5d36e       1       1       1
3  001v  5d35c       0       0       0
4  001c  5cc1a       1       0       0
5  003N  5d89f       0       0       0
6  003N  5d8a6       1       0       0
7  003N  5d8b1       0       1       0
8  003N  5d8b3       0       0       1
9  003N  5d8cc       0       0       0
1
Quang Hoang 30 sep. 2019 a las 15:35
58170839