summaryrefslogtreecommitdiff
path: root/f1elo
diff options
context:
space:
mode:
authoremkael <emkael@tlen.pl>2014-10-06 15:51:30 +0200
committeremkael <emkael@tlen.pl>2014-10-06 15:51:30 +0200
commit8249784c586a088c09598305fd408f376aad26fb (patch)
tree21a894b662a4c5bc4271d146bb6a3f38e715c236 /f1elo
* initial commit
Diffstat (limited to 'f1elo')
-rw-r--r--f1elo/__init__.py0
-rw-r--r--f1elo/db.py25
-rw-r--r--f1elo/elo.py62
-rw-r--r--f1elo/model.py89
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']