<commit_before>package de.cupofjava.machinelearning.soccer.worldcup

import com.google.common.base.Charsets
import com.google.common.io.Resources
import de.cupofjava.machinelearning.soccer.worldcup.feature.*
import groovy.util.logging.Slf4j
import org.encog.engine.network.activation.ActivationLinear
import org.encog.engine.network.activation.ActivationTANH
import org.encog.ml.data.MLData
import org.encog.ml.data.MLDataSet
import org.encog.ml.train.MLTrain
import org.encog.ml.train.strategy.end.EarlyStoppingStrategy
import org.encog.ml.train.strategy.end.EndIterationsStrategy
import org.encog.ml.train.strategy.end.EndMaxErrorStrategy
import org.encog.neural.networks.BasicNetwork
import org.encog.neural.networks.layers.BasicLayer
import org.encog.neural.networks.training.propagation.resilient.ResilientPropagation
import org.encog.util.concurrency.EngineConcurrency

import static groovyx.gpars.GParsPool.withPool

/**
 * TODO javadoc
 *
 * @author fmueller
 */
@Slf4j
class PredictMatchesMain {

  private static double TEST_DATA_RATIO = 0.2
  private static double TRAINING_DATA_RATIO = 0.6
  private static double VALIDATION_DATA_RATIO = 0.2

  private static double MAX_ERROR_RATE = 0.1
  private static int MAX_ITERATIONS = 1000

  private static double HIDDEN_LAYER_RATIO = 0.667

  static void main(args) {
    log.info("Loading match data...")
    Matches.storeAllMatches(MatchParser.parseMatches(
        Resources.toString(Resources.getResource("soccerData.csv"), Charsets.UTF_8)))
    List<Match> matches = new LinkedList<>(Matches.allMatches())
    log.info("Loaded {} matches", matches.size())

    int testDataSetSize = (int) Math.round(matches.size() * TEST_DATA_RATIO)
    int validationDataSetSize = (int) Math.round(matches.size() * VALIDATION_DATA_RATIO)
    int trainingDataSetSize = (int) Math.round(matches.size() * TRAINING_DATA_RATIO)

    log.info("Training data set size: {}", trainingDataSetSize)
    log.info("Validation data set size: {}", validationDataSetSize)

    log.info("Splitting data into training, validation and test data set...")
    def testMatches = chooseRandomMatches(matches, testDataSetSize)
    matches.removeAll(testMatches)
    def validationMatches = chooseRandomMatches(matches, validationDataSetSize)
    matches.removeAll(validationMatches)
    def trainingMatches = chooseRandomMatches(matches, trainingDataSetSize)

    def featureSet = new FeatureSet(new HostFactor(),
        new GoalDifferences(), new GoalAverages(),
        new MatchStatistics(), new MatchStatisticsDifferences(),
        new HeadToHead())

    log.info("Computing features for training data set...")
    def trainingData = featureSet.computeDataSet(trainingMatches)
    log.info("Computing features for cross-validation data set...")
    def validationData = featureSet.computeDataSet(validationMatches)

    log.info("Start training...")
    def network = createNeuralNetwork(trainingData)
    trainNetwork(network, trainingData, validationData)

    log.info("Evaluating network performance on test data...")
    testNetwork(network, testMatches, featureSet)
    testBookie(testMatches)

    EngineConcurrency.getInstance().shutdown(2000L)
  }

  private static BasicNetwork createNeuralNetwork(MLDataSet trainingData) {
    BasicNetwork network = new BasicNetwork()
    network.addLayer(new BasicLayer(new ActivationLinear(), false, trainingData.getInputSize()))
    network.addLayer(new BasicLayer(new ActivationTANH(), true, (int) Math.round(trainingData.getInputSize() * HIDDEN_LAYER_RATIO)))
    network.addLayer(new BasicLayer(new ActivationLinear(), true, trainingData.getIdealSize()))
    network.getStructure().finalizeStructure()
    network.reset()<commit_msg>refactored main class and added javadoc<commit_after>package de.cupofjava.machinelearning.soccer.worldcup

import com.google.common.base.Charsets
import com.google.common.io.Resources
import de.cupofjava.machinelearning.soccer.worldcup.feature.*
import groovy.util.logging.Slf4j
import org.encog.engine.network.activation.ActivationLinear
import org.encog.engine.network.activation.ActivationTANH
import org.encog.ml.data.MLData
import org.encog.ml.data.MLDataSet
import org.encog.ml.train.MLTrain
import org.encog.ml.train.strategy.end.EarlyStoppingStrategy
import org.encog.ml.train.strategy.end.EndIterationsStrategy
import org.encog.ml.train.strategy.end.EndMaxErrorStrategy
import org.encog.neural.networks.BasicNetwork
import org.encog.neural.networks.layers.BasicLayer
import org.encog.neural.networks.training.propagation.resilient.ResilientPropagation
import org.encog.util.concurrency.EngineConcurrency

import static groovyx.gpars.GParsPool.withPool

/**
 * This project is a predictor for matches between national soccer teams.
 * For that, a neural network is trained and evaluated on a test data set.
 * Afterwards the performance of the bookmakers is evaluated on this
 * test data set.
 *
 * @author fmueller
 */
@Slf4j
class PredictMatchesMain {

  private static double TEST_DATA_RATIO = 0.2
  private static double VALIDATION_DATA_RATIO = 0.2

  private static double MAX_ERROR_RATE = 0.1
  private static int MAX_ITERATIONS = 1000

  private static double HIDDEN_LAYER_RATIO = 0.667

  static void main(args) {
    log.info("Loading match data...")
    Matches.storeAllMatches(MatchParser.parseMatches(
        Resources.toString(Resources.getResource("soccerData.csv"), Charsets.UTF_8)))
    List<Match> matches = new LinkedList<>(Matches.allMatches())
    log.info("Loaded {} matches", matches.size())

    int testDataSetSize = (int) Math.round(matches.size() * TEST_DATA_RATIO)
    int validationDataSetSize = (int) Math.round(matches.size() * VALIDATION_DATA_RATIO)

    log.info("Splitting data into training, validation and test data set...")
    def testMatches = chooseRandomMatches(matches, testDataSetSize)
    matches.removeAll(testMatches)
    def validationMatches = chooseRandomMatches(matches, validationDataSetSize)
    matches.removeAll(validationMatches)
    def trainingMatches = new HashSet<>(matches)

    def featureSet = new FeatureSet(new HostFactor(),
        new GoalDifferences(), new GoalAverages(),
        new MatchStatistics(), new MatchStatisticsDifferences(),
        new HeadToHead())

    log.info("Computing features for training data set...")
    def trainingData = featureSet.computeDataSet(trainingMatches)
    log.info("Computing features for cross-validation data set...")
    def validationData = featureSet.computeDataSet(validationMatches)

    log.info("Start training...")
    def network = createNeuralNetwork(trainingData)
    trainNetwork(network, trainingData, validationData)

    log.info("Evaluating network performance on test data...")
    testNetwork(network, testMatches, featureSet)
    testBookie(testMatches)

    EngineConcurrency.getInstance().shutdown(2000L)
  }

  private static BasicNetwork createNeuralNetwork(MLDataSet trainingData) {
    BasicNetwork network = new BasicNetwork()
    network.addLayer(new BasicLayer(new ActivationLinear(), false, trainingData.getInputSize()))
    network.addLayer(new BasicLayer(new ActivationTANH(), true, (int) Math.round(trainingData.getInputSize() * HIDDEN_LAYER_RATIO)))
    network.addLayer(new BasicLayer(new ActivationLinear(), true, trainingData.getIdealSize()))
    network.getStructure().finalizeStructure()
    network.reset()
{'fraction_non_alphanumeric': 0.09792486097924862, 'fraction_numerical': 0.005967720059677201, 'mean_word_length': 5.094214876033058, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1799694', 'n_tokens_mistral': 2226, 'n_tokens_neox': 2155, 'n_words': 456}