{ "info": { "author": "Dan Parker", "author_email": "dan.m.parker0@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "# nflsim\n\nThis package simulates the NFL regular season and playoffs using a simple, customizable Monte Carlo method.\n\n### Installation\n\nThe package is on [PyPI] and can be installed with pip:\n\n```\npip install nflsim\n```\n\n### How it works\n\nDuring each simulation, nflsim uses the methods described below to assign a winner to all remaining NFL games in a given season. It then uses the NFL's complex [tiebreaking procedures] to determine playoff seeding, and the playoffs are simulated game-by-game.\n\nBefore beginning the simulations, each team is assigned a power rating (PWR) with mean 0, such that a team with a PWR of 3 would be favored by 5 points vs a team with a PWR of -2 on a neutral field. By default, the base power rankings for each team are calculated using an equally-weighted combination of normalized versions of the [SRS], [FPI], [DVOA], and [Sagarin] rankings. The rankings systems used and their relative weights are configurable, and custom ranking systems are supported. The individual rating systems and the combined rankings can be regressed to the mean (or to custom team-specific values) as desired.\n\nThe team PWR rankings are adjusted at the beginning of each season simulation by a random amount, determined using a normal distribution with mean 0 and a user-provided standard deviation (2 points by default):\n```\nadjusted_pwr = [PWR] - numpy.random.normal(0, [rank_adj])\n```\n \nThis adjustment represents the uncertainty in each team's base PWR projection, which includes both model error and injury risk. Higher values equate to more variance in outcomes.\n\nWhen simulating a game, the home team's PWR is adjusted upwards by a fixed amount and compared to the away team's PWR. The resulting point differential is used to generate a normal cumulative distribution function, which determines the home team's probability of winning the game. This win probability is compared to a random number to determine the simulated winner of the game:\n```\nhome_pwr_difference = ([Home PWR] + [Home Adj]) - [Away PWR]\nhome_win_probability = 1 - scipy.stats.norm(home_pwr_difference, [stdev]).cdf(0)\nis_home_winner = numpy.random.random() < home_win_probability\n```\n\nBoth the home adjustment ([3 points by default]) and the standard deviation used to generate the normal distribution ([13 points by default]) are configurable.\n\n### Usage\n\n##### Basics\n\nEach simulation is controlled by a Simulate object. You create an object by specifying the season to simulate and the number of simulations:\n```python\nimport nflsim as nfl\nsimulation = nfl.Simulate(season=2018, n_sims=10000)\n```\n \nIf desired, you can customize the values for home-field advantage, the PWR rank adjustment used at the beginning of each simulation, and the standard deviation used when simulating individual games:\n```python\nsimulation = nfl.Simulate(season=2018, n_sims=10000, rank_adj=3, home_adj=2.5, st_dev=13.5)\n``` \n##### PWRsystems\n \nYou can customize how the power rankings are generated by creating a PWRsystems object. You create an object by indicating which systems to include:\n```python\nsystems = nfl.PWRsystems(dvoa=True, fpi=True, sagarin=True)\nsimulation = nfl.Simulate(season=2018, n_sims=10000, pwr_systems=systems)\n```\n\nThe weights for each system (default = 1) can be specified using the built-in objects for each system (SRS, DVOA, FPI, and Sagarin):\n```python\nsystems = nfl.PWRsystems(srs=True, dvoa=nfl.DVOA(weight=2), fpi=nfl.FPI(weight=1.5))\n```\n\nYou can also incorporate your own rating system by creating a generic PWR object and passing it a pandas DataFrame containing the custom rankings. The DataFrame must include one column called 'Team' containing the full team names and another column containing the team rankings. The name of the ranking column should be unique from those of the other systems being used (so don't use \"FPI\" or \"SRS\"):\n```python\nmy_sys_df = pandas.DataFrame([{'Team':'A','Power':-2},{'Team':'B','Power':5}])\nmy_sys = nfl.PWR(weight=2, values=my_sys_df)\nsystems = nfl.PWRsystems(srs=True, others=my_sys)\n```\n\nTo use multiple custom systems, pass a list of DataFrames instead of a single DataFrame:\n```python\ndf1 = pandas.DataFrame([{'Team':'A','Power':-2},{'Team':'B','Power':5}])\ndf2 = pandas.DataFrame([{'Team':'A','Power':0},{'Team':'B','Power':2}])\nmy_sys_1 = nfl.PWR(weight=2, values=df1)\nmy_sys_2 = nfl.PWR(weight=1.5, values=df2)\nsystems = nfl.PWRsystems(srs=True, others=[my_sys_1, my_sys_2])\n```\n\n##### Regression\n\nOptionally, you can choose to regress the ratings generated by each system by creating a Regression object (if regress_to is omitted, no regression will be used). By default, PWR values will be regressed to the sample mean:\n```python\nmy_sys = nfl.SRS(weight=2, regress_to=nfl.Regression())\n```\n\nYou can use fixed weighting by specifying a decimal between 0 and 1, or variable weighting based on the percentage of a specified number of games played (the default option):\n```python\n#(PWR * 0.75) + (sample_mean * 0.25)\nregression_fixed = nfl.Regression(weight=0.25)\n#((PWR * games_played) + (sample_mean * max(0, 10 - games_played))) / max(10, games_played)\nregression_variable = nfl.Regression(n_games=10)\n```\n \nYou can regress PWR to a fixed value rather than using the sample mean:\n```python\nregression = nfl.Regression(to=0, weight=0.5)\n```\n \nYou can also specify a custom regression value for each team using a pandas DataFrame. The DataFrame must contain one column called 'Team' containing the full team names and another called 'Baseline' for the regression values:\n```python\ndf = pd.DataFrame([{'Team':'A','Baseline':-2},{'Team':'B','Baseline':5}])\nregression = nfl.Regression(to=df, n_games=16)\n```\n \nIn addition to (or instead of) regressing the values for individual PWR systems, you can choose to regress the final results after combining the various systems:\n```python\nregression = nfl.Regression(n_games=10)\nsystems = nfl.PWRsystems(regress_to=regression, srs=True, dvoa=nfl.DVOA(weight=2))\n```\n\n##### Execution and Analysis\n\nOnce you've set up your Simulate object, use run() to execute the simulation.\n```python\nregression = nfl.Regression(n_games=10)\nsystems = nfl.PWRsystems(srs=nfl.SRS(regress_to=regression), fpi=True, dvoa=nfl.DVOA(weight=2))\nsimulation = nfl.Simulate(season=2018, n_sims=10000, pwr_systems=systems)\nsimulation.run()\n```\n \nThe run() method will return a reference to the Simulate object, so this syntax is also acceptable:\n```python\nsimulation = nfl.Simulate(season=2018, n_sims=10000, pwr_systems=systems).run()\n```\n\nBy default, run() will use the joblib package to run the simulations in parallel; this can be overridden by setting parallel=False:\n```python\nsimulation = nfl.Simulate(season=2018, n_sims=100).run(parallel=False)\n```\n \nOnce the simulation has executed, the results are aggregated and stored in several related dataframes. These can either be directly accessed using the simulations property:\n```python\nstandings = sim.simulations.standings\nregularseason = sim.simulations.regularseason\nseeding = sim.simulations.seeding\nplayoffs = sim.simulations.playoffs\n```\n\nOr returned as copies using class methods:\n```python\nstandings = sim.standings()\nregularseason = sim.regularseason()\nseeding = sim.seeding()\nplayoffs = sim.playoffs()\n```\n\nBy default, all of the aggregated dataframes use MultiIndexes incorporating the simulation number and the within-simulation row number. The class methods include an option to extract the \"Simulation\" portion of the MultiIndex into its own column:\n```python\nstandings_reindexed = sim.standings(reindex=True)\n```\n\nYou can also entirely disable the generation of aggregated statistics, in which case the results are stored as a list of Simulation objects:\n```python\nsim = nfl.Simulate(season=2018, n_sims=100000).run(combine=False)\nfor simulation in sim.simulations.values:\n rankings = simulation.rankings\n standings = simulation.standings\n regularseason = simulation.regularseason\n seeding = simulation.seeding\n playoffs = simulation.playoffs\n```\n\n[//]: #\n [PyPI]: \n [SRS]: \n [FPI]: \n [DVOA]: \n [Sagarin]: \n [tiebreaking procedures]: \n [3 points by default]: \n [13 points by default]: ", "description_content_type": "text/markdown", "docs_url": null, "download_url": "https://github.com/dmparker0/nflsim/archive/v1.1.1.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/dmparker0/nflsim/", "keywords": "NFL,football,sports,simulation,statistics", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "nflsim", "package_url": "https://pypi.org/project/nflsim/", "platform": "", "project_url": "https://pypi.org/project/nflsim/", "project_urls": { "Download": "https://github.com/dmparker0/nflsim/archive/v1.1.1.tar.gz", "Homepage": "https://github.com/dmparker0/nflsim/" }, "release_url": "https://pypi.org/project/nflsim/1.1.1/", "requires_dist": null, "requires_python": "", "summary": "A tool for simulating the NFL regular season and playoffs", "version": "1.1.1" }, "last_serial": 4437504, "releases": { "0.0": [ { "comment_text": "", "digests": { "md5": "85a9f7b5d744bc65f98c29b85309d7fb", "sha256": "8c356c573f8d6016e8b5d2b1fb242ed1aa10fa65d2e1ee20b0dc389dba8deb84" }, "downloads": -1, "filename": "nflsim-0.0.tar.gz", "has_sig": false, "md5_digest": "85a9f7b5d744bc65f98c29b85309d7fb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11948, "upload_time": "2018-10-23T21:34:19", "url": "https://files.pythonhosted.org/packages/52/b9/6c959afe245f8cc418d326d60efc5670ba87499c5f3cb3166b6d7b8a0b69/nflsim-0.0.tar.gz" } ], "1.0": [ { "comment_text": "", "digests": { "md5": "098b0e580ef212e5f0e82463b0a10fbc", "sha256": "e7fc3248e5fc00d81cdab4242b8d7d31b9a3c484bb42b8c4d2e07f8e71fb178a" }, "downloads": -1, "filename": "nflsim-1.0.tar.gz", "has_sig": false, "md5_digest": "098b0e580ef212e5f0e82463b0a10fbc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12009, "upload_time": "2018-10-24T18:41:20", "url": "https://files.pythonhosted.org/packages/72/cd/1a08af555eb1d4081465ada927d8779ba06a6cd47163410f3df9f2330038/nflsim-1.0.tar.gz" } ], "1.1": [ { "comment_text": "", "digests": { "md5": "12acafe70cc2bafe73f80f5068be1291", "sha256": "193d75eecb1345aab79b83e4097322204b6eb9e94aecb35bed8e0b07aa853736" }, "downloads": -1, "filename": "nflsim-1.1.tar.gz", "has_sig": false, "md5_digest": "12acafe70cc2bafe73f80f5068be1291", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13281, "upload_time": "2018-10-30T20:50:42", "url": "https://files.pythonhosted.org/packages/ec/9f/5a141ea597a5ce59cfdcf5e46125ee5cbebcba0b963781829ceac58fc2cc/nflsim-1.1.tar.gz" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "7a231c6ead7e2f9547ce3b0f433b2283", "sha256": "cf6a692b1fc4eb9878f556e420b8197bd9ed5ea32cd4cad6b840af7fd0649670" }, "downloads": -1, "filename": "nflsim-1.1.1.tar.gz", "has_sig": false, "md5_digest": "7a231c6ead7e2f9547ce3b0f433b2283", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13157, "upload_time": "2018-10-31T16:42:11", "url": "https://files.pythonhosted.org/packages/58/0f/14da3fc71dea66efe47c82be0f00cfca8571ac36ecd666cd7c258cdf45f9/nflsim-1.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "7a231c6ead7e2f9547ce3b0f433b2283", "sha256": "cf6a692b1fc4eb9878f556e420b8197bd9ed5ea32cd4cad6b840af7fd0649670" }, "downloads": -1, "filename": "nflsim-1.1.1.tar.gz", "has_sig": false, "md5_digest": "7a231c6ead7e2f9547ce3b0f433b2283", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13157, "upload_time": "2018-10-31T16:42:11", "url": "https://files.pythonhosted.org/packages/58/0f/14da3fc71dea66efe47c82be0f00cfca8571ac36ecd666cd7c258cdf45f9/nflsim-1.1.1.tar.gz" } ] }