<jupyter_start><jupyter_text><jupyter_code># https://en.wikipedia.org/wiki/Elo_rating_system
# Lichess uses the glicko2 rating system which is more accurate and way more complex than Elo.
# Therefore, there will be a difference between the ratings on lichess and the ratings I calculate here
# I'll be using the linear performance rating system which is simple compared to the original Elo rating system.
# rating = avrg opponent rating + 800*fractional score - 400
def rating(avrgopprating,fscore):
    return avrgopprating + 800*fscore - 400

x = ['Overall','<2700','2700s','2800s','2900s','3000s','3100<'] 
y = [rating(np.mean(mg.opp_elo),fscore(vco(mg))),
    rating(np.mean(mg[mg.opp_elo<2700].opp_elo),fscore(vc(mg,mg.opp_elo<2700))),
    rating(np.mean(mg[(mg.opp_elo<2800) &(mg.opp_elo>=2700)].opp_elo),fscore(vc(mg,(mg.opp_elo<2800) &(mg.opp_elo>=2700)))),
    rating(np.mean(mg[(mg.opp_elo<2900) &(mg.opp_elo>=2800)].opp_elo),fscore(vc(mg,(mg.opp_elo<2900) &(mg.opp_elo>=2800)))),
    rating(np.mean(mg[(mg.opp_elo<3000) &(mg.opp_elo>=2900)].opp_elo),fscore(vc(mg,(mg.opp_elo<3000) &(mg.opp_elo>=2900)))),
    rating(np.mean(mg[(mg.opp_elo<3100) &(mg.opp_elo>=3000)].opp_elo),fscore(vc(mg,(mg.opp_elo<3100) &(mg.opp_elo>=3000)))),
    rating(np.mean(mg[mg.opp_elo>3100].opp_elo),fscore(vc(mg,mg.opp_elo>3100)))]
ratings = y
bars = plt.bar(x,y)
bars[0].set_facecolor('purple')
plt.title('Linear Performance Rating by Opponent Rating')
plt.xlabel('Opponent Rating')
plt.ylabel('Linear Performance')
for index, value in enumerate(y):
    plt.text(index, value,
             str(round(value)),ha='center')
plt.show()

x = ['Overall','<2700','2700s','2800s','2900s','3000s','3100<'] 
y = [np.mean(mg.opp_elo), np.mean(mg[mg.opp_elo<2700].opp_elo),
    np.mean(mg[(mg.opp_elo<2800) &(mg.opp_elo>=2700)].opp_elo),
    np.mean(mg[(mg.opp_elo<2900) &(mg.opp_elo>=2800)].opp_elo),
    np.mean(mg[(mg.opp_elo<3000) &(mg.opp_elo>=2900)].opp_elo),
    np.mean(mg[(mg.opp_elo<3100) &(mg.opp_elo>=3000)].opp_elo),
    np.mean(mg[mg.opp_elo>3100].opp_elo)]
means = y
bars = plt.bar(x,y)
bars[0].set_facecolor('purple')
plt.title('Average Opponent Rating by Opponent Rating Range')
plt.xlabel('Opponent Rating Range')
plt.ylabel('Average Opponent Rating')
for index, value in enumerate(y):
    plt.text(index, value,
             str(round(value)),ha='center')
plt.show()

# After looking at the two above graphs, I realized that this 'linear performance rating' 
# is not that useful as a metric over avrg opp rating for magnus since he wins so often.
# not that useful because magnus is literally the greatest player ever and does not lose that often
# That means the lp rating will be very correlated to avrg opponent rating
# It only stops being correlated when one plays vs higher rated players but he is among the highest rated
# This metric is a lot more useful for players that have fscores that vary a lot above and below .5 
# Magnus's fscore goes from .83 against ~2363 rated players to .64 against ~3151 rated players
ratingsVmeans = pd.DataFrame([ratings,means]).T
ratingsVmeans.columns = ['lp_rating','opp_rating']
ratingsVmeans
ratingsVmeans.plot.scatter(x='lp_rating',y='opp_rating')
plt.title('Linear Performance Rating vs Average Opponent Rating')
plt.show()
# LP Rating and Opponent rating are super correlated so there's no reason to use LP rating as its own metric
# .997 correlation wow
# win rate varies and opponent rating varies, should be negatively correlated, and lp rating could be used a metric to stay constant and isolate variables
# except it doesnt for magnus s
ratingsVmeans.corr(method='pearson')
fscores = [fscore(vco(cg)),fscore(vc(mg,mg.opp_elo<2700)),fscore(vc(mg,(mg.opp_elo<2800) &(mg.opp_elo>=2700))),fscore(vc(mg,(mg.opp_elo<2900) &(mg.opp_elo>=2800))),fscore(vc(mg,(mg.opp_elo<3000) &(mg.opp_elo>=2900))),fscore(vc(mg,(mg.opp_elo<3100) &(mg.opp_elo>=3000))),fscore(vc(mg,mg.opp_elo>=3100))]
meansVscores = pd.DataFrame([means,fscores]).T
meansVscores.columns = ['opp_rating','fscore']
meansVscores
meansVscores.plot.scatter(x=0,y=1)
# 0.95 correlation, confirms that fractional score and opponent rating are very negatively correlated
meansVscores.corr(method='pearson')

x = ['Overall','White','Black']
y = [rating(np.mean(mg.opp_elo),fscore(vco(mg))),
    rating(np.mean(mg[mg.magnus_color=='white'].opp_elo),fscore(vc(mg,mg.magnus_color=='white'))),
    rating(np.mean(mg[mg.magnus_color=='black'].opp_elo),fscore(vc(mg,mg.magnus_color=='black')))]
    
bars = plt.bar(x,y)
bars[0].set_facecolor('purple')
plt.title('Linear Performance Rating by Color')
plt.xlabel('Color')
plt.ylabel('Linear Performance')
for index, value in enumerate(y):
    plt.text(index, value,
             str(round(value)),ha='center')
plt.show()
# not influenced by opponent rating, Magnus simply plays better as white than black
print('Overall: ',np.mean(mg.opp_elo))
print(np.mean(mg[mg.magnus_color=='white'].opp_elo))
print(np.mean(mg[mg.magnus_color=='black'].opp_elo))
# avrg opponent rating had more influence than win rate here 
x = ['Overall','2018','2019','2020','2021']
y = [rating(np.mean(mg.opp_elo),fscore(vco(mg))),
    rating(np.mean(mg[mg.datetime.str[0:4]=='2018'].opp_elo),fscore(vc(mg,mg.datetime.str[0:4]=='2018'))),
    rating(np.mean(mg[mg.datetime.str[0:4]=='2019'].opp_elo),fscore(vc(mg,mg.datetime.str[0:4]=='2019'))),
    rating(np.mean(mg[mg.datetime.str[0:4]=='2020'].opp_elo),fscore(vc(mg,mg.datetime.str[0:4]=='2020'))),
    rating(np.mean(mg[mg.datetime.str[0:4]=='2021'].opp_elo),fscore(vc(mg,mg.datetime.str[0:4]=='2021')))]
bars = plt.bar(x,y)
bars[0].set_facecolor('purple')
plt.title('Linear Performance Rating by Year')
plt.xlabel('Year')
plt.ylabel('Performance')
for index, value in enumerate(y):
    plt.text(index, value,
             str(round(value)),ha='center')
plt.show()
print(np.mean(mg[mg.datetime.str[0:4]=='2018'].opp_elo))
print(np.mean(mg[mg.datetime.str[0:4]=='2019'].opp_elo))
print(np.mean(mg[mg.datetime.str[0:4]=='2020'].opp_elo))
print(np.mean(mg[mg.datetime.str[0:4]=='2021'].opp_elo))
x = ['Overall','1+0','Not 1+0']
y = [rating(np.mean(mg.opp_elo),fscore(vco(mg))),
    rating(np.mean(mg[mg.time_control=='1+0'].opp_elo),fscore(vc(mg,mg.time_control=='1+0'))),
    rating(np.mean(mg[mg.time_control!='1+0'].opp_elo),fscore(vc(mg,mg.time_control!='1+0')))]
bars = plt.bar(x,y)
bars[0].set_facecolor('purple')
plt.title('Linear Performance Rating by Time Control')
plt.xlabel('Time Control')
plt.ylabel('Linear Performance')
for index, value in enumerate(y):
    plt.text(index, value,
             str(round(value)),ha='center')
plt.show()
print(np.mean(mg[mg.time_control=='1+0'].opp_elo))
print(np.mean(mg[mg.time_control!='1+0'].opp_elo))<jupyter_output>2910.2312123592565
2619.870492635856
{'fraction_non_alphanumeric': 0.18470397165214825, 'fraction_numerical': 0.056695703528716966, 'mean_word_length': 6.435784851811197, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 24, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '480809', 'license': 'MIT', 'n_tokens_mistral': 2819, 'n_tokens_neox': 2506, 'n_words': 476, 'path': 'Elo Analysis.ipynb', 'repo_name': 'dealom/Magnus-Carlsen-Lichess-Games-Dataset-Analysis', 'size': '6773'}