Tengo un marco de datos como el siguiente. Lo que estoy tratando de hacer es calcular una columna E1 y F1 con una clasificación y un grupo para luego devolver el marco de datos completo. La columna B1 es incremental, pero no necesariamente en 1, pero la ordenación en B1 será

A1  B1    C1     D1  
A    8    0.4    1.3
A    1    0.25   1.25   
B    5    0.5    1.02 
C    2    0.32   1.85  
B    1    0.15   1.22  
B    4    0.66   1.97  
B    3    0.29   1.87  
C    1    0.99   1.22  
C    3    0.78   1.39  
C    4    0.65   1.99  
A    2    0.32   1.02  

Si solo tuviera un valor A1 como

A1  B1    C1     D1  
A    1    0.25   1.25   
A    8    0.4    1.3
A    2    0.32   1.02  

Mi flujo de trabajo es

df.sort_values(by=['B1'])
df = df.reset_index(drop=True)

l = df.index.values
for i in range(len(l)):
    tempZ = df.loc[l[i], 'B1'] - df.loc[l[i-1], 'B1']
    tempJ = (df.loc[l [i], 'C1'] - df.loc[l[i-1], 'C1'])
    tempI = (df.loc[l [i], 'D1'] - df.loc[l[i-1], 'D1'])
    *** DO a whole series of mathematical calculations ***
    X = *** Final mathematical calculations ***
    Y = *** Final mathematical calculations ***
    df.loc[l[i], 'E1'] = tempE
    df.loc[l[i], 'F1'] = tempF

Que luego generaría mi marco de datos como se esperaba

A1  B1    C1     D1      E1    F1
A    1    0.25   1.25   7.33   0.33  
A    2    0.32   1.02   7.89   0.12
A    8    0.4    1.3    8.65   0.22

Pero quiero hacerlo para todo el marco de datos.

A1  B1    C1     D1      E1    F1
A    1    0.25   1.25   7.33   0.33  
A    2    0.32   1.02   7.89   0.12
A    8    0.4    1.3    8.65   0.22
B    1    0.15   1.22   12.32  0.77  
B    3    0.29   1.87   1.11   0.12
B    4    0.66   1.97   7.12   0.99
B    5    0.5    1.02   9.25   0.55
C    1    0.99   1.22   2.35   0.123
C    2    0.32   1.85   6.32   1.03 
C    3    0.78   1.39   6.33   1.00 
C    4    0.65   1.99   12.02  0.33  

Entonces, mi marco de datos debe agruparse por A1 y ordenarse en B1. los cálculos se realizan en las columnas C1 y D1, pero también en las columnas anteriores.

Entonces, supongo que mi pregunta es, ¿cuál sería la forma más eficiente de lograr esto con un marco de datos grande en el que necesitaría hacer algún tipo de grupo y luego generar el marco de datos completo con las nuevas columnas?

Datos

data = [['A',8,0.4,1.3],['A',1,0.25,1.25],['B',5,0.5,1.02],['C',2,0.32,1.85], 
 ['B',1,0.15,1.22],['B',4,0.66,1.97],['B',3,0.29,1.87],['C',1,0.99,1.22], 
 ['C',3,0.78,1.39],['C',4,0.65,1.99],['A',2,0.32,1.02]]

df = pd.DataFrame(data, columns = ['A1', 'B1', 'C1', 'D1'])
0
Messak 22 ene. 2021 a las 19:23

2 respuestas

La mejor respuesta

Estoy usando el siguiente CSV ( guardado como test.csv ):

A1,B1,C1,D1
A,8,0.4,1.3
A,1,0.25,1.25
B,5,0.5,1.02
C,2,0.32,1.85
B,1,0.15,1.22
B,4,0.66,1.97
B,3,0.29,1.87
C,1,0.99,1.22
C,3,0.78,1.39
C,4,0.65,1.99
A,2,0.32,1.02

El siguiente código se agrupará en A1 y se ordenará en B1:

import pandas as pd

df = pd.read_csv('test.csv')

res = pd.DataFrame(columns = df.columns.tolist())
for _, df_chnk in df.groupby('A1', sort=True):
    df_chnk = df_chnk.reset_index(drop=True).sort_values(by=['B1'], ascending=True)
    res = res.append(df_chnk)
res = res.reset_index(drop=True)
print(res)

El código anterior generará el siguiente marco de datos:

   A1 B1    C1    D1
0   A  1  0.25  1.25
1   A  2  0.32  1.02
2   A  8  0.40  1.30
3   B  1  0.15  1.22
4   B  3  0.29  1.87
5   B  4  0.66  1.97
6   B  5  0.50  1.02
7   C  1  0.99  1.22
8   C  2  0.32  1.85
9   C  3  0.78  1.39
10  C  4  0.65  1.99

Para realizar la siguiente operación:

tempZ = df.loc[l[i], 'B1'] - df.loc[l[i-1], 'B1']
tempJ = (df.loc[l [i], 'C1'] - df.loc[l[i-1], 'C1'])
tempI = (df.loc[l [i], 'D1'] - df.loc[l[i-1], 'D1'])

Consulte pandas.DataFrame.diff . ¡Puede usarlo en cada uno de los df_chnk!

1
anurag 22 ene. 2021 a las 16:56

Ordenaría los valores por A y B y luego haría cálculos con groupby y aplicaría, por lo que tiene operaciones vectorizadas, en lugar de bucles, que son muy ineficientes:

data = [['A',8,0.4,1.3],['A',1,0.25,1.25],['B',5,0.5,1.02],['C',2,0.32,1.85], 
 ['B',1,0.15,1.22],['B',4,0.66,1.97],['B',3,0.29,1.87],['C',1,0.99,1.22], 
 ['C',3,0.78,1.39],['C',4,0.65,1.99],['A',2,0.32,1.02]]

df = pd.DataFrame(data, columns = ['A1', 'B1', 'C1', 'D1']).sort_values(['A1', 'B1'])
df['new'] = df.groupby('A1').apply(lambda x: ((x['C1'].diff() *  x['D1'].diff()) / x['B1'].mean())).droplevel(0)
df
   A1  B1    C1    D1       new
1   A   1  0.25  1.25       NaN
10  A   2  0.32  1.02 -0.004391
0   A   8  0.40  1.30  0.006109
4   B   1  0.15  1.22       NaN
6   B   3  0.29  1.87  0.028000
5   B   4  0.66  1.97  0.011385
2   B   5  0.50  1.02  0.046769
7   C   1  0.99  1.22       NaN
3   C   2  0.32  1.85 -0.168840
8   C   3  0.78  1.39 -0.084640
9   C   4  0.65  1.99 -0.031200
0
jjsantoso 22 ene. 2021 a las 17:02
65848957