import%20marimo%0A%0A__generated_with%20%3D%20%220.18.4%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Utilities%20Module%20(%60pyrf.utilities%60)%0A%0A%20%20%20%20The%20utilities%20module%20provides%20helper%20functions%20for%20probability%20calculations%0A%20%20%20%20and%20data%20manipulation.%0A%0A%20%20%20%20%23%23%20Functions%0A%0A%20%20%20%20-%20%60sum_diagonals%60%3A%20Sum%20the%20diagonals%20of%20a%20PMF%20matrix%20to%20get%20goal%20difference%20probabilities%0A%20%20%20%20-%20%60calc_total_mass%60%3A%20Calculate%20total%20probability%20mass%20(should%20equal%201.0%20for%20valid%20PMF)%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20pyrf%20as%20rf%0A%0A%20%20%20%20%23%20Create%20a%20grid%20and%20distribution%20for%20examples%0A%20%20%20%20grid%20%3D%20rf.GoalGrid(n%3D6)%0A%20%20%20%20dist%20%3D%20rf.BivariatePoisson(lambda_home%3D1.5%2C%20lambda_away%3D1.2)%0A%20%20%20%20pmf%20%3D%20dist.pmf(grid)%0A%20%20%20%20return%20pmf%2C%20rf%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20%60sum_diagonals%60%0A%0A%20%20%20%20This%20function%20sums%20the%20probabilities%20along%20each%20diagonal%20of%20a%20PMF%20matrix.%0A%20%20%20%20Each%20diagonal%20corresponds%20to%20a%20specific%20goal%20difference%20(home%20-%20away).%0A%0A%20%20%20%20-%20Diagonal%200%3A%20Draws%20(0-0%2C%201-1%2C%202-2%2C%20...)%0A%20%20%20%20-%20Diagonal%20%2B1%3A%20Home%20wins%20by%201%20(1-0%2C%202-1%2C%203-2%2C%20...)%0A%20%20%20%20-%20Diagonal%20-1%3A%20Away%20wins%20by%201%20(0-1%2C%201-2%2C%202-3%2C%20...)%0A%0A%20%20%20%20This%20effectively%20converts%20a%20bivariate%20PMF%20into%20a%20univariate%20goal%20difference%20distribution.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(pmf%2C%20rf)%3A%0A%20%20%20%20%23%20Sum%20diagonals%20to%20get%20goal%20difference%20probabilities%0A%20%20%20%20goal_diff_probs%20%3D%20rf.sum_diagonals(pmf.to_numpy())%0A%20%20%20%20print(%22Goal%20difference%20probabilities%3A%22)%0A%20%20%20%20print(goal_diff_probs)%0A%20%20%20%20return%20(goal_diff_probs%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(goal_diff_probs%2C%20mo)%3A%0A%20%20%20%20%23%20Show%20as%20formatted%20table%0A%20%20%20%20mo.md(f%22%22%22%0A%20%20%20%20%23%23%23%20Key%20Probabilities%0A%0A%20%20%20%20%7C%20Outcome%20%7C%20Probability%20%7C%0A%20%20%20%20%7C%3A-------%3A%7C%3A-----------%3A%7C%0A%20%20%20%20%7C%20Home%20wins%20%7C%20%7Bgoal_diff_probs%5Bgoal_diff_probs.index%20%3E%200%5D.sum()%3A.1%25%7D%20%7C%0A%20%20%20%20%7C%20Draw%20%7C%20%7Bgoal_diff_probs%5B0%5D%3A.1%25%7D%20%7C%0A%20%20%20%20%7C%20Away%20wins%20%7C%20%7Bgoal_diff_probs%5Bgoal_diff_probs.index%20%3C%200%5D.sum()%3A.1%25%7D%20%7C%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20%60calc_total_mass%60%0A%0A%20%20%20%20Calculates%20the%20total%20probability%20mass%20of%20a%20DataFrame.%20For%20a%20valid%20PMF%2C%0A%20%20%20%20this%20should%20equal%201.0%20(or%20very%20close%20due%20to%20floating%20point%20precision).%0A%0A%20%20%20%20This%20is%20useful%20for%3A%0A%20%20%20%20-%20Validating%20that%20a%20PMF%20is%20properly%20normalized%0A%20%20%20%20-%20Calculating%20adjustment%20factors%20when%20redistributing%20probability%20mass%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(pmf%2C%20rf)%3A%0A%20%20%20%20total_mass%20%3D%20rf.utilities.calc_total_mass(pmf)%0A%20%20%20%20print(f%22Total%20probability%20mass%3A%20%7Btotal_mass%3A.10f%7D%22)%0A%20%20%20%20print(f%22Valid%20PMF%3A%20%7Babs(total_mass%20-%201.0)%20%3C%201e-6%7D%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Use%20Case%3A%20Probability%20Redistribution%0A%0A%20%20%20%20When%20adjusting%20a%20PMF%20(like%20in%20%60DixonColes%60)%2C%20%60calc_total_mass%60%20helps%0A%20%20%20%20calculate%20how%20much%20probability%20to%20add%20or%20remove%20from%20each%20region%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(pmf%2C%20rf)%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%0A%20%20%20%20%23%20Get%20mass%20on%20the%20main%20diagonal%20(draws)%0A%20%20%20%20n%20%3D%20pmf.shape%5B0%5D%0A%20%20%20%20diagonal_mask%20%3D%20np.eye(n%2C%20dtype%3Dbool)%0A%20%20%20%20diagonal_pmf%20%3D%20pmf.where(diagonal_mask)%0A%20%20%20%20draw_mass%20%3D%20rf.utilities.calc_total_mass(diagonal_pmf)%0A%0A%20%20%20%20print(f%22Probability%20mass%20on%20main%20diagonal%20(draws)%3A%20%7Bdraw_mass%3A.4f%7D%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
b4531f72e31c8c1343334ac35b274342