I am writing my Bachelor thesis in Python about predicting results of tennis matches based on historical data. I have started from Logistic Regression but my model isn't efficient. If you could look at it and tell me, what should I change. I am just getting started and I am not really sure if I understand these methods. I am using data from this repository https://github.com/JeffSackmann/tennis_atp, but i changed it a bit for my needs https://drive.google.com/file/d/1w8weQxhsMBvYwrDPVTuiM3diFxtsXaky/view?usp=sharing. Performance of this model isn't really good and I would like to improve it.

I will deal with missing data, by changing it to mean, median or mode and check which one is best.

import numpy as np
import pandas as pd
import random
from sklearn import preprocessing
from sklearn.linear_model import LogisticRegression

def df_mean(frame):
   index = np.where(frame.columns.values == 'minutes')[0][0]
   columns = frame.columns[index::]
   for i in columns:
      frame[i].replace(np.NaN, frame[i].mean(), inplace=True)
   return frame

def df_median(frame):
   index = np.where(frame.columns.values == 'minutes')[0][0]
   columns = frame.columns[index::]
   for i in columns:
      frame[i].replace(np.NaN, frame[i].median(), inplace=True)
   return frame

def df_mode(frame):
   index = np.where(frame.columns.values == 'minutes')[0][0]
   columns = frame.columns[index::]
   for i in columns:
      frame[i].replace(np.NaN, frame[i].mode(), inplace=True)
   return frame

For the first time i chose mean

df = df_mean(pd.read_excel('matches 00-19.xlsx')).dropna() df.index = range(61475)
frame = df[['winner_name', 'loser_name', 'winner_name']]
frame.columns = ["Player1", "Player2", "Winner"]
X = frame[["Player1", "Player2"]]
y = frame[['Winner']] 

In the data I had, in the dataframe the winner was always on the left and the loser on the right so I had to mix it.

for i in range(X.shape[0]):
   rand = random.getrandbits(1)
   if rand == True:
      X.iloc[i][0], X.iloc[i][1] = X.iloc[i][1], X.iloc[i][0]

y1 = pd.DataFrame(data=np.zeros(shape= (len(y),1)), columns= ['Winner'], dtype= np.int64)
for i in y.index:
   if y['Winner'][i] == X['Player2'][i]:
      y1['Winner'][i] = 1

y = y1

I had to change names of the players to numbers so I made a set of all the players and than made a dictionary of it. I know I could use 'winner_id' but those numbers are too big.

s1 = set(frame['Player1'])
s2 = set(frame['Player2'])
set_merged = sorted(s1.union(s2))

d1 = {}
for i in range(len(set_merged)):
   d1[set_merged[i]] = i

keys = list(d1.keys()) X2 = pd.DataFrame(data=np.zeros(shape= (len(X),2)),
columns= ['Player1','Player2'], dtype= np.int64)
for i in X['Player1'].index:
   if X['Player1'][i] in keys:
      X2['Player1'][i] = d1[X['Player1'][i]]

for i in X['Player2'].index:
   if X['Player2'][i] in keys:
      X2['Player2'][i] = d1[X['Player2'][i]]
X = X2

X_train = X[:49180]
y_train = np.ravel(y[:49180])

X_test = X[49180:]
y_test = np.ravel(y[49180:])

model = LogisticRegression()
model.fit(X_train, y_train)

I think your current under-performance is a data problem. The dataset in your google sheet seems like it contains far too few features that you could conceivably use to predict whether someone would win a tennis match.

You should consider some creative feature-engineering options. Stuff like (but not limited to):

  • how many wins or loses in a row has this tennis player had
  • what is the weather during the game
  • how many years of professional tennis have they played
  • how many tournaments have they won (somehow encode their previous accolades)

Additionally - you might want to re-structure your data. The schema of having one player on the left and the other on the right of the same row will always make the machine learn that there's a distinction between right and left, when in fact this is just a bias you are introducing via featurizing.

You could consider a system whereby you double-up your data and put each match where player 1 is on the left and then the right. This could conceivably force your estimator to consider the match from both sides.

As for the estimator consider looking into some ensemble methods like gradient boosting classifier, or random forest classifier instead of logistic regression.


Not the answer you're looking for? Browse other questions tagged or ask your own question.