Tengo un pandas.DataFrame
de la forma
index df df1 0 0 111 1 1 111 2 2 111 3 3 111 4 0 111 5 2 111 6 3 111 7 0 111 8 2 111 9 3 111 10 0 111 11 1 111 12 2 111 13 3 111 14 0 111 15 1 111 16 2 111 17 3 111 18 1 111 19 2 111 20 3 111
Quiero crear un marco de datos en el que la columna df repita 0,1,2,3. Pero hay algo que falta en los datos. Estoy tratando de completar los espacios en blanco con 0 agregando valores de fila. Aquí está mi resultado esperado:
index df df1 0 0 111 1 1 111 2 2 111 3 3 111 4 0 111 5 1 0 6 2 111 7 3 111 8 0 111 9 1 0 10 2 111 11 3 111 12 0 111 13 1 111 14 2 111 15 3 111 16 0 111 17 1 111 18 2 111 19 3 111 20 0 0 21 1 111 22 2 111 23 3 111
¿Cómo puedo conseguir esto?
¿Qué debo hacer si mi entrada es la siguiente?
index df1 df2 0 0 111 1 1 111 2 2 111 3 3 111 4 0 111 5 3 111 6 1 111 7 2 111
Aquí está mi resultado esperado:
index df1 df2 0 0 111 1 1 111 2 2 111 3 3 111 4 0 111 5 1 0 6 2 0 7 3 111 8 0 0 9 1 111 10 2 111 11 3 0
Puede configurar una agrupación personalizada para detectar cuándo los números crecientes en "df" se restablecen a un valor más bajo (o igual).
Luego vuelva a indexar usando el producto de los valores únicos en "df" y los grupos únicos.
Finalmente, vuelva a trabajar en la salida con una combinación de fillna
/ reset_index
/ rename_axis
:
# uncomment below if "index" is not the index # df = df.set_index('index') # find positions where "df" resets and make groups groups = df['df'].diff().le(0).cumsum() (df.set_index([groups, 'df'], drop=True) # set custom groups and "df" as index .reindex(pd.MultiIndex.from_product([groups.unique(), # reindex with all range(4), # combinations ], names=['group', 'df'])) .fillna(0, downcast='infer') # set missing values as zero .reset_index('df') # all below to restore a range index .reset_index(drop=True) .rename_axis('index') )
producción:
df df1 index 0 0 111 1 1 111 2 2 111 3 3 111 4 0 111 5 1 0 6 2 111 7 3 111 8 0 111 9 1 0 10 2 111 11 3 111 12 0 111 13 1 111 14 2 111 15 3 111 16 0 111 17 1 111 18 2 111 19 3 111 20 0 0 21 1 111 22 2 111 23 3 111
salida en el segundo ejemplo:
df1 df2 index 0 0 111 1 1 111 2 2 111 3 3 111 4 0 111 5 1 0 6 2 0 7 3 111 8 0 0 9 1 111 10 2 111 11 3 0
Usando la idea de @Mozway y combinándola con algunas funciones auxiliares de pyjanitor
, los valores faltantes se pueden hacer explícitos y luego completar. Nuevamente, esta es solo otra opción:
# pip install pyjanitor import pandas as pd import janitor as jn (df.assign(temp = df.df.diff().le(0).cumsum()) .complete('df', 'temp') # helper function .fillna(0) # relevant if you care about the order .sort_values('temp', kind='mergesort') # helper function .select_columns('df*') # or .drop(columns='temp') ) df df1 0 0 111.0 6 1 111.0 12 2 111.0 18 3 111.0 1 0 111.0 7 1 0.0 13 2 111.0 19 3 111.0 2 0 111.0 8 1 0.0 14 2 111.0 20 3 111.0 3 0 111.0 9 1 111.0 15 2 111.0 21 3 111.0 4 0 111.0 10 1 111.0 16 2 111.0 22 3 111.0 5 0 0.0 11 1 111.0 17 2 111.0 23 3 111.0
Puede configurar el grupo en secuencia creciente de la columna df
. Luego use .unstack()
y .stack()
, de la siguiente manera:
group = df['df'].le(df['df'].shift()).cumsum() # new group if column `df` <= `df` last entry df_out = (df.set_index([group, 'df']) # set `group` and column `df` as index .unstack(fill_value=0) # unstack `df` and fill missing entry of `df` in [0,1,2,3] as 0 for `df1` .stack() # stack back to original shape .droplevel(0) # drop `group` from index .reset_index() # restore `df` from index back to data column )
Resultado:
print(df_out) df df1 0 0 111 1 1 111 2 2 111 3 3 111 4 0 111 5 1 0 6 2 111 7 3 111 8 0 111 9 1 0 10 2 111 11 3 111 12 0 111 13 1 111 14 2 111 15 3 111 16 0 111 17 1 111 18 2 111 19 3 111 20 0 0 21 1 111 22 2 111 23 3 111
Para la entrada editada, use códigos similares:
group = df['df1'].le(df['df1'].shift()).cumsum() df_out2 = (df.set_index([group, 'df1']) .unstack(fill_value=0) .stack() .droplevel(0) .reset_index() )
Resultado:
print(df_out2) df1 df2 0 0 111 1 1 111 2 2 111 3 3 111 4 0 111 5 1 0 6 2 0 7 3 111 8 0 0 9 1 111 10 2 111 11 3 0