pandas vectorized
r = x.rev.div(x.cost)
r.abs().add(r < 0).rename('revenue_cost_ratio')
numpy vectorized
by the way, I'd use this one
r = x.rev.values / x.cost.values
pd.Series(np.abs(r) + (r < 0), x.index, name='revenue_cost_ratio')
if you insist on a lambda
f = lambda x: (x.rev * x.cost < 0) + abs(x.rev / x.cost)
x['revenue_cost_ratio'] = x.apply(f)
Let's look at your 3 cases
Case 1
if ((x['cost'] < 0) & (x['rev'] >=0 )):
x['r_c_ratio'] = (x['rev'] + abs(x['cost'])) / abs(x['cost'])
when x['cost'] < 0
, abs(x['cost'])
is just -1 * x['cost']
so this can be simplified to
(x['rev'] - x['cost']) / -x['cost']
or
(x['cost'] - x['rev']) / x['cost']
Case 2
elif((x['cost'] > 0) & (x['rev'] <=0 )):
x['r_c_ratio'] = (x['cost'] + abs(x['rev'])) / x['cost']
when x['rev'] <= 0
, abs(x['rev'])
is just -1 * x['rev']
so this can be simplified to
(x['cost'] - x['rev']) / x['cost']
Wow this is the same as case one! But we can reduce this further to
1 - x['rev'] / x['cost']
And when do we use it? Seems only when either x['rev']
or x['cost']
is negative but not both. Well, that only occurs when that ratio is negative.
Case 3
x['rev'] / x['cost']
Again! What luck! This looks a lot like 1 - x['rev'] / x['cost']
So if we pre-calculate x['rev'] / x['cost']
, test it for negativity and return it or 1 less it, we are good. Hence the functions in the beginning.