Probability calculation in python - python

My problem is: I have 12 players, with 3 of them being named A, B and C, respectively. 12 players are being divided into 2 groups, 6 people each. I need to calculate the probability of player A and B being in the same team, and player C being in thе eopposite one. Math is not my strongsuit, because im pretty sure this is not a hard thing to calculate, but i would be really grateful if you could help me with this one. Here is what i wrote so far:
import random
playersnumb = 12
players = list(range(12))
A = random.choice([x for x in range(12)])
B = random.choice([x for x in range(12) if x != A])
C = random.choice([x for x in range(12) if (x != A) and (x != B)])
random.shuffle(players)
team1 = (players[:6])
team2 = (players[6:])
if A in team1:
print("Player A is in team 1")
else:
print("Player A is in team 2")
if B in team1:
print("Player B is in team 1")
else:
print("Player B is in team 2")
if C in team1:
print("Player C is in team 1")
else:
print("Player C is in team 2")
Any help is appreciated.

I wrote a little bit based on your code. The idea is to loop multiple times over your test code, it is not 100% accurate, but i think good enough for you:
import random
def calculate(playercount: int = 12) -> bool:
players = list(range(playercount))
player_a = random.choice([x for x in range(playercount)])
player_b = random.choice([x for x in range(playercount) if x != player_a])
player_c = random.choice([x for x in range(playercount) if (x != player_a) and (x != player_b)])
random.shuffle(players)
team1 = (players[:playercount//2])
team2 = (players[playercount//2:])
# That are your "positive" events
return (player_a in team1 and player_b in team1 and player_c in team2) or\
(player_a in team2 and player_b in team2 and player_c in team1)
def calculate_all(runtimes: int = 100000) -> float:
counter = 0
# count all poyitive events
for i in range(runtimes):
if calculate():
counter += 1
# return how often they appeared, based on all tests
return counter / runtimes
print("The probability is about {} %".format(calculate_all() * 100))

The number of ways to fill 1 list of six total = 12!/(6! * 6!) comb(12,6)
The number of ways to fill a list of six (including A and B and not C) = 9!/(4! * 5!) comb(9, 4)
Also, want to find (not A and not B and C) = 9!/(5! * 4!) comb(9, 5)
>>> from math import comb
>>> comb(12, 6)
924
>>> comb(9, 4) + comb(9, 5)
252
>>> 252 / 924
0.2727272727272727

Related

probability of getting three of a kind by drawing 5 cards

so my goal is to try to simulate an actaul deck and draw five cards and check if there is a three of a kind. I have no problem making the deck and drawing five cards, the problem arises when i check for three of a kind
my code:
from random import shuffle, sample
from itertools import product
#generating deck
suits = ["s","d","h","c"]
values = ["1","2","3","4","5","6","7","8","9","10","11","12","13"]
deck = list(product(values,suits))
sim = 100000
three_of_a_kind = 0
for i in range(sim):
shuffle(deck)
#generating hand
hand = sample(deck,5)
#checking for three of a kind
if any(hand[0][0] == x[0] for x in hand):
three1 += 1
elif any(hand[1][0] == x[0] for x in hand):
three2 += 1
elif any(hand[2][0] == x[0] for x in hand):
three3 += 1
if three1 == 3 or three2 == 3 or three3 == 3:
three_of_a_kind += 1
prob_three = three_of_a_kind/sim
print(prob_three)
edit: my deck only had 12 cards and I changed it to 13 but my question has not changed
Using collections.Counter to count cards
# Counter(...) returns a dictionary of counts of card values
# Checking for count of 3 (card[0] is the card value in hand)
if any(v==3 for k,v in Counter(card[0] for cardin hand).items()):
three_of_a_kind += 1
Complete Code
from random import shuffle, sample
from itertools import product
from collections import Counter
#generating deck
suits = ["s","d","h","c"]
values = ["1","2","3","4","5","6","7","8","9","10","11","12","13"]
deck = list(product(values,suits))
sim = 100000
three_of_a_kind = 0
for i in range(sim):
shuffle(deck)
#generating hand
hand = sample(deck,5)
# Check for 3 of a kind by checking for 3 cards of same value
if any(v==3 for k,v in Counter(card[0] for card in hand).items()):
three_of_a_kind += 1
prob_three = three_of_a_kind/sim
print(f'{prob_three:.4%}')
Here is a little trick:
#checking for three of a kind
values = sorted(card[0] for card in hand)
if values.count(values[2]) == 3:
three_of_a_kind += 1 # three, but not four
If there are 3 equal values in a sorted list of length 5, it must look like one of these possibilities:
C C C x y
x C C C y
x y C C C
In each case the middle card value C = values[2] is the value we need to count.
For more general solutions see: collections.Counter
#checking for three of a kind
if 3 in collections.Counter(card[0] for card in hand).values():
three_of_a_kind += 1

How to create combinations with constrains in Python

I have a list of football players. Each player has three attributes: position (G, D, M, A), name and salary.
Position Name Salary
P Buffon 6
D Maldini 23
D Baresi 15
D Bergomi 7
C Kakà 33
C Gomez 18
A Ronaldo 52
A Vieri 44
...
I want to create all possible combinations of a football team which contains exactly 11 players. These are the constrains:
Players constrain: total elements = 11
Position constrain: P = 1, D = 4, C = 4, A = 2
Salary constrain: sum salary < 200
I have started researching and it looks to me that itertools could help me generate all possible teams given the constrains. But what is not clear to me is how to code the constrains.
subset = df[['position', 'name', 'salary']]
tuples = [tuple(x) for x in subset.values]
all_permutations = itertools.permutations(tuples)
for perm in all_permutations:
# constrains
The itertools library has a very nice function for iterating through combinations. You can get all combinations of 11 players, and then filter through those.
from collections import Counter
import itertools
def valid_team(team):
positions = []
salary = 0
for player in team:
(player_pos,_,player_salary)=player
positions.append(player_pos)
salary += player_salary
pos_count = Counter(positions)
return (
pos_count['P'] is 1 and
pos_count['D'] is 4 and
pos_count['C'] is 4 and
pos_count['A'] is 2 and
salary<200
)
for team in itertools.combinations(players,11):
if (valid_team(team)):
print("found valid team")
print(team)
else:
print("found invalid team")
It should be noted that there is lot of unnecessary processing in the above method, as you can select each position individually. Alternative implementation below.
players_sorted = {}
for player in players:
if player[0] not in players_sorted:
players_sorted[player[0]] = []
players_sorted[player[0]].append(player)
p_guys = itertools.combinations(players_sorted['P'],1)
d_guys = itertools.combinations(players_sorted['D'],4)
c_guys = itertools.combinations(players_sorted['C'],4)
a_guys = itertools.combinations(players_sorted['A'],2)
teams = itertools.product(p_guys,d_guys,c_guys,a_guys)
for team in teams:
team_players = []
for pos in team:
team_players.extend(pos)
if (valid_team(team_players)):
print("found valid team")
print(team)
else:
print("found invalid team")
print(team)
You can use simple recursion with a generator:
from collections import Counter
pos_c = {'P':1, 'D':4, 'C':4, 'A':2}
def teams(d, c = []):
if len(c) == 11:
yield c
else:
s, pos = sum(int(j) for *_, j in c), Counter([j for j, *_ in c])
for i in d:
if not c or (i not in c and s+int(i[-1]) < 200 and pos_c[i[0]] >= pos.get(i[0], 0)+1):
yield from teams(d, c+[i])

Program to Simulate 2 Coins Being Flipped at the Same Time

My assignment is to create a program that simulates 2 coins being tossed at the same time. If both heads, then Group A gets a point; if both tails then Group B gets a point. If the coins are different then the Prof gets a point. The program must take 2 inputs: number of games and number of tosses per game. Here are 2 separate sample runs to illustrate:
How many games? 1
How many coin tosses per game? 100
Game 0:
Group A: 25 (25.0%); Group B: 19 (19.0%); Prof: 56 (56.0%)
Wins: Group A=0 (0.0%); Group B=0 (0.0%); Prof=1 (100.0%)
How many games? 5
How many coin tosses per game? 10
Game 0:
Group A: 3 (30.0%); Group B: 1 (10.0%); Prof: 6 (60.0%)
Game 1:
Group A: 6 (60.0%); Group B: 1 (10.0%); Prof: 3 (30.0%)
Game 2:
Group A: 4 (40.0%); Group B: 1 (10.0%); Prof: 5 (50.0%)
Game 3:
Group A: 4 (40.0%); Group B: 1 (10.0%); Prof: 5 (50.0%)
Game 4:
Group A: 5 (50.0%); Group B: 3 (30.0%); Prof: 2 (20.0%)
Wins: Group A=2 (40.0%); Group B=0 (0.0%); Prof=3 (60.0%)
My code (albeit clunky) works for taking the inputs, simulating coin tosses, and calculating and displaying the number of points per group and the percent. My problem however, is in calculating and storing the number of wins across all of the games played. Here is my code as of now:
import random
def coinFlip():
games = input("How many games? ")
tosses = input("How many coin tosses per game? ")
for i in range(games):
gA = 0
gAW = 0
gB = 0
gBW = 0
prof = 0
profW = 0
for j in range(tosses):
flip1 = random.randint(0, 1)
flip2 = random.randint(0, 1)
if (flip1 == 0 and flip2 == 0):
gA += 1
elif (flip1 == 1 and flip2 == 1):
gB += 1
else:
prof += 1
gAper = ((gA * 1.0) / tosses) * 100
gBper = ((gB * 1.0) / tosses) * 100
profper = ((prof * 1.0) / tosses) * 100
if (gA > gB and gA > prof):
gAW += 1
elif (gB > gA and gB > prof):
gBW += 1
elif ( prof > gA and prof > gB):
profW += 1
gAWper = ((gAW * 1.0) / games) * 100
gBWper = ((gBW * 1.0) / games) * 100
profWper = ((profW * 1.0) / games) * 100
print "Game {}:".format(i)
print " Group A: {} ({}%); Group B: {} ({}%); Prof: {} ({}%)".format(gA, gAper, gB, gBper, prof, profper)
print "Wins: Group A = {} ({}%); Group B = {} ({}%); Prof: {} ({}%)".format(gAW, gAWper, gBW, gBWper, profW, profWper)
I'm thinking I should store the wins in a list, but that's where I'm lost.
The critical problem is that you have reset the long-term counts at the start of every game. Thus, nobody gets to record more than one win. This works great for my Monday-night Frisbee games, but is not effective for your assignment.
Return to your psuedo-code and see where the loops and initializations match up. Here's a code version:
def coinFlip():
# Set-up you do only once per program execution
games = input("How many games? ")
tosses = input("How many coin tosses per game? ")
games_won_A = 0
games_won_B = 0
games_won_prof = 0
for i in range(games):
# Set-up things you do once per game
tosses_won_A = 0
tosses_won_B = 0
tosses_won_prof = 0
for j in range(tosses):
# Things you do every toss
flip1 = random.randint(0, 1)
flip2 = random.randint(0, 1)
...
# Summary things you do every game
# ... such as compute percentages
# Summary things you do at the end of the program execution
# ... such as print the overall totals
Does that get you moving?
BTW< note that this becomes a lot shorter if you put the counters into a list. For instance, counting the winner of each flip becomes a single line:
win_count[flip1 + flip2] += 1
win_count can be a list of three elements, recording the wins for A, prof, and B, in that order.
This probably isn't what the OP was looking for, but in general generating random numbers with numpy can accomplish this quickly and simply.
import numpy as np
# get these from input or wherever
games = 5
tosses = 10
n_coins = 2
experiment = np.random.randint(2,size=(games, tosses, n_coins))
flip_results = experiment.sum(axis=2) # 0 means group A wins, 1 Prof, 2 group B
game_results = np.stack((flip_results == 0, flip_results == 1, flip_results == 2))
game_results = game_results.sum(axis=2)
total_results = game_results.sum(axis=1)
print(game_results, total_results)

can only concatenate list (not "str") to list - type error

I am working a a list updating program but when I run this code I get can only concatenate list (not "str") to list error. Here is my code:
A = 1
B = 2
C = 3
D = 4
E = 5
Acount = 1
Bcount = 1
Ccount = 1
Dcount = 1
Ecount = 1
ScoreA = 20
X = [A, B, C, D, E]
Y = [20, 40, 60, 80, 100]
Ave = input('Enter hours spent revising (1-5): ')
if Ave == '1':
Score = input('Enter test score: ')
Acount += 1
ScoreA = Y[0:1] + Score #Error occurs here
ScoreA = ScoreA / Acount
Y.insert(0, ScoreA)
Any help is appreciated, even it is only minor. If down voting please explain why so I can improve questions in the future.
The value ScoreA is being assigned a list splice. Then, you try to add "Score" to the list, but Score is a string. Therefore, you need to access the element by index in ScoreA and add it to Score, casted to an int:
Y = [20, 40, 60, 80, 100]
Score = input('Enter test score: ')
Acount += 1
ScoreA = Y[0:1][0] + int(Score) #Here, accessing the first value of Y, which is the only value
The problem is that Y[0:1] is a list:
In [95]: Y = [1,2,3,4,5]
In [96]: Y[0:1]
Out[96]: [1]
It seems that you are trying to add Score to the first element in Y, i.e. Y[0]. So I'd do this:
In [97]: Score = 5
In [98]: Y[0] += Score
In [99]: Y[0]
Out[99]: 6
There is another problem with your code, namely that input returns a string, not an int/float which you seem to want. Therefore, I'd recommend you change Score = input('Enter test score: ') to Score = float(input('Enter test score: '))

Producing a sorted football league table in Python

I have created a program which simulates an entire football season between teams. The user inputs the teams' names and their skill ratings. It then uses the Poisson distribution to compare their skill ratings and calculate the result between the two teams. After each match, the relevant lists are updated: the winning teams gains 3 points (so if it is the third team that has won then the value at index [2] increases by 3). I have a separate list for points, goals scored, goals conceded, games won, games drawn, and games lost (side note - is there a more efficient way of doing this?)
The problem I have comes at the end of the season: each team is outputted with their data in the order that the teams were originally input. This is done using the fact that a team's name in the 'names' list is the same index as their points in the 'points' list. So the issue is, if I order the 'points' list then they will be out of sync with their names. I hope this makes sense but here is an example output for a season:
Enter number of teams in league: 4
Enter team 1 name: a
Enter team 2 name: b
Enter team 3 name: c
Enter team 4 name: d
Enter a skill: 1
Enter b skill: 3
Enter c skill: 5
Enter d skill: 8
===========================================
a's home games:
===========================================
a 2 - 0 b
a 0 - 2 c
a 0 - 0 d
===========================================
b's home games:
===========================================
b 2 - 3 a
b 1 - 0 c
b 0 - 0 d
===========================================
c's home games:
===========================================
c 1 - 0 a
c 1 - 0 b
c 0 - 1 d
===========================================
d's home games:
===========================================
d 4 - 0 a
d 2 - 0 b
d 0 - 0 c
Final table:
a Skill: 1 Points: 7 For: 5 Against: 9 Goal difference: -4 Wins: 2 Draws: 1 Losses: 3
b Skill: 3 Points: 4 For: 3 Against: 8 Goal difference: -5 Wins: 1 Draws: 1 Losses: 4
c Skill: 5 Points: 10 For: 4 Against: 2 Goal difference: 2 Wins: 3 Draws: 1 Losses: 2
d Skill: 8 Points: 12 For: 7 Against: 0 Goal difference: 7 Wins: 3 Draws: 3 Losses: 0
[4, 7, 10, 12]
So what I would now like to do is to be able to print a final league table in descending points order, rather than the way it prints now just in index order.
Sorry if this is poorly worded - the code for my program might be more useful so here it is:
import math
import random
#Lambda value in Poisson distribution for higher rated team
lambOne = 1.148698355
#Lambda value for lower rated team
lambTwo = 0.8705505633
#Poisson distribution calculating goals scored by the home team
def homeMatch(homeRating,awayRating):
global lambOne
global x
global y
if x == y:
raise ValueError
else:
lamb = lambOne**(int(homeRating)-int(awayRating))
homeScore = 0
z = random.random()
while z > 0:
z = z - ((lamb**homeScore * math.exp(lamb * -1))/(math.factorial(homeScore)))
homeScore += 1
return (homeScore-1)
#Poisson distribution calculating goals scored by away team
def awayMatch(homeRating,awayRating):
global lambTwo
global x
global y
#This check is to stop a team playing itself
if x == y:
raise ValueError
else:
lamb = lambTwo**(int(homeRating)-int(awayRating))
awayScore = 0
z = random.random()
while z > 0:
z = z - ((lamb**awayScore * math.exp(lamb * -1))/(math.factorial(awayScore)))
awayScore += 1
return (awayScore-1)
#Selecting number of teams in league
leagueSize = int(input("Enter number of teams in league: "))
#Initialising empty lists
teamNames = []
teamSkill = []
teamPoints = []
teamFor = []
teamAgainst = []
teamWins = []
teamDraws = []
teamLosses = []
#Populating lists with number of zeroes equal to the number of teams (one zero for each)
for x in range(leagueSize):
teamPoints += [0]
teamFor += [0]
teamAgainst += [0]
teamWins += [0]
teamDraws += [0]
teamLosses += [0]
#Entering names and skill ratings for each team
for i in range(leagueSize):
teamNames += [input("Enter team "+str(i+1)+" name: ")]
for j in range(leagueSize):
teamSkill += [input("Enter "+teamNames[j]+" skill: ")]
#Initialising variables
homeScore = 0
awayScore = 0
#The season begins - each team plays all of its home games in one go
for x in range(leagueSize):
#input("Press enter to continue ")
print("===========================================")
print(teamNames[x]+"'s home games: ")
print("===========================================\n")
for y in range(leagueSize):
error = 0
try:
homeScore = homeMatch(teamSkill[x],teamSkill[y])
#Skipping a game to stop a team playing itself
except ValueError:
pass
error += 1
try:
awayScore = awayMatch(teamSkill[x],teamSkill[y])
except ValueError:
pass
if error == 0:
#Updating lists
print(teamNames[x],homeScore,"-",awayScore,teamNames[y],"\n")
teamFor[x] += homeScore
teamFor[y] += awayScore
teamAgainst[x] += awayScore
teamAgainst[y] += homeScore
if homeScore > awayScore:
teamWins[x] += 1
teamLosses[y] += 1
teamPoints[x] += 3
elif homeScore == awayScore:
teamDraws[x] += 1
teamDraws[y] += 1
teamPoints[x] += 1
teamPoints[y] += 1
else:
teamWins[y] += 1
teamLosses[x] += 1
teamPoints[y] += 3
else:
pass
#Printing table (unsorted)
print("Final table: ")
for x in range(leagueSize):
#Lots of formatting
print(teamNames[x]+(15-len(teamNames[x]))*" "+" Skill: "+str(teamSkill[x])+(5-len(str(teamSkill[x])))*" "+" Points: "+str(teamPoints[x])+(5-len(str(teamPoints[x])))*" "+" For: "+str(teamFor[x])+(5-len(str(teamFor[x])))*" "+" Against: "+str(teamAgainst[x])+(5-len(str(teamPoints[x])))*" "+" Goal difference: "+str(teamFor[x]-teamAgainst[x])+(5-len(str(teamFor[x]-teamAgainst[x])))*" "+" Wins: "+str(teamWins[x])+(5-len(str(teamWins[x])))*" "+" Draws: "+str(teamDraws[x])+(5-len(str(teamDraws[x])))*" "+" Losses: "+str(teamLosses[x])+(5-len(str(teamLosses[x])))*" ")
teamPoints.sort()
print(teamPoints)
Sorry that this is very long and likely poorly worded and inefficient but I hope someone will be able to help me! Thank you very much :)
While your current approach is (barely) workable, it makes it very difficult to (for example) change the information you want to store about each team. You might consider defining a Team class instead, each instance of which stores all the information about a specific team.
class Team:
def __init__(self, name, skill):
self.name = name
self.skill = skill
self.points = self.goals_for = self.goals_against = \
self.wins = self.draws = self.losses = 0
This lets you create a new team object by passing a name and a skill level, in this way:
t1 = Team("Bradford City", 3)
t1 now has attributes name and skill with the given values, as well as a number of others (points, goals_for, and so on) whose values are all zero.
Then you can initialise the league quite easily:
league_size = 4
teams = []
for _ in range(league_size):
teams.append(Team(input("Name of team "+str(_)+": "),
int(input("Team "+str(_)+"'s skill level: ")))
Then to print the skill level of each team you can loop over the list:
for team in teams:
print(team.name, team.skill)
I hope this gives you some idea how your approach can be simplified. Your functions to play the matches can also take teams as arguments now, and modify the team objects directly according to the computed outcomes.
To get to the answer you want, once you have a list of teams you can print them out sorted by the number of points they hold quite easily:
for team in sorted(teams, key=lambda t: t.points):
print(team.name, team.skill, team.points, ...)
As far as I can see, none of your global declarations were necessary (if a name isn't defined locally Python will look for a global name to satisfy a reference). Besides which, inputs to a function should usually be passed as arguments, it's rather bad practice just to grab things from the environment!
I hope this is sufficient for you to rework your program to be more tractable. As a beginner I'd say you have done extremely well to get this far. The next steps are going to be exciting for you!
Added later: Your all-play-all could be easier to program as a result:
for home in teams:
for away in teams:
if home is away: # Teams don't play themselves
continue
play_match(home, away)
The play_match function would simulate the match and adjust each team's statistics. Of course you could simulate the away matches with another line reading
play_match(away, home)
though I'm not sure your algorithm is symmetrical for that.

Categories

Resources