Tengo un marco de datos donde me gustaría mantener todas las columnas en mi conjunto de datos original y crear una nueva columna dinámica basada en el conjunto de datos existente.
Datos
stat1 stat2 id q122con q122av q122con q122av q222con q222av q222con q222av 50 1000 aa 40 10 900 100 50 0 1000 0 100 2000 bb 50 50 1500 500 75 25 1900 100Deseado
stat1 stat2 id date con av con av 50 1000 aa q122 40 10 900 100 50 1000 aa q222 50 0 1000 0 100 2000 bb q122 50 50 1500 500 100 2000 bb q222 75 25 1900 100Haciendo
df.pivot(index="id", columns="date", values=["con", "av"])Sin embargo, no obtengo las columnas completas dentro de mi conjunto de datos. Cualquier sugerencia es apreciada.
Muchos de sus problemas aquí tienen que ver con nombres de columnas duplicados:
import pandas as pd # Duplicating input dataframe with clipboard and remove dot numbers assign for duplicate column headers df = pd.read_clipboard() df.columns = df.columns.str.split('.').str[0] # Set index to move first three columns into index df = df.set_index(['stat1','stat2','id']) # Use groupby and cumcount to get order of duplicate column headers cols = df.groupby(df.columns, axis=1).cumcount().rename('No').reset_index() # Use str.extract to split "dates" from av and con with regex cols = cols['index'].str.extract('(q\d{3})(.*)').join(cols).drop('index', axis=1) # Create a new multiIndex column header df.columns = pd.MultiIndex.from_frame(cols, names=['date','av','con']) # Reshape dataframe by stacking the outer most column header to the dataframe index # And moved those columns from the index back into the dataframe with reset_index df_out = df.stack(0).reset_index() # Flatten headers back to one level df_out.columns = [f'{i}_{j}' if j else f'{i}' for i, j in df_out.columns] # And print print(df_out)Producción:
stat1 stat2 id date av av_1 con con_1 0 50 1000 aa q122 10 100 40 900 1 50 1000 aa q222 0 0 50 1000 2 100 2000 bb q122 50 500 50 1500 3 100 2000 bb q222 25 100 75 1900Una línea larga de wide_to_long
pd.wide_to_long(df.set_index(['stat1','stat2','id']).stack().groupby(level=[0,1,2,3]).agg(list).apply(pd.Series).unstack().stack(level=0).reset_index(), stubnames = ['q122','q222'], i = ['stat1','stat2','id','level_3'],j = 'date',suffix='\\w+').stack().unstack(level=[-3,-2]) Out[140]: level_3 0 1 date av con av con stat1 stat2 id 50 1000 aa q122 10 40 100 900 q222 0 50 0 1000 100 2000 bb q122 50 50 500 1500 q222 25 75 100 1900No es tan bonito como las otras soluciones, pero funciona:
out = df.set_index(['stat1','stat2','id']).stack() idx = pd.DataFrame(out.index.tolist()) count = idx.groupby(idx.columns.tolist()).cumcount().tolist() idx = (idx.iloc[:,:-1] .merge(idx.iloc[:,-1].str.extract('(q\d{3})(.*)'), left_index=True, right_index=True)) out.index = pd.MultiIndex.from_frame(idx, names=['stat1','stat2','id','date','val']) out = (out .to_frame() .assign(count=count) .groupby(['count','val','stat1','stat2','id','date']) .first() .unstack(level=[0,1]) .droplevel([0,1], axis=1) .reset_index() ) print(out)Producción:
val stat1 stat2 id date av con av con 0 50 1000 aa q122 10 40 100 900 1 50 1000 aa q222 0 50 0 1000 2 100 2000 bb q122 50 50 500 1500 3 100 2000 bb q222 25 75 100 1900Descubrí una manera más simple. Además, lo anterior produce columnas duplicadas:
df = pd.read_clipboard() out = df.set_index(['stat1', 'stat2', 'id']) out.columns = out.columns.str.split("((av)|(con))", expand = True).droplevel([-2,-3]) out = out.stack(level=0) out.columns = [''.join(col) for col in out.columns] out = out.reset_index().rename(columns={'level_3':'date'})Producción:
stat1 stat2 id date av av.1 con con.1 0 50 1000 aa q122 10 100 40 900 1 50 1000 aa q222 0 0 50 1000 2 100 2000 bb q122 50 500 50 1500 3 100 2000 bb q222 25 100 75 1900