Home > Net >  Calculating multiple columns using Panda's mask() and diff() with multiple conditions
Calculating multiple columns using Panda's mask() and diff() with multiple conditions

Time:05-03

I have a dataframe df df:

Date Type AVG1 AVG2 AVG3 AVG4 AVG5
2022-05 ROL1 0.33 0.45 0.12 0.96 1.33
2022-05 ROL2 1.43 0.11 0.75 1.99 3.01
2022-05 ROL3 0.11 0.32 0.55 1.26 4.22
2022-04 ROL1 1.66 0.71 0.87 5.88 1.11
2022-04 ROL2 2.31 0.89 2.20 4.36 4.87
2022-04 ROL3 5.40 1.22 4.45 0.01 0.31

And I need to create the columns AVG1_ROL1_MoM, AVG1_ROL2_MoM, AVG3_ROL1_MoM, AVG1_ROL2_MoM and so on. Where AVG1_ROL1_MoM is the difference in AVG1 where TYPE = ROL1 from one month to the other:

Date Type AVG1 AVG2 AVG3 AVG4 AVG5 AVG1_ROL1_MoM AVG1_ROL2_MoM
2022-05 ROL1 0.33 0.45 0.12 0.96 1.33 -1.33 NaN
2022-05 ROL2 1.43 0.11 0.75 1.99 3.01 NaN -0.88
2022-05 ROL3 0.11 0.32 0.55 1.26 4.22 NaN NaN
2022-04 ROL1 1.66 0.71 0.87 5.88 1.11 NaN NaN
2022-04 ROL2 2.31 0.89 2.20 4.36 4.87 NaN NaN
2022-04 ROL3 5.40 1.22 4.45 0.01 0.31 NaN NaN

I tried to do that with mask() and shift(), but it didn't work:

df['AVG1_ROL1_MoM'] = df.mask(df['Type']=="ROL1", df['AVG1'] - df['AVG1'].shift(), inplace=True)

This returns that an axis must be defined, but when I define and axis it returns that: "Cannot do inplace boolean setting on mixed-types with a non np.nan value"

What would be the best approach for this?

CodePudding user response:

  1. melt the dataframe to get all the values in a single column
  2. Create the new column names
  3. groupby to find the monthly differences
  4. pivot to get back the original structure
  5. merge with the original dataframe
melted = df.melt(["Date","Type"])
melted["column"] = melted["variable"] "_" melted["Type"] "_MoM"
melted["diff"] = melted.groupby(["Type","variable"])["value"].diff(-1)

pivoted = melted.pivot(["Date","Type"],"column","diff").sort_index(ascending=[False,True]).reset_index()

output = df.merge(pivoted, on=["Date","Type"])

>>> output
      Date  Type  AVG1  ...  AVG5_ROL1_MoM  AVG5_ROL2_MoM  AVG5_ROL3_MoM
0  2022-05  ROL1  0.33  ...           0.22            NaN            NaN
1  2022-05  ROL2  1.43  ...            NaN          -1.86            NaN
2  2022-05  ROL3  0.11  ...            NaN            NaN           3.91
3  2022-04  ROL1  1.66  ...            NaN            NaN            NaN
4  2022-04  ROL2  2.31  ...            NaN            NaN            NaN
5  2022-04  ROL3  5.40  ...            NaN            NaN            NaN

[6 rows x 22 columns]

CodePudding user response:

IUUC, you can try group by Type column and then compare the subgroup AVG shifted value and rename the outcome columns:

out = (df.filter(like='AVG')
       .groupby(df['Type'])
       .apply(lambda g: (g-g.shift(-1)).rename(columns=lambda col: f'{col}_{g.name}_MOM'))
)
print(out)

   AVG1_ROL1_MOM  AVG2_ROL1_MOM  AVG3_ROL1_MOM  AVG4_ROL1_MOM  AVG5_ROL1_MOM  \
0          -1.33          -0.26          -0.75          -4.92           0.22
1            NaN            NaN            NaN            NaN            NaN
2            NaN            NaN            NaN            NaN            NaN
3            NaN            NaN            NaN            NaN            NaN
4            NaN            NaN            NaN            NaN            NaN
5            NaN            NaN            NaN            NaN            NaN

   AVG1_ROL2_MOM  AVG2_ROL2_MOM  AVG3_ROL2_MOM  AVG4_ROL2_MOM  AVG5_ROL2_MOM  \
0            NaN            NaN            NaN            NaN            NaN
1          -0.88          -0.78          -1.45          -2.37          -1.86
2            NaN            NaN            NaN            NaN            NaN
3            NaN            NaN            NaN            NaN            NaN
4            NaN            NaN            NaN            NaN            NaN
5            NaN            NaN            NaN            NaN            NaN

   AVG1_ROL3_MOM  AVG2_ROL3_MOM  AVG3_ROL3_MOM  AVG4_ROL3_MOM  AVG5_ROL3_MOM
0            NaN            NaN            NaN            NaN            NaN
1            NaN            NaN            NaN            NaN            NaN
2          -5.29           -0.9           -3.9           1.25           3.91
3            NaN            NaN            NaN            NaN            NaN
4            NaN            NaN            NaN            NaN            NaN
5            NaN            NaN            NaN            NaN            NaN
out = pd.concat([df, out], axis=1)
print(out)

      Date  Type  AVG1  AVG2  AVG3  AVG4  AVG5  AVG1_ROL1_MOM  AVG2_ROL1_MOM  \
0  2022-05  ROL1  0.33  0.45  0.12  0.96  1.33          -1.33          -0.26
1  2022-05  ROL2  1.43  0.11  0.75  1.99  3.01            NaN            NaN
2  2022-05  ROL3  0.11  0.32  0.55  1.26  4.22            NaN            NaN
3  2022-04  ROL1  1.66  0.71  0.87  5.88  1.11            NaN            NaN
4  2022-04  ROL2  2.31  0.89  2.20  4.36  4.87            NaN            NaN
5  2022-04  ROL3  5.40  1.22  4.45  0.01  0.31            NaN            NaN

   AVG3_ROL1_MOM  AVG4_ROL1_MOM  AVG5_ROL1_MOM  AVG1_ROL2_MOM  AVG2_ROL2_MOM  \
0          -0.75          -4.92           0.22            NaN            NaN
1            NaN            NaN            NaN          -0.88          -0.78
2            NaN            NaN            NaN            NaN            NaN
3            NaN            NaN            NaN            NaN            NaN
4            NaN            NaN            NaN            NaN            NaN
5            NaN            NaN            NaN            NaN            NaN

   AVG3_ROL2_MOM  AVG4_ROL2_MOM  AVG5_ROL2_MOM  AVG1_ROL3_MOM  AVG2_ROL3_MOM  \
0            NaN            NaN            NaN            NaN            NaN
1          -1.45          -2.37          -1.86            NaN            NaN
2            NaN            NaN            NaN          -5.29           -0.9
3            NaN            NaN            NaN            NaN            NaN
4            NaN            NaN            NaN            NaN            NaN
5            NaN            NaN            NaN            NaN            NaN

   AVG3_ROL3_MOM  AVG4_ROL3_MOM  AVG5_ROL3_MOM
0            NaN            NaN            NaN
1            NaN            NaN            NaN
2           -3.9           1.25           3.91
3            NaN            NaN            NaN
4            NaN            NaN            NaN
5            NaN            NaN            NaN
  • Related