public async Task <float> CalculateExpectedPointsAsync(Element element) { var fplWebApiClient = new WebApiClient(); ElementSummaryResponse elementSummaryResponse = await fplWebApiClient.GetElementSummaryAsync(element.Id); float minutesPlayed = elementSummaryResponse.History.Sum(h => h.Minutes); float ninetiesPlayed = minutesPlayed / 90; float yellowCards = element.YellowCards; float yellowCardsPerNinety = yellowCards / ninetiesPlayed; float expectedYellowCardPoints = (yellowCardsPerNinety * PointsPerYellowCard); float redCards = element.RedCards; float redCardsPerNinety = redCards / ninetiesPlayed; float expectedRedCardPoints = (redCardsPerNinety * PointsPerRedCard); // Goals contribution // TODO: consider discounting (100% for last 6 down to 50% for 20 games ago?) float pointsPerGoal = PointsPerGoal(element.ElementType); float goals = element.GoalsScored; float goalsPerNinety = goals / ninetiesPlayed; float expectedPointsFromGoalsOnHistory = pointsPerGoal * goalsPerNinety; float expectedGoalsPerThreat = ExpectedGoalsPerThreat(element.ElementType); float threat = elementSummaryResponse.History.Sum(h => float.Parse(h.Threat)); float threatPerNinety = threat / ninetiesPlayed; float expectedGoalsFromThreat = threatPerNinety / expectedGoalsPerThreat; float expectedPointsFromGoalsOnThreat = pointsPerGoal * expectedGoalsFromThreat; float expectedPointsFromGoals = (expectedPointsFromGoalsOnHistory * HistoryGoalsFactor) + (expectedPointsFromGoalsOnThreat * ThreatGoalsFactor); return(expectedYellowCardPoints + expectedRedCardPoints + expectedPointsFromGoals); }
public async Task Make(WebApiClient fplWebApiClient, StaticResponse staticResponse, string path) { IEnumerable <Fixture> fixtures = await fplWebApiClient.GetFixturesAsync(); using (StreamWriter writer = new StreamWriter(File.Create(path))) { writer.WriteLine("event_id,player_id,player_name,difficulty,home,points"); int progress = 0; int max = staticResponse.Elements.Count(); foreach (Element element in staticResponse.Elements) { Console.WriteLine($"Predicting {++progress} of {max}"); ElementSummaryResponse elementResponse = await fplWebApiClient.GetElementSummaryAsync(element.Id); if (elementResponse == null) { continue; } ElementHistoryPast history2017 = elementResponse.HistoryPast.SingleOrDefault(hp => hp.SeasonName == "2017/18"); ElementHistoryPast history2018 = elementResponse.HistoryPast.SingleOrDefault(hp => hp.SeasonName == "2018/19"); ElementHistoryPast history2019 = elementResponse.HistoryPast.SingleOrDefault(hp => hp.SeasonName == "2019/20"); ModelInput fixtureData = new ModelInput() { Isvalid2017 = (history2017 == null) ? 0 : 1, Minutes2017 = (history2017 == null) ? 0 : history2017.Minutes, Points2017 = (history2017 == null) ? 0 : history2017.TotalPoints, Influence2017 = (history2017 == null) ? 0 : float.Parse(history2017.Influence), Creativity2017 = (history2017 == null) ? 0 : float.Parse(history2017.Creativity), Threat2017 = (history2017 == null) ? 0 : float.Parse(history2017.Threat), Isvalid2018 = (history2018 == null) ? 0 : 1, Minutes2018 = (history2018 == null) ? 0 : history2018.Minutes, Points2018 = (history2018 == null) ? 0 : history2018.TotalPoints, Influence2018 = (history2018 == null) ? 0 : float.Parse(history2018.Influence), Creativity2018 = (history2018 == null) ? 0 : float.Parse(history2018.Creativity), Threat2018 = (history2018 == null) ? 0 : float.Parse(history2018.Threat), Isvalid2019 = (history2019 == null) ? 0 : 1, Minutes2019 = (history2019 == null) ? 0 : history2019.Minutes, Points2019 = (history2019 == null) ? 0 : history2019.TotalPoints, Influence2019 = (history2019 == null) ? 0 : float.Parse(history2019.Influence), Creativity2019 = (history2019 == null) ? 0 : float.Parse(history2019.Creativity), Threat2019 = (history2019 == null) ? 0 : float.Parse(history2019.Threat), Playerid = element.Id, Teamid = element.Team, Position = element.ElementType, Selectedby = float.Parse(element.SelectedByPercent), Transfersin = element.TransfersInEvent, Transfersout = element.TransfersOutEvent, Diff = 2F, Home = "0", Value = element.NowCost }; foreach (ElementHistory history in elementResponse.History) { Fixture gwFixture = fixtures.Single(f => f.Id == history.FixtureId); AddPreviousGameweekToInput(fixtureData, history, gwFixture, staticResponse.CurrentEvent); } foreach (ElementFixture fixture in elementResponse.Fixtures.Take(5)) { fixtureData.Diff = fixture.Difficulty; fixtureData.Home = fixture.IsHome ? "1" : "0"; var predictionResult = ConsumeModel.Predict(fixtureData); writer.WriteLine($"{fixture.EventId},{element.Id},{element.FirstName} {element.SecondName},{fixtureData.Diff},{fixtureData.Home},{predictionResult.Score}"); } } } }
public async Task Build(WebApiClient fplWebApiClient, StaticResponse staticResponse, string path) { IEnumerable <Fixture> fixtures = await fplWebApiClient.GetFixturesAsync(); using (StreamWriter writer = new StreamWriter(File.Create(path))) { Event currentEvent = staticResponse.Events.Single(e => e.IsCurrent); int numPreviousGameweeks = currentEvent.Id - 1; string gameweeksHeader = BuildGameweeksHeader(currentEvent.Id); writer.WriteLine($"{PreviousSeason.GetHeaderRow("2017")},{PreviousSeason.GetHeaderRow("2018")},{PreviousSeason.GetHeaderRow("2019")},{gameweeksHeader},playerid,teamid,position,selectedby,transfersin,transfersout,diff,home,value,points"); int progress = 0; //IEnumerable<Element> elementsToProcess = staticResponse.Elements.Take(50); IEnumerable <Element> elementsToProcess = staticResponse.Elements; int max = elementsToProcess.Count(); foreach (Element element in elementsToProcess) { Console.WriteLine($"Processing {++progress} of {max}"); ElementSummaryResponse elementResponse = await fplWebApiClient.GetElementSummaryAsync(element.Id); if (elementResponse == null) { continue; } ElementHistoryPast history2017 = elementResponse.HistoryPast.SingleOrDefault(hp => hp.SeasonName == "2017/18"); ElementHistoryPast history2018 = elementResponse.HistoryPast.SingleOrDefault(hp => hp.SeasonName == "2018/19"); ElementHistoryPast history2019 = elementResponse.HistoryPast.SingleOrDefault(hp => hp.SeasonName == "2019/20"); PreviousSeason season2017 = BuildPreviousSeason(history2017); PreviousSeason season2018 = BuildPreviousSeason(history2018); PreviousSeason season2019 = BuildPreviousSeason(history2019); // First pass to build all previous match data by gameweek var previousMatchesByGameweek = new Dictionary <int, PreviousMatch>(); foreach (ElementHistory history in elementResponse.History) { // TODO: add support for multi-match weeks if (previousMatchesByGameweek.ContainsKey(history.Round)) { continue; } Fixture fixture = fixtures.Single(f => f.Id == history.FixtureId); PreviousMatch gameweek = BuildPreviousMatch(history, fixture); previousMatchesByGameweek.Add(history.Round, gameweek); } PreviousMatch gameweekNull = BuildPreviousMatch(null, null); foreach (ElementHistory history in elementResponse.History) { TrainingDataRow row = new TrainingDataRow(); row.Season2017 = season2017; row.Season2018 = season2018; row.Season2019 = season2019; row.PreviousGameweeks = new PreviousMatch[numPreviousGameweeks]; int previousRound = history.Round - 1; for (int round = 0; round < numPreviousGameweeks; ++round) { if (previousMatchesByGameweek.ContainsKey(previousRound)) { row.PreviousGameweeks[round] = previousMatchesByGameweek[previousRound]; } else { row.PreviousGameweeks[round] = gameweekNull; } --previousRound; } Fixture fixture = fixtures.Single(f => f.Id == history.FixtureId); row.AtHome = history.WasHome ? 1 : 0; if (history.WasHome) { row.Difficulty = fixture.HomeTeamDifficulty; } else { row.Difficulty = fixture.AwayTeamDifficulty; } row.Value = history.Value; row.TotalPoints = history.TotalPoints; string seasonsData = $"{row.Season2017},{row.Season2018},{row.Season2019}"; var previousGameweeksBuilder = new StringBuilder(); for (int round = 0; round < numPreviousGameweeks; ++round) { previousGameweeksBuilder.Append(row.PreviousGameweeks[round]); if (round < (numPreviousGameweeks - 1)) { previousGameweeksBuilder.Append(","); } } string gameweeksData = previousGameweeksBuilder.ToString(); string otherData = $"{element.Id},{element.Team},{element.ElementType},{element.SelectedByPercent:F1},{history.TransfersIn:F1},{history.TransfersOut:F1},{row.Difficulty},{row.AtHome},{row.Value:F1},{row.TotalPoints:F1}"; writer.WriteLine($"{seasonsData},{gameweeksData},{otherData}"); } } } }