diff options
author | emkael <emkael@tlen.pl> | 2014-10-06 15:51:30 +0200 |
---|---|---|
committer | emkael <emkael@tlen.pl> | 2014-10-06 15:51:30 +0200 |
commit | 8249784c586a088c09598305fd408f376aad26fb (patch) | |
tree | 21a894b662a4c5bc4271d146bb6a3f38e715c236 /f1elo |
* initial commit
Diffstat (limited to 'f1elo')
-rw-r--r-- | f1elo/__init__.py | 0 | ||||
-rw-r--r-- | f1elo/db.py | 25 | ||||
-rw-r--r-- | f1elo/elo.py | 62 | ||||
-rw-r--r-- | f1elo/model.py | 89 |
4 files changed, 176 insertions, 0 deletions
diff --git a/f1elo/__init__.py b/f1elo/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/f1elo/__init__.py diff --git a/f1elo/db.py b/f1elo/db.py new file mode 100644 index 0000000..49ccc3d --- /dev/null +++ b/f1elo/db.py @@ -0,0 +1,25 @@ +import __main__ +from os import path + +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +import json + +config = json.load(open(path.dirname(__main__.__file__) + '/config/db.json')) +engine = create_engine("mysql://{0[user]}:{0[pass]}@{0[host]}/{0[db]}?charset=utf8".format(config)) +Session = sessionmaker(bind=engine) + +from f1elo.model import Driver + +def find_driver(name, country, session): + driver = session.query(Driver).filter(Driver.driver==name).first() + if driver: + return driver + else: + driver = Driver() + driver.driver = name + driver.country = country + session.add(driver) + return driver + diff --git a/f1elo/elo.py b/f1elo/elo.py new file mode 100644 index 0000000..3ddc6e4 --- /dev/null +++ b/f1elo/elo.py @@ -0,0 +1,62 @@ +import __main__ +from os import path + +from f1elo.model import * + +import json +from itertools import combinations + +class Elo: + def __init__(self, session): + self.session = session + self.config = json.load(open(path.dirname(__main__.__file__) + '/config/elo.json')) + + def get_ranking(self, driver, rank_date=None): + rank = driver.get_ranking(rank_date) + if rank: + return rank.ranking + return self.config['initial_ranking'] + + def get_entry_ranking(self, entry, date=None): + return sum([self.get_ranking(d, date) for d in entry.drivers]) / len(entry.drivers) + + def rank_race(self, race): + entries = race.entries + entries_to_compare = [] + rankings = {} + new_rankings = {} + for e in entries: + rankings[e] = self.get_entry_ranking(e, race.date) + new_rankings[e] = 0.0 + if e.result_group: + entries_to_compare.append(e) + for c in combinations(entries_to_compare, 2): + score = self.get_score(rankings[c[0]] - rankings[c[1]], self.get_outcome(c), self.get_importance(race, [rankings[c[0]], rankings[c[1]]])) + #print c[0], '@', rankings[c[0]] + #print 'against' + #print c[1], '@', rankings[c[1]] + #print 'score: ', score + #print + new_rankings[c[0]] += score + new_rankings[c[1]] -= score + return new_rankings + + def get_importance(self, race, rankings): + base_importance = self.config['importance'][race.type.code] + min_rank = min(rankings) + if min_rank < 2100: + return base_importance + if min_rank <= 2400: + return base_importance * 0.75 + return base_importance / 2 + + + def get_outcome(self, entries): + if entries[0].result_group < entries[1].result_group: + return 1 + elif entries[0].result_group > entries[1].result_group: + return 0 + return 0.5 + + def get_score(self, difference, outcome, importance): + return importance * (outcome - 1 / (1 + (10 ** (-difference / self.config['disparity'])))) diff --git a/f1elo/model.py b/f1elo/model.py new file mode 100644 index 0000000..3133a59 --- /dev/null +++ b/f1elo/model.py @@ -0,0 +1,89 @@ +from sqlalchemy import Column, Table, ForeignKey +from sqlalchemy.types import Date, Float, Integer, String, Boolean +from sqlalchemy.orm import backref, relationship, sessionmaker +from sqlalchemy.ext.declarative import declarative_base + +Base = declarative_base() + +class Driver(Base): + __tablename__ = 'drivers' + + id = Column(Integer, primary_key=True) + driver = Column(String) + country = Column(String) + + rankings = relationship('Ranking', order_by='Ranking.rank_date', back_populates='driver') + + def __repr__(self): + return (u"<%s (#%d)>" % (self.driver, self.id)).encode('utf8') + + def get_ranking(self, rank_date=None): + ranks = self.rankings + if rank_date is not None: + ranks = [r for r in ranks if r.rank_date < rank_date] + if len(ranks): + return ranks[-1] + return None + +driver_entry = Table('driver_entries', Base.metadata, + Column('_driver', Integer, ForeignKey('drivers.id')), + Column('_entry', Integer, ForeignKey('entries.id')), + Column('id', Integer)) + +class Entry(Base): + __tablename__ = 'entries' + + id = Column(Integer, primary_key=True) + result = Column(String) + car_no = Column(String) + result_group = Column(Integer) + _race = Column(Integer, ForeignKey('races.id')) + + race = relationship('Race', back_populates='entries', order_by=result_group) + drivers = relationship('Driver', secondary=driver_entry) + + def __repr__(self): + return ('#%s (%s) %s[%d]' % (self.car_no, ', '.join([driver.__repr__().decode('utf8') for driver in self.drivers]), self.result, self.result_group)).encode('utf8') + +class Race(Base): + __tablename__ = 'races' + + id = Column(Integer, primary_key=True) + race = Column(String) + date = Column(Date) + ranked = Column(Boolean) + + _type = Column(Integer, ForeignKey('race_types.id')) + type = relationship('RaceType', back_populates='races', order_by='Race.date') + entries = relationship('Entry', back_populates='race', order_by='Entry.result_group') + + def __repr__(self): + return ('%s (%s)' % (self.race, self.date)).encode('utf8') + +class RaceType(Base): + __tablename__ = 'race_types' + + id = Column(Integer, primary_key=True) + code = Column(String) + description = Column(String) + + races = relationship('Race', back_populates='type') + + def __repr__(self): + return ('%s (%s)' % (self.description, self.code)).encode('utf8') + +class Ranking(Base): + __tablename__ = 'rankings' + + id = Column(Integer, primary_key=True) + rank_date = Column(Date) + ranking = Column(Float) + + _driver = Column(Integer, ForeignKey('drivers.id')) + driver = relationship('Driver', back_populates='rankings', order_by=rank_date) + + def __repr__(self): + return ("%s: %0.2f (%s)" % (self.driver.__repr__().decode('utf8'), self.ranking, self. rank_date)).encode('utf8') + + +__all__ = ['Driver', 'Entry', 'Ranking', 'Race', 'RaceType'] |