I want to create a score based on the value of several columns in the dataframe. I created the following snippet but the function does not apply as it return only 0 values...
def momentum_score (row):
if ((row['rsi_1'] < 30) & (row['rsi_2'] > 30) & (row['rsi_3'] > 30)):
val = 1
if ((row['rsi_1'] < 30) & (row['rsi_2'] < 30) & (row['rsi_3'] > 30)):
val = 2
if ((row['rsi_1'] < 30) & (row['rsi_2'] < 30) & (row['rsi_3'] < 30)):
val = 3
else:
val=0
return val
dfw['mom'] = dfw.apply(momentum_score, axis=1)
dfw
Please see the picture to have a look at my dataframe enter image description here
CodePudding user response:
You can try with apply but it's slower than a vectorized solution. The problem is the use of the if-elif-els statement.
def momentum_score (row):
if ((row['rsi_1'] < 30) & (row['rsi_2'] > 30) & (row['rsi_3'] > 30)):
val = 1
elif ((row['rsi_1'] < 30) & (row['rsi_2'] < 30) & (row['rsi_3'] > 30)):
val = 2
elif ((row['rsi_1'] < 30) & (row['rsi_2'] < 30) & (row['rsi_3'] < 30)):
val = 3
else:
val=0
return val
dfw['mom'] = dfw.apply(momentum_score, axis=1)
dfw
CodePudding user response:
Use np.select
rsi1 = dfw['rsi_1']
rsi2 = dfw['rsi_2']
rsi3 = dfw['rsi_3']
conds =\
[(rsi1 < 30) & (rsi2 > 30) & (rsi3 > 30),
(rsi1 < 30) & (rsi2 < 30) & (rsi3 > 30),
(rsi1 < 30) & (rsi2 < 30) & (rsi3 < 30)]
choices = [1, 2, 3]
#choices = list(range(1, len(conds) 1))
df['mom'] = np.select(conds, choices, default=0)
CodePudding user response:
Try the following instead (untested, but I think this is what you want):
dfw.loc['mom'] = 0 # default value
rsi1 = dfw['rsi_1']
rsi2 = dfw['rsi_2']
rsi3 = dfw['rsi_3']
dfw.loc[(rsi1 < 30) & (rsi2 > 30) & (rsi3 > 30), 'mom'] = 1
dfw.loc[(rsi1 < 30) & (rsi2 < 30) & (rsi3 > 30), 'mom'] = 2
dfw.loc[(rsi1 < 30) & (rsi2 < 30) & (rsi3 < 30), 'mom'] = 3