Advanced Guide#

Warning

These features have not been tested against real world data to check for their efficacy. You should test the parameters against your own data to ensure they suit your needs.

Additive Dynamics Factor#

If sigma gets too small, eventually the rating change volatility will decrease. To prevent this you can pass the parameter tau to rate. tau should preferably be a small decimal of two significant digits.

Here are some visuals of how ordinals change with different tau values:

_images/tau.png

You can combine tau with another parameter prevent_sigma_increase to ensure the win probability always remains congruent with the actual win rate.

Here is how this looks:

_images/ordinals.png

Time Decay#

You can represent the decay of a player’s skill over time by increasing sigma by a little per match not played (or every time interval). First collect data on by how much sigma goes up or down by resetting sigma to it’s default value per interval. The value by which sigma should change must be an average of the change of sigma over all matches when sigma is reset per interval.

Here is an example of how to do this:

from openskill import Rating, rate, predict_win

x, y = Rating(), Rating()

mu_precision = 1 + 0.0001 / 365
sigma_precision = 1 + 1 / 365

# Let player X win 66% of the games.
for match in range(10000):
    if match % 3:
        [[x], [y]] = rate([[x], [y]])
    else:
        [[y], [x]] = rate([[y], [x]])

    # Decay Rating - Assume 1 Match Per Day
    x.mu /= mu_precision
    y.mu /= mu_precision

    x.sigma *= sigma_precision
    y.sigma *= sigma_precision

print("Before Large Decay: ")
print(f"Player X: mu={x.mu}, sigma={x.sigma}")
print(f"Player Y: mu={y.mu}, sigma={y.sigma}\n")

print("Predict Winner Before Decay:")
x_percent, y_percent = predict_win([[x], [y]])
print(f"X has a {x_percent * 100: 0.2f}% chance of winning over Y\n")

# Decay Rating - Assume 365 Days Passed
for match in range(365):

    # Only player X's rating has decayed.
    if (x.mu < 25 + 3 * 25 / 3) or (x.mu > 25 - 3 * 25 / 3):
        x.mu /= mu_precision

    if x.sigma < 25 / 3:
        x.sigma *= sigma_precision

print("Player X's Rating After Decay: ")
print(f"Player X: mu={x.mu}, sigma={x.sigma}\n")

# One Match b/w X and Y
[[x], [y]] = rate([[x], [y]])
x.mu /= mu_precision
y.mu /= mu_precision
x.sigma *= sigma_precision
y.sigma *= sigma_precision


print("After Large Decay (1 Year): ")
print(f"Player X: mu={x.mu}, sigma={x.sigma}")
print(f"Player Y: mu={y.mu}, sigma={y.sigma}\n")

print("Predict Winner After Decay:")
x_percent, y_percent = predict_win([[x], [y]])
print(f"X has a {x_percent * 100: 0.2f}% chance of winning over Y")

This will produce the following output:

Before Large Decay:
Player X: mu=26.986479759996925, sigma=1.879261533806081
Player Y: mu=22.87672143851661, sigma=1.879261533806081

Predict Winner Before Decay:
X has a  70.27% chance of winning over Y

Player X's Rating After Decay:
Player X: mu=26.983781247317594, sigma=5.101382249884723

After Large Decay (1 Year):
Player X: mu=28.199913286886318, sigma=4.958583411621401
Player Y: mu=22.711677880164803, sigma=1.881565104224607

Predict Winner After Decay:
X has a  58.51% chance of winning over Y