My question got rejected the last time so I am trying a better approach to getting a solution:
df.head:
predicted_u4 u_2_5_weight predicted_o2.5_n predicted_score_difference dnb_weight total_score o_1_5_weight predicted_total_score away_score predicted_bttsu2.5_n home_score btts_u_2_5_weight result_match selection_n o_2_5_weight btts_o_2_5_weight predicted_bttso2.5_n win_weight predicted_result predicted_btts_n selection_match_n u_4_5_weight btts_weight predicted_u2.5_n result
0 0.530389 0.4 0.697917 0.881006 0.7 4 3.2 3.540952 3 0.08308 1 0.4 no match O 2.5 (untested) 0.40 0.40 0.536766 1.1 home 0.618518 match 0.4 0.40 0.291228 away
1 0.530389 0.4 0.697917 0.881006 0.7 4 3.2 3.540952 3 0.08308 1 0.4 no match O 2.5 (untested) 0.40 0.40 0.536766 1.1 home 0.618518 match 0.4 0.40 0.291228 away
2 0.743486 0.4 0.477249 0.229046 0.7 2 3.2 2.458867 0 0.13194 2 0.4 match U 2.5 (untested) 0.48 0.40 0.397920 1.1 home 0.531042 match 0.4 0.54 0.529926 home
3 0.743486 0.4 0.477249 0.229046 0.7 2 3.2 2.458867 0 0.13194 2 0.4 match U 2.5 (untested) 0.48 0.40 0.397920 1.1 home 0.531042 match 0.4 0.54 0.529926 home
4 0.752334 0.4 0.532446 0.357271 0.7 1 3.2 2.599825 0 0.06794 1 0.4 match U 2.5 (untested) 0.54 0.44 0.435302 1.1 home 0.516939 match 0.4 0.52 0.480485 home
df.shape[0]:
2437086
I am trying a function to update the rows using:
def selection_n(row):
if (row["win_weight"] == 1.1 or row["btts_o_2_5_weight"] == 0.4) and row["predicted_score_difference"] > row["win_weight"] and row["predicted_bttso2.5_n"] > row["btts_o_2_5_weight"]:
return "W & BTTS O 2.5 (untested)"
elif row["predicted_score_difference"] > row["win_weight"] and row["predicted_bttso2.5_n"] > row["btts_o_2_5_weight"]:
return "W & BTTS O 2.5"
if (row["win_weight"] == 1.1 or row["btts_weight"] == 0.4) and row["predicted_score_difference"] > row["win_weight"] and row["predicted_btts_n"] > row["btts_weight"]:
return "W & BTTS (untested)"
elif row["predicted_score_difference"] > row["win_weight"] and row["predicted_btts_n"] > row["btts_weight"]:
return "W & BTTS"
if (row["win_weight"] == 1.1 or row["o_2_5_weight"] == 0.4) and row["predicted_score_difference"] > row["win_weight"] and row["predicted_o2.5_n"] > row["o_2_5_weight"]:
return "W & O 2.5 (untested)"
elif row["predicted_score_difference"] > row["win_weight"] and row["predicted_o2.5_n"] > row["o_2_5_weight"]:
return "W & O 2.5"
if (row["win_weight"] == 1.1 or row["o_1_5_weight"] == 3.2) and row["predicted_score_difference"] > row["win_weight"] and row["predicted_total_score"] > row["o_1_5_weight"]:
return "W & O 1.5 (untested)"
elif row["predicted_score_difference"] > row["win_weight"] and row["predicted_total_score"] > row["o_1_5_weight"]:
return "W & O 1.5"
if (row["win_weight"] == 1.1 or row["u_2_5_weight"] == 0.4) and row["predicted_score_difference"] > row["win_weight"] and row["predicted_u2.5_n"] > row["u_2_5_weight"]:
return "W & U 2.5 (untested)"
elif row["predicted_score_difference"] > row["win_weight"] and row["predicted_u2.5_n"] > row["u_2_5_weight"]:
return "W & U 2.5"
if (row["win_weight"] == 1.1 or row["u_4_5_weight"] == 0.4) and row["predicted_score_difference"] > row["win_weight"] and row["predicted_u4"] > row["u_4_5_weight"]:
return "W & U 4.5 (untested)"
elif row["predicted_score_difference"] > row["win_weight"] and row["predicted_u4"] > row["u_4_5_weight"]:
return "W & U 4.5"
if row["win_weight"] == 1.1 and row["predicted_score_difference"] > row["win_weight"]:
return "W (untested)"
elif row["predicted_score_difference"] > row["win_weight"]:
return "W"
if row["o_2_5_weight"] == 0.4 and row["predicted_o2.5_n"] > row["o_2_5_weight"]:
return "O 2.5 (untested)"
elif row["predicted_o2.5_n"] > row["o_2_5_weight"]:
return "O 2.5"
if row["btts_o_2_5_weight"] == 0.4 and row["predicted_bttso2.5_n"] > row["btts_o_2_5_weight"]:
return "BTTS O 2.5 (untested)"
elif row["predicted_bttso2.5_n"] > row["btts_o_2_5_weight"]:
return "BTTS O 2.5"
if row["btts_weight"] == 0.4 and row["predicted_btts_n"] > row["btts_weight"]:
return "BTTS (untested)"
elif row["predicted_btts_n"] > row["btts_weight"]:
return "BTTS"
if row["u_2_5_weight"] == 0.4 and row["predicted_u2.5_n"] > row["u_2_5_weight"]:
return "U 2.5 (untested)"
elif row["predicted_u2.5_n"] > row["u_2_5_weight"]:
return "U 2.5"
if row["dnb_weight"] == 0.7 and row["dnb_weight"] < row["predicted_score_difference"] < row["win_weight"]:
return "DNB (untested)"
elif row["dnb_weight"] < row["predicted_score_difference"] < row["win_weight"]:
return "DNB"
if row["u_4_5_weight"] == 0.4 and row["predicted_u4"] > row["u_4_5_weight"]:
return "U 4.5 (untested)"
elif row["predicted_u4"] > row["u_4_5_weight"]:
return "U 4.5"
if (row["o_1_5_weight"] == 0.4 or row["u_4_5_weight"] == 0.4) and row["predicted_total_score"] > row["o_1_5_weight"] and row["predicted_u4"] > row["u_4_5_weight"]:
return "O 1.5 and U 4.5 (untested)"
elif row["predicted_total_score"] > row["o_1_5_weight"] and row["predicted_u4"] > row["u_4_5_weight"]:
return "O 1.5 and U 4.5"
if row["btts_u_2_5_weight"] == 0.4 and row["predicted_bttsu2.5_n"] > row["btts_u_2_5_weight"]:
return "U 2.5 & BTTS (untested)"
elif row["btts_u_2_5_weight"] == 0.4 and row["predicted_bttsu2.5_n"] > row["btts_u_2_5_weight"]:
return "U 2.5 & BTTS"
def selection_match_n(row):
if pd.isna(row["home_score"]) or pd.isna(row["away_score"]):
return "no_result"
if pd.isnull(row["selection_n"]):
return "no sel."
if row["result_match"] == 'match' and row["predicted_result"] != 'draw' and row["home_score"] > 0 and row["away_score"] > 0 and row["total_score"] > 2 and (row["selection_n"] == 'W & BTTS O 2.5' or row["selection_n"] == 'W & BTTS O 2.5 (untested)'):
return "match"
if row["result_match"] == 'match' and row["predicted_result"] != 'draw' and row["home_score"] > 0 and row["away_score"] > 0 and (row["selection_n"] == 'W & BTTS' or row["selection_n"] == 'W & BTTS (untested)'):
return "match"
if row["result_match"] == 'match' and row["predicted_result"] != 'draw' and row["total_score"] > 2 and (row["selection_n"] == 'W & O 2.5' or row["selection_n"] == 'W & O 2.5 (untested)'):
return "match"
if row["result_match"] == 'match' and row["predicted_result"] != 'draw' and row["total_score"] > 1 and (row["selection_n"] == 'W & O 1.5' or row["selection_n"] == 'W & O 1.5 (untested)'):
return "match"
if row["result_match"] == 'match' and row["predicted_result"] != 'draw' and row["total_score"] < 3 and (row["selection_n"] == 'W & U 2.5' or row["selection_n"] == 'W & U 2.5 (untested)'):
return "match"
if row["result_match"] == 'match' and row["predicted_result"] != 'draw' and row["total_score"] < 5 and (row["selection_n"] == "W & U 4.5" or row["selection_n"] == "W & U 4.5 (untested)"):
return "match"
if row["result_match"] == 'match' and row["predicted_result"] != 'draw' and (row["selection_n"] == "W" or row["selection_n"] == "W (untested)"):
return "match"
if row["total_score"] > 2 and (row["selection_n"] == 'O 2.5' or row["selection_n"] == 'O 2.5 (untested)'):
return "match"
if row["home_score"] > 0 and row["away_score"] > 0 and row["total_score"] > 2 and (row["selection_n"] == 'BTTS O 2.5' or row["selection_n"] == 'BTTS O 2.5 (untested)'):
return "match"
if row["home_score"] > 0 and row["away_score"] > 0 and (row["selection_n"] == 'BTTS' or row["selection_n"] == 'BTTS (untested)'):
return "match"
if row["total_score"] < 3 and (row["selection_n"] == 'U 2.5' or row["selection_n"] == 'U 2.5 (untested)'):
return "match"
if (row["result_match"] == 'match' or row["result"] == 'draw' or row["predicted_result"] == 'draw') and (row["selection_n"] == "DNB" or row["selection_n"] == "DNB (untested)"):
return "match"
if row["total_score"] < 5 and (row["selection_n"] == 'U 4.5' or row["selection_n"] == 'U 4.5 (untested)'):
return "match"
if 1 < row["total_score"] < 5 and (row["selection_n"] == 'O 1.5 and U 4.5' or row["selection_n"] == 'O 1.5 and U 4.5 (untested)'):
return "match"
if row["home_score"] > 0 and row["away_score"] > 0 and row["total_score"] < 3 and (row["selection_n"] == 'U 2.5 & BTTS' or row["selection_n"] == 'U 2.5 & BTTS (untested)'):
return "match"
else:
return "no match"
def selection_update_n(row):
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'W & BTTS O 2.5' or row["selection_n"] == 'W & BTTS O 2.5 (untested)'):
if row["result_match"] == 'no match' and row["predicted_result"] != 'draw':
row["win_weight"] += 0.02
elif (row["home_score"] == 0 or row["away_score"] == 0) and row["total_score"] < 3:
row["btts_o_2_5_weight"] += 0.02
elif row["home_score"] == 0 or row["away_score"] == 0:
row["btts_o_2_5_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'W & BTTS' or row["selection_n"] == 'W & BTTS (untested)') and row["result_match"] == 'no match' and row["predicted_result"] != 'draw':
if row["home_score"] > 0 and row["away_score"] > 0:
row["win_weight"] += 0.02
elif (row["home_score"] == 0 or row["away_score"] == 0):
row["win_weight"] += 0.02
row["btts_weight"] += 0.02
elif row["selection_match_n"] == 'no match' and (row["selection_n"] == 'W & BTTS' or row["selection_n"] == 'W & BTTS (untested)') and row["result_match"] == 'match' and row["predicted_result"] != 'draw' and (row["home_score"] == 0 or row["away_score"] == 0):
row["btts_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'W & O 2.5' or row["selection_n"] == 'W & O 2.5 (untested)') and row["result_match"] == 'no match' and row["predicted_result"] != 'draw':
if row["total_score"] > 2:
row["win_weight"] += 0.02
elif row["total_score"] < 3:
row["win_weight"] += 0.02
row["o_2_5_weight"] += 0.02
elif row["selection_match_n"] == 'no match' and (row["selection_n"] == 'W & O 2.5' or row["selection_n"] == 'W & O 2.5 (untested)') and row["result_match"] == 'match' and row["predicted_result"] != 'draw' and row["total_score"] < 3:
row["o_2_5_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'W & O 1.5' or row["selection_n"] == 'W & O 1.5 (untested)') and row["result_match"] == 'no match' and row["predicted_result"] != 'draw':
if row["total_score"] > 1:
row["win_weight"] += 0.02
else:
row["win_weight"] += 0.02
row["o_1_5_weight"] += 0.02
elif row["selection_match_n"] == 'no match' and (row["selection_n"] == 'W & O 1.5' or row["selection_n"] == 'W & O 1.5 (untested)') and row["result_match"] == 'match' and row["predicted_result"] != 'draw' and row["total_score"] < 2:
row["o_1_5_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'W & U 2.5' or row["selection_n"] == 'W & U 2.5 (untested)') and row["result_match"] == 'no match' and row["predicted_result"] != 'draw':
if row["total_score"] < 3:
row["win_weight"] += 0.02
else:
row["win_weight"] += 0.02
row["u_2_5_weight"] += 0.02
elif row["selection_match_n"] == 'no match' and (row["selection_n"] == 'W & U 2.5' or row["selection_n"] == 'W & U 2.5 (untested)') and row["result_match"] == 'match' and row["predicted_result"] != 'draw' and row["total_score"] > 2:
row["u_2_5_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == "W & U 4.5" or row["selection_n"] == "W & U 4.5 (untested)") and row["result_match"] == 'no match' and row["predicted_result"] != 'draw':
if row["total_score"] < 5:
row["win_weight"] += 0.02
else:
row["win_weight"] += 0.02
row["u_4_5_weight"] += 0.02
elif row["selection_match_n"] == 'no match' and (row["selection_n"] == "W & U 4.5" or row["selection_n"] == "W & U 4.5 (untested)") and row["result_match"] == 'match' and row["predicted_result"] != 'draw' and row["total_score"] > 4:
row["u_4_5_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == "W" or row["selection_n"] == "W (untested)") and row["result_match"] == 'no match' and row["predicted_result"] != 'draw':
row["win_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == "W" or row["selection_n"] == "W (untested)") and row["result_match"] == 'no match' and row["predicted_result"] != 'draw':
row["win_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'O 2.5' or row["selection_n"] == 'O 2.5 (untested)') and row["total_score"] < 3:
row["o_2_5_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'BTTS O 2.5' or row["selection_n"] == 'BTTS O 2.5 (untested)') and (row["home_score"] == 0 or row["away_score"] == 0 or row["total_score"] < 3):
row["btts_o_2_5_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'BTTS' or row["selection_n"] == 'BTTS (untested)') and (row["home_score"] == 0 or row["away_score"] == 0):
row["btts_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'U 2.5' or row["selection_n"] == 'U 2.5 (untested)') and row["total_score"] > 2:
row["u_2_5_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == "DNB" or row["selection_n"] == "DNB (untested)") and row["predicted_result"] != 'draw' and (row["result_match"] != 'no match' or row["result"] != 'draw'):
row["dnb_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'U 4.5' or row["selection_n"] == 'U 4.5 (untested)') and row["total_score"] > 4:
row["u_4_5_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'O 1.5 and U 4.5' or row["selection_n"] == 'O 1.5 and U 4.5 (untested)') and (row["total_score"] < 2 or row["total_score"] > 4):
row["o_1_5_weight"] += 0.02
row["u_4_5_weight"] += 0.02
if row["selection_match_n"] == 'no match' and (row["selection_n"] == 'U 2.5 & BTTS' or row["selection_n"] == 'U 2.5 & BTTS (untested)') and (row["home_score"] == 0 or row["away_score"] == 0 or row["total_score"] > 2):
row["btts_u_2_5_weight"] += 0.0
return row
I am trying various approaches to improve the performance. Note, I am unable to use modin as I use Pycharm environment and I get init errors with either ray or dask hence unable to exploit multicore processing.
timeit.timeit(lambda: df.apply(selection_n, axis=1), number=10):
173.67167650000192
timeit.timeit(lambda: df.apply(selection_match_n, axis=1), number=10):
112.6237928000046
timeit.timeit(lambda: df.apply(selection_update_n, axis=1), number=10):
160.64576310000848
If you want to know what I am trying to accomplish here,
There are selections in the selection_n
column that gets updated based on the _weight
columns these weights are checked for matches and all no_matches need to be updated and then checked again. This loop continues until all the "no match" entries get confirmed to "match"
Since this dataframe is a big one, the loop gets very time consuming (last time, the loop took 4 days to complete)
Based on "law of increasing returns" I have tried this approach which tends to work better as the no_match rows reduce every loop so .apply
would work faster:
loop_counter = 0
while (df["selection_match_n"] == "no match").any():
start_time = time.time()
loop_counter += 1
print(f"Iteration: {loop_counter}")
df['selection_n'] = df.swifter.apply(selection_n, axis=1)
# Splitting the DataFrame
no_match_rows = df[df['selection_match_n'] == 'no match']
other_rows = df[df['selection_match_n'] != 'no match']
# Process the no_match_rows DataFrame
no_match_rows['selection_n'] = no_match_rows.swifter.apply(selection_n, axis=1)
no_match_rows = no_match_rows.swifter.apply(selection_update_n, axis=1)
no_match_rows['selection_match_n'] = no_match_rows.swifter.apply(selection_match_n, axis=1)
print('Count of Selection: no_match rows:', (no_match_rows["selection_match_n"] == "no match").sum())
# Concatenate the modified no_match_rows back with other_rows
df = pd.concat([other_rows, no_match_rows])
I have tried swifter
which does not do much.
I am wondering what is the best way to improve performance of these functions. I think vectorisation can be the best use coupled with Cython (if that's possible).