The code below executes fine when the third condition and choice are removed.
I am using the operator
module to pass in a tilde.
The problem is that there are times where I want to NOT take the inverse of these statements, and other times that I do.
In the conditions
section, I am passing None
to avoid using an operator there, but this is obviously incorrect. I also tried using an if
statement to avoid using the inverse operator, i but don't know how to connect if
statements with an &
.
FWIW - I realize I could define all the possible specs
individually, but there are more than a dozen of them, so this approach seemed a lot better to me.
import pandas as pd
import numpy as np
from operator import lt as less_than, invert as invrt
import math
infinity = math.inf
names = [
[5, 'b0524', .02, 'shoes'],
[1, 'b0874', .12, 'toy'],
[10, 'b0321', .11, 'b0321'],
[7, 'b0781', .60, 'car'],
[8, 'b0321', .16, 'plane']
]
df = pd.DataFrame(names, columns=['orders', 'id', 'acos', 'term'])
acos = .15
exclude = ['toy']
def specs(df, min_orders, max_orders, operator, acos, exclude, tilde1, tilde2):
return (
(df['orders'] >= min_orders) &
(df['orders'] <= max_orders) &
(operator(df['acos'], acos)) &
(tilde1(df['term'].str.contains('|'.join(exclude)))) &
(tilde2(df['term'].str.contains(pat = 'b0', case = False)))
)
def strategy(df, acos, exclude):
conditions = ([
specs(df, 3, infinity, less_than, acos, exclude, invrt, invrt),
specs(df, 1, 2, less_than, acos, exclude, invrt, invrt),
specs(df, 1, 2, less_than, acos, exclude, None, None),
])
choices = [
'strat1',
'strat2',
'strat3'
]
df['strategy'] = np.select(conditions, choices, default='NA')
return df
strategy(df, acos, exclude)
print(df)
CodePudding user response:
I think something like this should work. The idea is to use a conditional expression
(aka ternary operator
) to toggle between actually calling tilde2
vs simply returning a like-sized result filled with True
(there may be a more elegant way to do this, but I have gotten the array of True
by comparing df['term']
to itself for equality, which will always be True
).
def specs(df, min_orders, max_orders, operator, acos, exclude, tilde1, tilde2):
return (
(df['orders'] >= min_orders) &
(df['orders'] <= max_orders) &
(operator(df['acos'], acos)) &
(tilde1(df['term'].str.contains('|'.join(exclude)))) &
(df['term'] == df['term'] if tilde2 is None else tilde2(df['term'].str.contains(pat = 'b0', case = False)))
)