Home > OS >  Mask column based on condition in another column
Mask column based on condition in another column

Time:05-10

class subclass date value
1 A 02-10-22 .5
1 A 02-21-22 .6
1 A 02-28-22 .8
1 B 02-09-22 .3
1 B 02-14-22 .4
1 B 02-28-22 .5
2 C 02-15-22 .9
2 C 02-28-22 .8

I have a dataframe like above. Several (class, subclass) pairs have values ordered by dates. The bottom date for each (class, subclass) is guaranteed to be the maximum date, for example 02-28-22.

I would like to transform to the dataset below. For the date right before the maximum date, if it is not exactly 7 days before the maximum date - we change the corresponding value to NaN. Otherwise we leave it alone, as well the other dates. FE, the row with date 02-21-22 is left alone; while the row with 02-14-22 is now NaN.

Dates are stored as strings: '02-15-22'.

class subclass date value
1 A 02-10-22 .5
1 A 02-21-22 .6
1 A 02-28-22 .8
1 B 02-09-22 .3
1 B 02-14-22 NaN
1 B 02-28-22 .5
2 C 02-15-22 NaN
2 C 02-28-22 .8

CodePudding user response:

Find the max date and the second max date using groupby. Then use where to mask the relevant values:

maxdate = df.groupby(["class", "subclass"])["date"].transform('max')
nextmaxdate = df.groupby(["class","subclass"])["date"].transform(lambda x: x.nlargest(2).min())

df["value"] = df["value"].where(df["date"].ne(nextmaxdate) | maxdate.sub(nextmaxdate).dt.days.eq(7))

>>> df
   class subclass       date  value
0      1        A 2022-02-10    0.5
1      1        A 2022-02-21    0.6
2      1        A 2022-02-28    0.8
3      1        B 2022-02-09    0.3
4      1        B 2022-02-14    NaN
5      1        B 2022-02-28    0.5
6      2        C 2022-02-15    NaN
7      2        C 2022-02-28    0.8

CodePudding user response:

Calculate reverse cumcount to identify the row preceding the last row, then group and shift the date column and subtract a offset of 7 days, then mask the values in value column preceding to last row where the required condition is not met

c = df[::-1].groupby(['class', 'subclass']).cumcount()
d = df.groupby(['class', 'subclass'])['date'].shift(-1) - pd.DateOffset(days=7)
df['value'] = df['value'].mask(df['date'].ne(d) & c.eq(1))

   class subclass       date  value
0      1        A 2022-02-10    0.5
1      1        A 2022-02-21    0.6
2      1        A 2022-02-28    0.8
3      1        B 2022-02-09    0.3
4      1        B 2022-02-14    NaN
5      1        B 2022-02-28    0.5
6      2        C 2022-02-15    NaN
7      2        C 2022-02-28    0.8
  • Related