from typing import Union
import pandas as pd
[docs]def expected_score(rating_a: int, rating_b: int) -> float:
"""Calculates the expected score of player_a against player_b.
Args:
rating_a: Rating of player_a
rating_b: Rating of player_b
Returns:
expected score of player_a
Example::
>>> import pgnhelper.elo
>>> white_elo = 2600
>>> black_elo = 2500
>>> score = pgnhelper.elo.expected_score(white_elo, black_elo)
>>> score
0.6400649998028851
"""
rd = rating_b - rating_a
return 1 / (1 + 10 ** (rd / 400))
[docs]def add_rating_change(df: pd.DataFrame, is_rating: bool, k: int = 10) -> pd.DataFrame:
"""Adds rating change columns to existing df.
Args:
df: A dataframe of players match records.
is_rating: True if players have rating.
k: The k factor.
Returns:
A dataframe of game records with elo rating change columns.
[Round, White, Black, WElo, BElo, Result, Wpt, Bpt, Arm, WRChg, BRChg]
"""
if not is_rating:
df['WRChg'] = 0
df['BRChg'] = 0
else:
df['WRChg'] = k * (df.Wpt - expected_score(df.WElo, df.BElo))
df['BRChg'] = k * (df.Bpt - expected_score(df.BElo, df.WElo))
return df
[docs]def get_rating(df: pd.DataFrame, p: str) -> Union[int, str]:
"""Gets the rating of player p.
Args:
df: A dataframe of players match records.
p: A player name.
Returns:
rating of player p
"""
dfr = df.loc[df.White == p]
if len(dfr):
return dfr.iloc[0]['WElo']
dfr = df.loc[df.Black == p]
if len(dfr):
return dfr.iloc[0]['BElo']
return '?'
[docs]def get_rating_change(df: pd.DataFrame, p: str, k: int = 10) -> float:
"""Gets the rating change of player p.
The given df has a rating change column for each side. This rating
change column was calculated using a k factor with value 10. The
k parameter if not 10 will be used to recalculate the rating change
for the given player.
Armageddon games are not included in the returned rating change value.
Args:
df: A dataframe of players match records.
p: A player named p.
k: The rating change k factor.
Returns:
rating change
Eample 1, get the rating change of a player in the PGN file::
>>> import pgnhelper.record
>>> import pgnhelper.elo
>>> df, players, is_rating = pgnhelper.record.get_pgn_data("./pgn/superbet_classic_2022_bucharest.pgn")
>>> players
['Firouzja, Alireza', 'Aronian, Levon', 'So, Wesley', 'Nepomniachtchi, Ian', 'Caruana, Fabiano', 'Vachier-Lagrave, Maxime', 'Deac, Bogdan-Daniel', 'Mamedyarov, Shakhriyar', 'Dominguez Perez, Leinier', 'Rapport, Richard']
>>> rc_levon = pgnhelper.elo.get_rating_change(df, "Aronian, Levon", k=10)
>>> rc_levon
9.496967974633389
Eample 2, get the rating change of black player::
>>> import pgnhelper.elo
>>> white_rating = 2700
>>> black_rating = 2600
>>> black_point = 1
>>> white_point = 0
>>> expected_score = pgnhelper.elo.expected_score(black_rating, white_rating)
>>> k = 10
>>> rating_change = k * (black_point - expected_score)
>>> rating_change
6.400649998028851
"""
dfw = df.loc[(df.White == p) & (df.Arm == 0)]
dfb = df.loc[(df.Black == p) & (df.Arm == 0)]
s = dfw.WRChg.sum() + dfb.BRChg.sum()
if k != 10:
s = s / 10
return k * s
return s