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
3 respuestas
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.
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
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
Preguntas relacionadas
Nuevas preguntas
python
Python es un lenguaje de programación multipropósito, de tipificación dinámica y de múltiples paradigmas. Está diseñado para ser rápido de aprender, comprender y usar, y hacer cumplir una sintaxis limpia y uniforme. Tenga en cuenta que Python 2 está oficialmente fuera de soporte a partir del 01-01-2020. Aún así, para preguntas de Python específicas de la versión, agregue la etiqueta [python-2.7] o [python-3.x]. Cuando utilice una variante de Python (por ejemplo, Jython, PyPy) o una biblioteca (por ejemplo, Pandas y NumPy), inclúyala en las etiquetas.