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.
lambdafunction, but&is the bitwise-and operator in Python. You want theandoperator when you're doing a logical-and (which appears to be what you want here). The two operators do work the same for the Boolean valuesTrueandFalse, but won't always do the same thing if you have other "truthy" values involved in the operaton (e.g. compare1 & 2with1 and 2).