Skip to content

Instantly share code, notes, and snippets.

@kliph
Last active January 18, 2019 00:47
Show Gist options
  • Save kliph/2906141e4a0949d8f696b32fcbe2bea7 to your computer and use it in GitHub Desktop.
Save kliph/2906141e4a0949d8f696b32fcbe2bea7 to your computer and use it in GitHub Desktop.
Predict Soccer win streaks
*#*
*~*
.bundle
soccer-predict
source 'https://rubygems.org'
gem 'nokogiri'
gem 'pry'
GEM
remote: https://rubygems.org/
specs:
coderay (1.1.2)
method_source (0.9.2)
mini_portile2 (2.3.0)
nokogiri (1.8.2)
mini_portile2 (~> 2.3.0)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
PLATFORMS
ruby
DEPENDENCIES
nokogiri
pry
BUNDLED WITH
1.17.3
require 'open-uri'
require 'nokogiri'
# previous_picks = ["Chelsea", 'Tottenham']
# Usage:
# load 'predict.rb'
# p = Predict.new(previous_picks)
# start = Time.now; p.realize_streaks!; Time.now - start
# p.scored_streaks
class Predict
attr_accessor :teams, :matches, :upcoming_probabilities, :streaks, :scored_streaks, :previous_picks
def initialize(previous_picks = [])
@previous_picks = previous_picks
@matches = matches_node_set.map do |e|
{
first_team_name(e) => first_team_prob(e),
second_team_name(e) => second_team_prob(e)
}
end
@teams = matches_node_set.map { |e| [e['data-team1'], e['data-team2']] }.flatten.uniq - @previous_picks
@upcoming_probabilities = roi.map { |idx| next_n_matches.map { |ary| ary[idx] }.reduce({}, :merge) }
@streaks = []
@scored_streaks = []
@prediction_weights = prediction_weights
@evaluated_streaks = {}
end
def n
7
end
def evaluate_streaks!(streak)
score = 0
evaluated_streak = streak.each_with_index.map do |team, idx|
team_score = score_team(team, idx)
score += team_score
{team => team_score}
end
@evaluated_streaks[score] = evaluated_streak
end
def realize_streaks!
puts "Evaluating possible streaks..."
@teams.permutation(n) { |streak| evaluate_streaks!(streak) }
puts "Determining top 10 streaks..."
top_scores = @evaluated_streaks.keys.sort{|a, b| b <=> a}.take(10)
@scored_streaks = top_scores.map{|k| [k, @evaluated_streaks[k]]}
end
def score_team(team, idx)
score = @upcoming_probabilities[idx][team]
score * @prediction_weights[idx]
end
def roi
(0...n)
end
def prediction_weights
[1.5, 1.2, 1.2, 1, 1, 1, 1]
end
def next_n_matches
@teams.map do |team|
@matches.partition { |h| h.keys.include? team }.first[roi]
end
end
def percent_to_float(s)
s.sub('%', '').to_f / 100
end
def first_team_name(match_node)
match_node.css('tr.match-top').css('td.team')[0]['data-str']
end
def first_team_prob(match_node)
percent_to_float(match_node.css('tr.match-top').css('td.prob')[0].children.text)
end
def second_team_name(match_node)
match_node.css('tr.match-bottom').css('td.team')[0]['data-str']
end
def second_team_prob(match_node)
percent_to_float(match_node.css('tr.match-bottom').css('td.prob')[0].children.text)
end
def matches_node_set
upcoming_games.css('.match-container')
end
def url
'https://projects.fivethirtyeight.com/soccer-predictions/premier-league/'
end
def doc
Nokogiri::HTML(open(url))
end
def upcoming_games
doc.css('.games-container.upcoming')
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment