Lineup Optimizer Part 1 — Nick's Niche (2024)

DFSLineup Optimizer

Written By Nick's Niche

Fanduel Player List

Hey Everyone!

Today's this tutorial is a step-by-step walkthrough to create your own daily fantasy sports lineup optimizer! Whether you want a single lineup, or are maxing out a 150 entry tournament, this video is for you!

***NOTE**** This video is going to be a fairly high level view of the code itself. Going forward my tutorial videos will be much more granular explaining what is happening, when, and why with demonstrations and examples for learning purposes. This video is just a preview of the end game to give everyone something to work toward!

Packages needed: pandas, pulp, openpyxl, and re as shown being imported below.

import pandas as pdfrom pulp import *import openpyxlimport re

Next up we will open a temporary excel workbook in the background to write lineups to -

wb = openpyxl.Workbook()ws = wb.active

Then, we will be loading our fantasy player list csv into a pandas dataframe for manipulation. -

players = pd.read_csv(r"C:\Users\nfwya\Fanduel\playerLists\20200807.csv", usecols= ['Id', 'Position', 'FPPG', 'Salary'])

After our player data is loaded, it’s time to start working with it. Regrouping dataframe by position and resetting the dataframe index off of positions — This allows us to use the grouped series as a new dataframe.

availables = players.groupby(["Position", "Id", "FPPG", "Salary", 'Team']).agg('count')availables = availables.reset_index()

Next, we need to define empty salary and point dictionaries in order to track the metrics for our lineup optimizer, by storing each player’s data by position -

salaries = {}points = {}teams = {}

Next, we will need to loop through each position in our grouped dataframe to create a dictionary with key value pair formatting of:

{player id: salary} and {player id: points}

Then, we will update empty dictionaries with a new dictionary entries with the Position being the Key, and all the player IDs as the value, with dual roles as the Key for the nested dictionary. ------ This results in nested dictionary with the following logic {K1:V1}, {K2:V2} --- {K1:{K2:V2}} Where K2=V1 ---- K1=Position, V1=K2=Player ID, V2= Points/Salary

for pos in availables.Position.unique(): available_pos = availables[availables.Position == pos] salary = list(available_pos[['Id', 'Salary']].set_index("Id").to_dict().values())[0] point = list(available_pos[['Id', 'FPPG']].set_index("Id").to_dict().values())[0] salaries[pos] = salary points[pos] = point

After this, we need to define dictionary of positional constraints (how many player we need from each position) and define the Salary Cap we want to use.

pos_num_available = { "PG": 2, "SG": 2, "SF": 2, "PF": 2, "C": 1 }salary_cap = 60000

Next, we will be establishing our lineup creation loop:

for lineup in range(1,151):

To do this, we will need to create a pulp variable to track whether player is chosen or not, (Binary = yes/no)

for lineup in range(1,151): _vars = {k: LpVariable.dict(k, v, cat='Binary') for k, v in points.items()}

define our ‘problem’, maximize function because we want max fantasy points

for lineup in range(1,151): _vars = {k: LpVariable.dict(k, v, cat='Binary') for k, v in points.items()} prob = LpProblem("Fantasy", LpMaximize)

Create empty lists to track rewards, costs and positional constraints

for lineup in range(1,151): _vars = {k: LpVariable.dict(k, v, cat='Binary') for k, v in points.items()} prob = LpProblem("Fantasy", LpMaximize) rewards = [] costs = [] position_constraints = []

Iterate over each player to populate previously created tracking lists for solving.

for lineup in range(1,151): _vars = {k: LpVariable.dict(k, v, cat='Binary') for k, v in points.items()} prob = LpProblem("Fantasy", LpMaximize) rewards = [] costs = [] position_constraints = [] for k, v in _vars.items(): costs += lpSum([salaries[k][i] * _vars[k][i] for i in v]) rewards += lpSum([points[k][i] * _vars[k][i] for i in v]) prob += lpSum([_vars[k][i] for i in v]) == pos_num_available[k]

Next, we will add the costs(Salary) and rewards(Points) into the optimization calculation, add in our logic check for slightly lowering the salary cap for every lineup after the first iteration to ensure varied lineups, and then solve.

for lineup in range(1,151): _vars = {k: LpVariable.dict(k, v, cat='Binary') for k, v in points.items()} prob = LpProblem("Fantasy", LpMaximize) rewards = [] costs = [] position_constraints = [] for k, v in _vars.items(): costs += lpSum([salaries[k][i] * _vars[k][i] for i in v]) rewards += lpSum([points[k][i] * _vars[k][i] for i in v]) prob += lpSum([_vars[k][i] for i in v]) == pos_num_available[k] prob += lpSum(rewards) prob += lpSum(costs) <= salary_cap if not lineup == 1: prob += (lpSum(rewards) <= total_score-0.01) prob.solve()

Now that we have solved the lineup function, we need to evaluate it to return the total score, then reset our column variable for writing to excel back to column 1 to start the new lineup.

for lineup in range(1,151): _vars = {k: LpVariable.dict(k, v, cat='Binary') for k, v in points.items()} prob = LpProblem("Fantasy", LpMaximize) rewards = [] costs = [] position_constraints = [] for k, v in _vars.items(): costs += lpSum([salaries[k][i] * _vars[k][i] for i in v]) rewards += lpSum([points[k][i] * _vars[k][i] for i in v]) prob += lpSum([_vars[k][i] for i in v]) == pos_num_available[k] prob += lpSum(rewards) prob += lpSum(costs) <= salary_cap if not lineup == 1: prob += (lpSum(rewards) <= total_score-0.01) prob.solve() score= str(prob.objective) colnum = 1

Now, the default output of this function is going to be a list of every single player in our dataset, with a variable of either a 1 or 0 assigned to it, depending on whether or not that player was chosen for the lineup. So we need to loop through this list and single out the players chosen, and write them to excel.

for lineup in range(1,151): _vars = {k: LpVariable.dict(k, v, cat='Binary') for k, v in points.items()} prob = LpProblem("Fantasy", LpMaximize) rewards = [] costs = [] position_constraints = [] for k, v in _vars.items(): costs += lpSum([salaries[k][i] * _vars[k][i] for i in v]) rewards += lpSum([points[k][i] * _vars[k][i] for i in v]) prob += lpSum([_vars[k][i] for i in v]) == pos_num_available[k] prob += lpSum(rewards) prob += lpSum(costs) <= salary_cap if not lineup == 1: prob += (lpSum(rewards) <= total_score-0.01) prob.solve() score= str(prob.objective) constraints = [str(const) for const in prob.constraints.values()] colnum = 1 for v in prob.variables(): score = score.replace(v.name, str(v.varValue)) if v.varValue !=0: ws.cell(row=lineup, column=colnum).value = v.name colnum +=1

Next, we just need to save our total_score variable to reference in all lineup creations after the first run through, write our final score into the excel spreadsheet for reference, and print out the lineup number and score if you would like to see the results as it runs. That finishes up our for loop creating the lineups, so we decrease the indent level back outside of the for loop and save the workbook. And we’re done!

for lineup in range(1,151): _vars = {k: LpVariable.dict(k, v, cat='Binary') for k, v in points.items()} prob = LpProblem("Fantasy", LpMaximize) rewards = [] costs = [] position_constraints = [] for k, v in _vars.items(): costs += lpSum([salaries[k][i] * _vars[k][i] for i in v]) rewards += lpSum([points[k][i] * _vars[k][i] for i in v]) prob += lpSum([_vars[k][i] for i in v]) == pos_num_available[k] prob += lpSum(rewards) prob += lpSum(costs) <= salary_cap if not lineup == 1: prob += (lpSum(rewards) <= total_score-0.01) prob.solve() score= str(prob.objective) constraints = [str(const) for const in prob.constraints.values()] colnum = 1 for v in prob.variables(): score = score.replace(v.name, str(v.varValue)) if v.varValue !=0: ws.cell(row=lineup, column=colnum).value = v.name colnum +=1 total_score = eval(score) ws.cell(row=lineup, column=colnum).value = total_score print(lineup, total_score)wb.save(r"\playerLists\Lineups20200807_12111.xlsx")

With this export format a little cleanup will be required prior to uploading to fanduel: -Remove Position and following Underscore from player ID ----- PF_PLAYERID == PLAYERID Then find and replace interior underscore with hyphen to match format of fanduel download. Can write a simple vlookup function in excel to return the player name from the fanduel download if you want to review lineups prior to uploading.

DFSLineup Optimizer

Nick's Niche

Lineup Optimizer Part 1 — Nick's Niche (2024)

FAQs

What is the best paid DFS lineup optimizer? ›

FTN's NFL Lineup Optimizer for DFS is the best optimizer for daily fantasy (DFS) football gamers. The optimizer gives you what you need to compete on a consistent basis.

What is FTN's NFL lineup optimizer for DFS? ›

FTN's NFL Lineup Optimizer for DFS is the best optimizer for daily fantasy (DFS) across DraftKings and FanDuel. Find those critical plays with low ownership that will give you a huge edge on the competition. Enjoy our daily MLB projections, powered by FTN Data. Includes all primary stats for hitters and pitchers.

Are there any free DFS lineup optimizers? ›

NFL Optimizer

Use our free NFL lineup generator to build optimized DraftKings and Fanduel lineups. This tool takes our top rated DFS projections and adds on the ability to lock, filter, and exclude players and teams. Lock in your core players and then hit 'Optimize' to build multiple lineups instantly.

Who has the most accurate NFL DFS projections? ›

Draft Sharks Wins Fantasy Pros 3-Year Rolling Accuracy Title
RankMost Accurate Expertssite
1Jared SmolaDraft Sharks
2Rob WaziakFantasy Life
3Nick ZylakFantasy Football Advice
4Ryan Noonan4for4
1 more row
May 16, 2024

What is the best NBA dfs optimizer? ›

FTN's NBA Lineup Optimizer for DFS is the best optimizer for daily fantasy (DFS) basketball players. With this optimizer, you'll always be playing to win. It's almost impossible to scale and win consistency in NBA DFS without an optimizer. If you haven't used one yet — welcome to the big leagues.

Who has the most accurate NBA dfs projections? ›

Daily Fantasy Nerd is the best tool for DFS analytics and bankroll tracking. It has the most accurate projections, relevant metrics, and an optimizer for efficient lineup building!

What is the best optimizer for MLB DFS? ›

FTN's MLB Lineup Optimizer for DFS is the best optimizer for daily fantasy baseball players. The optimizer has every tool you need to finish in the green and build your bankroll on a consistent basis.

Is SaberSim worth it? ›

"Traditional optimizers are outdated. I've tried almost every one of them, and SaberSim is the best one, hands down." "SaberSim notices players I'd never pick up on. You get more leverage and value using a sim built by data scientists."

Top Articles
Latest Posts
Article information

Author: Jamar Nader

Last Updated:

Views: 6167

Rating: 4.4 / 5 (55 voted)

Reviews: 86% of readers found this page helpful

Author information

Name: Jamar Nader

Birthday: 1995-02-28

Address: Apt. 536 6162 Reichel Greens, Port Zackaryside, CT 22682-9804

Phone: +9958384818317

Job: IT Representative

Hobby: Scrapbooking, Hiking, Hunting, Kite flying, Blacksmithing, Video gaming, Foraging

Introduction: My name is Jamar Nader, I am a fine, shiny, colorful, bright, nice, perfect, curious person who loves writing and wants to share my knowledge and understanding with you.