Encontré esta pregunta que es bastante similar a lo que estoy tratando de hacer: python pandas groupby calcular el cambio

El único problema es que mi marco de datos es mucho más complejo, ya que tiene muchas más columnas de valor para las que también quiero calcular las diferencias y algunas columnas de tipo de cadena que necesito mantener, pero obviamente no puedo calcular la diferencia numérica de esos

Group |   Date      | Value | Leader |  Quantity
  A     01-02-2016     16.0      John        1
  A     01-03-2016     15.0      John        1
  B     01-02-2016     16.0     Phillip      1
  B     01-03-2016     13.0     Phillip      1 
  C     01-02-2016     16.0       Bob        1
  C     01-03-2016     16.0       Bob        1 

¿Hay alguna manera de alterar el código para que pueda hacer que la diferencia se aplique a los valores de tipo flotante, en lugar de tener que especificar qué columnas son las de tipo flotante usando loc / iloc? Entonces obtendría algo como esto:

    Date    Group      Change in Value    Leader    Change in Quantity
2016-01-02    A             NaN            John            NaN
2016-01-03    A       -0.062500            John             0
2016-01-02    B             NaN           Phillip          NaN
2016-01-03    B       -0.187500           Phillip           0 
2016-01-02    C             NaN             Bob            NaN
2016-01-03    C        0.000000             Bob             0

Además, ¿sería posible cambiar el pct_change a diff? Así que idealmente obtendría algo como esto:

    Date    Group   Leader    Change in Value    Change in Quantity
2016-01-02    A      John          NaN                    NaN
2016-01-03    A      John         -1.0                    0.0
2016-01-02    B    Phillip         NaN                    NaN
2016-01-03    B    Phillip        -3.0                    0.0
2016-01-02    C      Bob           NaN                    NaN
2016-01-03    C      Bob           0.0                    0.0

Detalles adicionales sobre mi conjunto de datos real:

  • Para cada grupo, hay dos filas (solo se están considerando dos fechas)
  • Idealmente, quiero poder cortar las filas para eliminar todas las que tengan los valores NaN
  • Necesito todos los valores numéricos para mostrar como flotantes para mantener la coherencia.

¡Gracias de antemano!

1
Mathsical Studies 24 jul. 2020 a las 19:23

2 respuestas

La mejor respuesta

Utilice select_dtypes y join

df1 = df.select_dtypes('number')
df_final = df.drop(df1.columns, 1).join(df1.groupby(df['Group'])
                                           .pct_change().add_prefix('Change_in_'))

Out[10]:
  Group        Date   Leader  Change_in_Value  Change_in_Quantity
0     A  01-02-2016     John              NaN                 NaN
1     A  01-03-2016     John          -0.0625                 0.0
2     B  01-02-2016  Phillip              NaN                 NaN
3     B  01-03-2016  Phillip          -0.1875                 0.0
4     C  01-02-2016      Bob              NaN                 NaN
5     C  01-03-2016      Bob           0.0000                 0.0

Usando diff. Simplemente reemplace pct_change por diff

df1 = df.select_dtypes('number')
df_final =  df.drop(df1.columns, 1).join(df1.groupby(df['Group'])
                                            .diff().add_prefix('Change_in_'))
    
Out[15]:
  Group        Date   Leader  Change_in_Value  Change_in_Quantity
0     A  01-02-2016     John             NaN                NaN
1     A  01-03-2016     John            -1.0                0.0
2     B  01-02-2016  Phillip             NaN                NaN
3     B  01-03-2016  Phillip            -3.0                0.0
4     C  01-02-2016      Bob             NaN                NaN
5     C  01-03-2016      Bob             0.0                0.0
2
Andy L. 25 jul. 2020 a las 16:56

Solo puedes hacer:

cols = []
for col in df3.columns:
    if str(col).startswith('Value'):
        cols.append(col)

for i in range(len(cols)-1):
    df["Change " + i] = (df["Value " + i] - df["Value " + i].shift(-1)) / df["Value " + i]
0
Let's try 24 jul. 2020 a las 17:46