sublee / trueskill

An implementation of the TrueSkill rating system for Python
https://trueskill.org/
Other
742 stars 112 forks source link

ZeroDivisionError #5

Closed warner121 closed 11 years ago

warner121 commented 11 years ago

Hi sublee,

I have encountered a problem with the calculation of some ratings (admittedly with some rather unusual parameter settings):

transform_ratings([Rating(mu=-323.263, sigma=2.965), Rating(mu=-48.441, sigma=2.190)], ranks = [0, 1]) Traceback (most recent call last): File "", line 1, in File "/usr/lib/python2.7/site-packages/trueskill/init.py", line 602, in transform_ratings return _g().transform_ratings(rating_groups, ranks, min_delta) File "/usr/lib/python2.7/site-packages/trueskill/init.py", line 531, in transform_ratings return self.rate(rating_groups, ranks, min_delta=min_delta) File "/usr/lib/python2.7/site-packages/trueskill/init.py", line 389, in rate self.run_schedule(_args) File "/usr/lib/python2.7/site-packages/trueskill/init.py", line 309, in run_schedule delta = trunc_layer[0].up() File "/usr/lib/python2.7/site-packages/trueskill/factorgraph.py", line 193, in up v = self.v_func(_args) File "/usr/lib/python2.7/site-packages/trueskill/init.py", line 45, in v_win return pdf(x) / cdf(x) ZeroDivisionError: float division by zero

sublee commented 11 years ago

Hi,

I realized the error but I couldn't find a solution to fix it. In this case, both cdf and pdf in the v_win function returns 0.0 because the real value is too low. Python can't guarantee an enough precision.

However, another implementations make different result. See the below:

Probably the expectation is Microsoft's. Both results have similar sigma but the C# implementation couldn't calculate correct mu. I'll try to refer to another implementations but Microsoft didn't open the source code. I can patch to calculate only correct sigma but mu.

ps. Your ratings are unexpectedly too low. Are they really valid?

sublee commented 11 years ago

@warner121

https://github.com/sublee/trueskill/blob/master/trueskilltests.py#L426

I just committed 1d3208a6db245d6ca9737a2ce1ecf5f0c16d1b7e to fix a half of the problem. Now my implementation returns N(NaN, 2.683) and N(NaN, 2.080) instead of ZeroDivisionError raising just like the C# implementation. But we know, it's not an eventual expectation.

warner121 commented 11 years ago

Great - thanks for looking into this issue. I came across the error while evaluating the performance of different parameters in my project, and was aware these values were pretty extreme. I think the fix you have implemented is neater than the zero division. Thanks!

sublee commented 11 years ago

I changed my mind. ZeroDivisionError is better than NaN. If the rate() function transforms a rating to NaN silently, your program will save it to the database without a doubt. Then you can't recover meaningful rating.

I reopened this issue. I'm still finding a solution.

sublee commented 11 years ago

I added backend option to TrueSkill class to choose cdf, pdf, ppf implementation. There are 3 backends; None (internal implementation), 'scipy', 'mpmath'. If you choose 'mpmath' backend, this problem will be disappeared. Of course you have to install mpmath first.

>>> from trueskill import *
>>> rate_1vs1(Rating(mu=-323.263, sigma=2.965), Rating(mu=-48.441, sigma=2.190))Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
  File "trueskill/__init__.py", line 622, in rate_1vs1  
    return _g().rate_1vs1(rating1, rating2, drawn, min_delta)  
  File "trueskill/__init__.py", line 504, in rate_1vs1  
    teams = self.rate([(rating1,), (rating2,)], ranks, min_delta=min_delta)  
  File "trueskill/__init__.py", line 416, in rate  
    self.run_schedule(*args)  
  File "trueskill/__init__.py", line 332, in run_schedule  
    delta = trunc_layer[0].up()  
  File "trueskill/factorgraph.py", line 196, in up  
    w = self.w_func(*args)  
  File "trueskill/__init__.py", line 164, in w_win  
    raise FloatingPointError('Cannot calculate correctly, '  
FloatingPointError: Cannot calculate correctly, set backend to 'mpmath'
>>> setup(backend='mpmath')
<TrueSkill mu=25.000 sigma=8.333 beta=4.167 tau=0.083 draw_probability=10.0% backend='mpmath'>
>>> rate_1vs1(Rating(mu=-323.263, sigma=2.965), Rating(mu=-48.441, sigma=2.190))
(Rating(mu=-273.060, sigma=2.683), Rating(mu=-75.848, sigma=2.080))