How to recognize changed value when apply transform() pandas

Viewed 56

I have a DF like below

df = pd.DataFrame({'category' : ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C'],
                   'size': [20, 0, 10, 30, 30, 0, 0, 10],
                   'price': [5, 0, 2, 10, 10, 0, 0, 3],
                    'flag' : [0,0,0,0,0,0,0,0]
                  })

I would like to change 0 in ['size'] column into the max value of the category so

df['size'] = np.where(df['size'].eq(0), df.groupby('category')['size'].transform('max'), df['size']) 
df['price'] = np.where(df['price'].eq(0), df.groupby('category')['price'].transform('max'), df['price']) 

And output would be like

df = pd.DataFrame({'category' : ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C'],
                   'size': [20, 20, 10, 30, 30, 30, 10, 10],
                   'price': [5, 5, 2, 10, 10, 10, 3, 3],
                    'flag' : [0,0,0,0,0,0,0,0]
                  })

(process so far confirmed)

But now I would like to know which row has been changed so I assigned a ['flag'] column and would like to change the value 0 to 1 when any other value in the same row has been changed. So desired output would be like below

df = pd.DataFrame({'category' : ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C'],
                   'size': [20, 20, 10, 30, 30, 30, 10, 10],
                   'price': [5, 5, 2, 10, 10, 10, 3, 3],
                    'flag' : [0,1,0,0,0,1,1,0]
                  })

Is there anyway I can do this one line with the transform sentence? Or any other good way?

2 Answers

Can you just label what will be changed before applying your operations? i.e. find the places where size == 0:

df['flag'] = (df['size'] == 0).astype(int)

# then do
df['size'] = np.where(df['size'].eq(0), df.groupby('category')['size'].transform('max'), df['size'])
df['price'] = np.where(df['price'].eq(0), df.groupby('category')['price'].transform('max'), df['price'])

Or for either price or size:

df['flag'] = ((df['size'] == 0) | (df['price'] == 0)).astype(int)

Check here I add the addtional condition due to the whole value price and size in that group maybe 0

cond1 = df.groupby('category')['size'].transform('max')
cond2 = df.groupby('category')['price'].transform('max')

df['changed'] = ((df['size'].ne(cond1)&df['size'].eq(0)) | (df['price'].ne(cond2)&df['price'].eq(0)))  .astype(int)
df['size'] = np.where(df['size'].eq(0), cond1, df['size']) 
df['price'] = np.where(df['price'].eq(0), cond2, df['price']) 

Out[406]: 
  category  size  price  flag  changed
0        A    20      5     0        0
1        A    20      5     0        1
2        A    10      2     0        0
3        B    30     10     0        0
4        B    30     10     0        0
5        B    30     10     0        1
6        C    10      3     0        1
7        C    10      3     0        0

Or if the max value always more than 0

df['changes'] = df[['size','price']].eq(0).any(1).astype(int)
Related