'Python & Pandas: apply scoring function to df new column not working
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
Solution 1:[1]
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
Solution 2:[2]
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)
Solution 3:[3]
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
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | 9769953 |
