Git Product home page Git Product logo

go-openskill's Introduction

GO-OPENSKILL

CircleCI

Go implementation of Weng-Lin Rating, as described at https://www.csie.ntu.edu.tw/~cjlin/papers/online_ranking/online_journal.pdf

Speed

Note: The following paragraph is copied verbatim from the javascript implementation and is not yet verified for this implementation.

Up to 20x faster than TrueSkill!

Model Speed (higher is better) Variance Samples
Openskill/bradleyTerryFull 62,643 ops/sec ±1.09% 91 runs sampled
Openskill/bradleyTerryPart 40,152 ops/sec ±0.73% 91 runs sampled
Openskill/thurstoneMostellerFull 59,336 ops/sec ±0.74% 93 runs sampled
Openskill/thurstoneMostellerPart 38,666 ops/sec ±1.21% 92 runs sampled
Openskill/plackettLuce 23,492 ops/sec ±0.26% 91 runs sampled
TrueSkill 2,962 ops/sec ±3.23% 82 runs sampled

See this post for more.

Installation

go get github.com/intinig/go-openskill

Usage

Ratings are kept as an object which represent a gaussian curve, with properties where mu represents the mean, and sigma represents the spread or standard deviation. Create these with:

package main

import (
	"github.com/intinig/go-openskill/rating"
	"github.com/intinig/go-openskill/types"
)

func main() {
	a1 := rating.New() // mu = 25, sigma = 8.333
	a2 := rating.NewWithOptions(&types.OpenSkillOptions{
		Mu: ptr.Float64(32.444),
		Sigma: ptr.Float64(5.123),
	}) // mu = 32.444, sigma = 5.123

	b1 := rating.NewWithOptions(&types.OpenSkillOptions{
		Mu: ptr.Float64(43.381),
		Sigma: ptr.Float64(2.421),
	}) // mu = 43.381, sigma = 2.421
	b2 := rating.NewWithOptions(&types.OpenSkillOptions{
		Mu: ptr.Float64(25.188),
		Sigma: ptr.Float64(6.211),
	}) // mu = 25.188, sigma = 6.211

}

If a1 and a2 are on a team, and wins against a team of b1 and b2, send this into Rate

package main

import (
	"github.com/intinig/go-openskill/rating"
	"github.com/intinig/go-openskill/types"
)

func main() {
	rating.Rate([]types.Team{
		{
			a1,
			a2,
		},
		{
			b1,
			b2
		},
		&types.OpenSkillOptions{},
	}) // []types.Team{{mu: 28.67..., sigma: 8.07...}, ...
}

Teams can be asymmetric, too! For example, a game like Axis and Allies can be 3 vs 2, and this can be modeled here.

Ranking

When displaying a rating, or sorting a list of ratings, you can use ordinal

package main

import (
	"github.com/intinig/go-openskill/rating"
	"github.com/intinig/go-openskill/types"
)

func main() {
	a1 := rating.NewWithOptions(&types.OpenSkillOptions{
		Mu: ptr.Float64(43.07),
		Sigma: ptr.Float64(2.42),
	}) 
	a1.Ordinal() // 35.81
}

By default, this returns mu - 3*sigma, showing a rating for which there's a 99.7% likelihood the player's true rating is higher, so with early games, a player's ordinal rating will usually go up and could go up even if that player loses.

Artificial Ranking

If your teams are listed in one order but your ranking is in a different order, for convenience you can specify a Ranks option, such as

package main

import (
	"github.com/intinig/go-openskill/rating"
	"github.com/intinig/go-openskill/types"
)

func main() {
	a1 := rating.New()
	rating.Rate([]types.Team{{a1}, {a1}, {a1}, {a1}}, &types.OpenSkillOptions{
		Ranks: []int{4, 1, 3, 2},
    }) // []types.Team{Mu: 20.963..., Sigma: 8.084...} 🐌, { Mu: 27.795, Sigma: 8.263 }🥇
}

It's assumed that the lower ranks are better (wins), while higher ranks are worse (losses). You can provide a Score instead, where lower is worse and higher is better. These can just be raw scores from the game, if you want.

Ties should have either equivalent rank or score.

package main

import (
	"github.com/intinig/go-openskill/rating"
	"github.com/intinig/go-openskill/types"
)

func main() {
	a1 := rating.New()
	rating.Rate([]types.Team{{a1}, {a1}, {a1}, {a1}}, &types.OpenSkillOptions{
		Score: []int{44, 16, 23, 21},
    }) // []types.Team{Mu: 20.963..., Sigma: 8.084...} 🐌, { Mu: 27.795, Sigma: 8.263 }🥇
}

Predicting Winners

For a given match of any number of teams, using PredictWin you can find a relative odds that each of those teams will win.

package main

import (
	"github.com/intinig/go-openskill/rating"
	"github.com/intinig/go-openskill/types"
)

func main() {
	a1 := rating.New()
	a2 := rating.NewWithOptions(&types.OpenSkillOptions{
		Mu: ptr.Float64(33.564),
		Sigma: ptr.Float64(1.123),
	}) 
    
	rating.PredictWin([]types.Team{{a1}, {a2}}) // [ 0.45110899943132493, 0.5488910005686751 ]  they add up to 1
}

Predicting Draws

Also, for a given match, using PredictDraw you can get the relative chance that these teams will draw. The number returned here should be treated as relative to other matches, but in reality the odds of an actual legal draw will be impacted by some meta-function based on the rules of the game.

package main

import (
	"github.com/intinig/go-openskill/rating"
	"github.com/intinig/go-openskill/types"
)

func main() {
	a1 := rating.New()
	a2 := rating.NewWithOptions(&types.OpenSkillOptions{
		Mu: ptr.Float64(33.564),
		Sigma: ptr.Float64(1.123),
	}) 
    
	rating.PredictDraw([]types.Team{{a1}, {a2}}) // 0.09025530533015186
}

This can be used in a similar way that you might use quality in TrueSkill if you were optimizing a matchmaking system, or optimizing a tournament tree structure for exciting finals and semi-finals such as in the NCAA.

Alternative Models

By default, we use a Plackett-Luce model, which is probably good enough for most cases. When speed is an issue, the library runs faster with other models

package main

import (
	"github.com/intinig/go-openskill/rating"
	"github.com/intinig/go-openskill/types"
)

func main() {
	a1 := rating.New()
	a2 := rating.NewWithOptions(&types.OpenSkillOptions{
		Mu: ptr.Float64(33.564),
		Sigma: ptr.Float64(1.123),
	})

	rating.Rate([]types.Team{{a1}, {a2}}, &types.OpenSkillOptions{
		Model: types.ModelBradleyTerryFull,
    }) 
}
  • Bradley-Terry rating models follow a logistic distribution over a player's skill, similar to Glicko.
  • Thurstone-Mosteller rating models follow a gaussian distribution, similar to TrueSkill. Gaussian CDF/PDF functions differ in implementation from system to system (they're all just chebyshev approximations anyway). The accuracy of this model isn't usually as great either, but tuning this with an alternative gamma function can improve the accuracy if you really want to get into it.
  • Full pairing should have more accurate ratings over partial pairing, however in high k games (like a 100+ person marathon race), Bradley-Terry and Thurstone-Mosteller models need to do a calculation of joint probability which involves is a k-1 dimensional integration, which is computationally expensive. Use partial pairing in this case, where players only change based on their neighbors.
  • Plackett-Luce (default) is a generalized Bradley-Terry model for k ≥ 3 teams. It scales best.

Implementations in other languages

TODO

Current status of porting the project through porting the test suite from the original project.

  • src/tests/util/rankings.test.ts (6.331 s)
  • src/models/tests/index.test.ts (6.933 s)
  • src/models/tests/thurstone-mosteller-part-series.test.ts (6.941 s)
  • src/models/tests/thurstone-mosteller-full-series.test.ts (6.942 s)
  • src/tests/rating.test.ts (6.953 s)
  • src/models/tests/plackett-luce-series.test.ts (6.953 s)
  • src/models/tests/bradley-terry-part-series.test.ts (6.953 s)
  • src/models/tests/bradley-terry-part.test.ts (6.948 s)
  • src/tests/rate.test.ts (6.961 s)
  • src/models/tests/bradley-terry-full.test.ts (6.962 s)
  • src/models/tests/bradley-terry-full-series.test.ts (6.961 s)
  • src/models/tests/thurstone-mosteller-full.test.ts (6.963 s)
  • src/tests/predict-win.test.ts (6.968 s)
  • src/models/tests/thurstone-mosteller-part.test.ts (6.97 s)
  • src/models/tests/plackett-luce.test.ts (6.984 s)
  • src/tests/predict-draw.test.ts
  • src/tests/util/ladder-pairs.test.ts
  • src/tests/ordinal.test.ts
  • src/tests/util/util-c.test.ts
  • src/tests/util/util-a.test.ts
  • src/tests/util/score.test.ts
  • src/tests/util/team-rating.test.ts
  • src/tests/util/util-sum-q.test.ts

go-openskill's People

Contributors

intinig avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.