Tengo una lista de DataFrames. Cada uno de estos DataFrames se ve así:

df_list[0] =

       place place2 value1 value2
    0   x     a     10     0
    1   y     a     15     10
    2   z     b     5      10

Para darte un ejemplo concreto te mostraré dos más:

df_list[1] =     

       place place2 value1 value2
    0   x     a     20     20
    1   y     a     0      0

df_list[2]=

       place place2 value1 value2
    0   x     a     50     10
    1   y     a     30     20
    2   z     b     0      40

Como puede ver, no cada uno de estos marcos de datos contiene todos los "lugares" posibles. Sin embargo, 'place2' siempre está asociado al mismo 'lugar'.

Me gustaría tener un DataFrame final donde pudiera ver los 3 primeros 'valor1' y 'valor2' y su "i" asociada como en df_list[i], para cada 'lugar'. El formato realmente no importa, pero por ejemplo, podría verse así:

   place place2 v1_1st v1_1st_i v2_1st v2_1st_i v1_2nd v1_2nd_i v2_2nd v2_2nd_i v1_3rd v1_3rd_i ...
   x     a      50     2         20.    1       20.     1.      10.     0.       10.    2
   y     a      30     2         20.    2.      15.     0.      10.     0.       0.     1
   z     b      5      0         40.    2.      0.      2.      10.     0.       NaN.   NaN

Gracias por su paciencia conmigo ! besos y abrazos

1
jeanbeau 2 dic. 2020 a las 20:35

2 respuestas

La mejor respuesta

Necesito algunos pasos aquí.

Primero concatenamos todos los dfs de df_list mientras agregamos una columna a cada uno que realiza un seguimiento del índice de ese df en la lista, lo colocamos en la columna di:

df_ag = pd.concat([d.assign(di = n) for n,d in enumerate(df_list)], axis=0, ignore_index=True)
df_ag

Produce

    place    place2      value1    value2    di
--  -------  --------  --------  --------  ----
 0  x        a               10         0     0
 1  y        a               15        10     0
 2  z        b                5        10     0
 3  x        a               20        20     1
 4  y        a                0         0     1
 5  x        a               50        10     2
 6  y        a               30        20     2
 7  z        b                0        40     2

Trataremos a value1 y value2 por separado. Para value1, agrupamos por ['place', 'place2'], buscamos los 3 más grandes por grupo y los clasificamos (a través de reset_index() dentro de cada grupo)

df_agv1 = df_ag.groupby(['place','place2']).apply(lambda d: d.nlargest(3, 'value1').reset_index(drop=True))
df_agv1

Esto produce


                place   place2  value1  value2  di
place   place2                      
x       a   0   x       a       50      10      2
            1   x       a       20      20      1
            2   x       a       10      0       0
y       a   0   y       a       30      20      2
            1   y       a       15      10      0
            2   y       a       0       0       1
z       b   0   z       b       5       10      0
            1   z       b       0       40      2

Esto ya tiene la información que necesitamos (columnas value1 y di). Suponiendo que desea que el formato se acerque más al formato que especificó, debemos extraer value1 y di para cada grupo. Podemos hacerlo así:

df_agv1 = df_agv1.drop(columns = ['place','place2','value2']).unstack(level=2)
df_agv1.columns = df_agv1.columns.to_flat_index()
df_agv1

Que produce

              ('value1', 0)    ('value1', 1)    ('value1', 2)    ('di', 0)    ('di', 1)    ('di', 2)
----------  ---------------  ---------------  ---------------  -----------  -----------  -----------
('x', 'a')               50               20               10            2            1            0
('y', 'a')               30               15                0            2            0            1
('z', 'b')                5                0              nan            0            2          nan

Y esto es lo que pediste por value1. Es posible que desee cambiar el nombre de las etiquetas de las columnas si no le gustan estas

Entonces podemos hacer lo mismo para value2 cambiando value1 & lt; - & gt; value2 en los comandos anteriores, para producir df_agv2, no repito los pasos aquí

Si quieres unir los dos, puedes hacerlo con algo como

pd.concat([df_agv1,df_agv2], axis=1)
0
piterbarg 2 dic. 2020 a las 22:41

Otra opción

df1 = pd.DataFrame([['x', 'a', 10, 0], ['y', 'a', 15, 10], ['z', 'b', 5, 10]], columns=['place', 'place2', 'value', 'value2'])
df2 = pd.DataFrame([['x', 'a', 20, 20], ['y', 'a', 0, 0]], columns=['place', 'place2', 'value', 'value2'])
df3 = pd.DataFrame([['x', 'a', 50, 10], ['y', 'a', 30, 20], ['z', 'b', 0, 40]], columns=['place', 'place2', 'value', 'value2'])

df_list =[df1, df2, df3]

Identifique la posición de la lista para cada marco de datos en la lista:

for i, df in enumerate(df_list):
    df['listposition'] = i

Concatenar los marcos de datos:

df_temp = pd.concat(df_list, axis=0)

Analizar el valor y el valor2 por separado pero de la misma manera para fusionarlos más tarde:

df_pv1 = df_temp[['place','place2','value', 'listposition']].sort_values('value')
df_pv1.rename(columns={'listposition': 'listposition'}, inplace=True)
df_pv2 = df_temp[['place','place2', 'value2', 'listposition']].sort_values('value2')
df_pv2.rename(columns={'listposition': 'listposition2'}, inplace=True)

Agrupar por lugar, lugar2 (tomando la cabeza mientras ordenamos las columnas de valor en sentido descendente)

df_ranked_pv1 = df_pv1.groupby(['place','place2']).head(3).sort_values(['place', 'place2', 'value'], ascending=[True, True, False])
df_ranked_pv2 = df_pv2.groupby(['place','place2']).head(3).sort_values(['place', 'place2', 'value2'], ascending=[True, True, False])

Ponlo todo junto. Mencionaste que el formato no estaba establecido, así que este es un diseño diferente.

df_final = pd.concat([df_ranked_pv1, df_ranked_pv2[['value2', 'listposition2']]], axis=1)

In [125]: df_final
Out[125]:
  place place2  value  listposition  value2  listposition2
0     x      a     50             2      20              1
0     x      a     20             1      10              2
0     x      a     10             0       0              0
1     y      a     30             2      20              2
1     y      a     15             0      10              0
1     y      a      0             1       0              1
2     z      b      5             0      40              2
2     z      b      0             2      10              0
0
Jonathan Leon 2 dic. 2020 a las 22:36