how do print a data analysis summary table in python? - python
After testing pokers hands x amount of times, I need to print a table with the title of the hand (full house, flush, etc.), the number of times each of them occurred, the percentage of times they occurred, expected percentage, and difference between the two. It won't let me run it with more than 2 iterations.
Here is what I have:
def is_pair(hand):
Yes = 0
for card in hand:
count = 0
for i in hand:
if (card['value']) == (i['value']):
count += 1
if count == 2:
Yes = 1
if Yes == 0:
return False
else:
if is_full_house(hand) is True:
return False
elif is_2_pair(hand) is True:
return False
elif is_3_of_a_kind(hand) is True:
return False
elif is_4_of_a_kind(hand) is True:
return False
else:
return True
def is_2_pair(hand):
Yes = 0
for card in hand:
count = 0
for i in hand:
if card['value'] == i['value']:
count += 1
if count == 2:
Yes += 1
if Yes == 4:
if is_4_of_a_kind(hand) is True:
return False
elif is_full_house(hand) is True:
return False
else:
return True
else:
return False
def is_3_of_a_kind(hand):
Yes = 0
for card in hand:
count = 0
for i in hand:
if card['value'] == i['value']:
count += 1
if count == 3:
Yes = 1
if Yes == 0:
return False
else:
if is_full_house(hand) is True:
return False
else:
return True
def is_4_of_a_kind(hand):
Yes = 0
for card in hand:
count = 0
for i in hand:
if card['value'] == i['value']:
count += 1
if count == 4:
Yes = 1
if Yes == 0:
return False
else:
return True
def is_full_house(hand):
Yes = 0
if is_3_of_a_kind(hand) is True:
Yes += 1
else:
return False
if is_pair(hand) is True:
Yes += 1
else:
return False
if Yes == 2:
return True
else:
return False
def is_flush(hand):
Yes = 0
for card in hand:
count = 0
for i in hand:
if card['suit'] == i['suit']:
count += 1
if count == 5:
Yes = 1
if Yes == 0:
return False
else:
return True
def is_straight(hand):
list = []
for card in hand:
list.append(card['value'])
list.sort()
if is_pair(hand) is True:
return False
elif is_2_pair(hand) is True:
return False
elif is_3_of_a_kind(hand) is True:
return False
elif is_4_of_a_kind(hand) is True:
return False
elif is_full_house(hand) is True:
return False
elif list[4] - list [0] == 4:
return True
else:
return False
def is_high_card(hand):
if (is_pair(hand) is False) and (is_2_pair(hand) is False) and (is_3_of_a_kind(hand) is False) and (is_4_of_a_kind(hand) is False) and (is_flush(hand) is False) and (is_full_house(hand) is False) and (is_straight(hand) is False) and (is_straight_flush(hand) is False):
return True
else:
return False
def is_straight_flush(hand):
if (is_straight(hand) is True) and (is_flush(hand) is True):
return True
else:
return False
def main():
deck = build_deck()
shuffle(deck)
hand = deck[:5]
return hand
def tests():
hand = main()
if is_straight_flush(hand) is True:
return('Straight flush')
elif is_4_of_a_kind(hand) is True:
return('Four of a kind')
elif is_full_house(hand) is True:
return('Full house')
elif is_flush(hand) is True:
return('Flush')
elif is_straight(hand) is True:
return('Straight')
elif is_3_of_a_kind(hand) is True:
return('Three of a kind')
elif is_2_pair(hand) is True:
return('Two pairs')
elif is_pair(hand) is True:
return('One pair')
elif is_high_card(hand) is True:
return('High card')
def main2():
iterations = int(input("How many hands would you like to test? "))
hands = ['Straight flush', 'Four of a kind', 'Full house', 'Flush', 'Straight', 'Three of a kind', 'Two pair', 'One pair', 'High card']
sf_expected = round(40/2598960*100, 4)
fok_expected = round(624/2598960*100, 4)
fh_expected = round(3744/2598960*100, 4)
f_expected = round(5108/2598960*100, 4)
s_expected = round(10200/2598960*100, 4)
tok_expected = round(54912/2598960*100, 4)
tp_expected = round(123552/2598960*100, 4)
op_expected = round(1098240/2598960*100, 4)
hc_expected = round(1302540/2598960*100, 4)
sf_freq = 0
fok_freq = 0
fh_freq = 0
f_freq = 0
s_freq = 0
tok_freq = 0
tp_freq = 0
op_freq = 0
hc_freq = 0
for i in range(iterations):
tests()
if (tests() == 'Straight flush'):
sf_freq += 1
if (tests() == 'Four of a kind'):
fok_freq += 1
if (tests() == 'Full house'):
fh_freq += 1
if (tests() == 'Flush'):
f_freq += 1
if (tests() == 'Straight'):
s_freq += 1
if (tests() == 'Three of a kind'):
tok_freq += 1
if (tests() == 'Two pair'):
tp_freq += 1
if (tests() == 'One pair'):
op_freq += 1
if (tests() == 'High card'):
hc_freq += 1
occurences = [sf_freq, fok_freq, fh_freq, f_freq, s_freq, tok_freq, tp_freq, op_freq, hc_freq]
expected = [sf_expected, fok_expected, fh_expected, f_expected, s_expected, tok_expected, tp_expected, op_expected, hc_expected]
percent = [sf_freq/iterations * 100, fok_freq/iterations * 100, fh_freq/iterations * 100, f_freq/iterations * 100, s_freq/iterations * 100, tok_freq/iterations * 100, tp_freq/iterations * 100, op_freq/iterations * 100, hc_freq/iterations * 100]
difference = [sf_freq/iterations * 100 - sf_expected, fok_freq/iterations * 100 - fok_expected, fh_freq/iterations * 100 - fh_expected, f_freq/iterations * 100 - f_expected, s_freq/iterations * 100 - s_expected, tok_freq/iterations * 100 - tok_expected, tp_freq/iterations * 100 - tp_expected, op_freq/iterations * 100 - op_expected, hc_freq/iterations * 100 - hc_expected]
print("{:<15} {:<15} {:<15} {:<15} {:>15}".format('Hand', 'Occurences','Percent', 'Expected', 'Difference'))
all = [['Straight flush', sf_freq, sf_freq/iterations * 100, sf_expected, sf_freq/iterations * 100 - sf_expected],
['Four of a kind', fok_freq, fok_freq/iterations * 100, fok_expected, fok_freq/iterations * 100 - fok_expected],
['Full house', fh_freq, fh_freq/iterations * 100, fh_expected, fh_freq/iterations * 100 - fh_expected],
['Flush', f_freq, f_freq/iterations * 100, f_expected, f_freq/iterations * 100 - f_expected],
['Straight', s_freq, s_freq/iterations * 100, s_expected, s_freq/iterations * 100 - s_expected],
['Three of a kind', tok_freq, tok_freq/iterations * 100, tok_expected, tok_freq/iterations * 100 - tok_expected],
['Two pair', tp_freq, tp_freq/iterations * 100, tp_expected, tp_freq/iterations * 100 - tp_expected],
['One pair', op_freq, op_freq/iterations * 100, op_expected, op_freq/iterations * 100 - op_expected],
['High card', hc_freq, hc_freq/iterations * 100, hc_expected, hc_freq/iterations * 100 - hc_expected]]
for list in all:
hands, occurences, percent, expected, difference = list
print("{:<15} {:<15} {:<15} {:<15} {:>15}".format(hands, occurences, percent, expected, difference))
main2()
It's a little unclear why you aren't getting any output, which seems to be the implication of your question. Is your code raising an exception?
It looks to me like the problem is with results. This appears to be a standard Python list (containing a collection of integers). Calling something like results/iterations would normally result in something like TypeError: unsupported operand type(s) for /: 'list' and 'int'.
Lists are not intended to support operations that apply to all their elements, but it's also unclear that's what you intended to achieve with this. Your format string specifies that results/iterations * 100 should be rendered in a space 10 characters wide and centered.
I believe you perhaps wanted to iterate through the individual values of hands, results, and expected, producing a set of rows to form a table. In that case I propose the following in place of your second print statement:
for hand, freq, expectation in zip(hands, results, expected):
percent = 100 * freq / iterations
print(f"{hand:^10}{freq:^10}{percent:^10}{expectation:^10}{percent-expectation:^10}")
I have used the somewhat friendlier f-string formatting, but if you have python <3.6 feel free to revert.
In general, the pandas data analysis library is a good fit for this kind of problem, since you can simply put your data in a pandas DataFrame and print it. However I appreciate that you may want to do this in base Python.
While I'm at it, I fear you have another error. You haven't told us what tests() does, but it looks like instead of calling it once per iteration and processing the result you call it many times.
Let me help you tidy your code and make it more maintainable, fixing this issue in the process.
hands = ['Straight flush', 'Four of a kind', 'Full house', 'Flush', 'Straight', 'Three of a kind', 'Two pair', 'One pair', 'High card']
results = {hand: 0 for hand in hands}
denom = 2598960 / 100
expected = [int(40/denom), int(624/denom), int(3744/denom), int(5108/2598960*100), int(10200/denom), int(54912/denom), int(123552/denom), int(1098240/denom), int(1302540/denom)]
for i in range(iterations):
hand = tests()
results[hand] += 1
By using a dictionary to store the results and using the hand name as the key to look up the result for that hand we improve the code.
You would then use results.values() to retrieve the list of results you had before.
I have also put your repeated code into a variable. If you ever had to change it, you now only have to change it in one place, making mistakes much less likely.
Related
Mastermind Python coding
Ok I have a feeling that this is a simple simple issue but I have been staring at this code for about 10 hours now. The issue I am having is in mastermind is that once I get it to recognize that I have the correct colors in the right spot I can get it to display the right spots with X and the wrong spots with O. I need to be able to convert that so instead of X and O I need it to tell the user that he/she has 2 blacks and one white For example: The secret code is RGYB The user enters RGOY so then Python relays "You have 2 blacks(The R and G spots) and one 1 White (The Y because it's the right color just in the wrong index) As of right now I got it to display X for the right color in the right spot and anything else it is an O I will post what I have been working with now but today I am at my wit's end https://pastebin.com/HKK0T7bQ if correctColor != "XXXX": for i in range(4): if guess[i] == tempCode[i]: correctColor += "X" if guess[i] != tempCode[i] in tempCode: correctColor += "O" print (correctColor + "\n") if correctColor == "XXXX": if attempts == 1: print ("You think you are sweet because you got it right on the first try? Play me again!") else: print ("Well done... You needed " + str(attempts) + " attempts to guess.") game = False
A few comments X and O you use X and 0 to denote the success, it will be easier and faster to use a list or tuple or booleans for this, that way you can use sum() to count how many colors and locations were correct. Then whether you represent that with X and O or red and white pins is a matter for later compartmentalization Your game logic (guess input, input validation, do you want to continue, etc) is mixed with the comparison logic, so it would be best to separate the different functions of your program into different methods. This is an fineexample to introduce object oriented programming, but is so simple it doesn't need OO, but it can help. What you need is a method which takes a series of colours and compares it to another series of colours Standard library Python has a very extended standard library, so a lot of stuff you want to do probably already exists Correct colours to count the number of letters which occur in 2 strings, you can use collections.Counter guess = "RGOY " solution = "RGYB" a = collections.Counter(guess) b = collections.Counter(solution) a & b Counter({'G': 1, 'R': 1, 'Y': 1}) correct_colours = sum((a & b).values()) 3 So the user guessed 3 colours correctly Correct locations can be solved with an easy list comprehension [g == s for g, s in zip(guess, solution)] [True, True, False, False] sum(g == s for g, s in zip(guess, solution)) 2 so the used put 2 colours on the correct location
This is a MasterMind I made in Python. Hope you like it and it helped you! :) import random import time from tkinter import * def select_level(): global level level = level_selector.get() root.destroy() root = Tk() level_selector = Scale(root, from_=1, to=3, tickinterval=1) level_selector.set(0) level_selector.pack() Button(root, text="Select a difficulty level", command=select_level).pack() mainloop() cpc_1_digit = 0 cpc_2_digit = 0 cpc_3_digit = 0 cpc_4_digit = 0 p_1_digit = 0 p_2_digit = 0 p_3_digit = 0 p_4_digit = 0 correct_correct = 0 correct_wrong = 0 chances = 0 if level == 1: chances = 15 elif level == 2: chances = 10 else: chances = 7 cpc_1_digit = random.randint(0, 9) while cpc_2_digit == cpc_1_digit or cpc_2_digit == cpc_3_digit or cpc_2_digit == cpc_4_digit: cpc_2_digit = random.randint(0, 9) while cpc_3_digit == cpc_1_digit or cpc_3_digit == cpc_2_digit or cpc_3_digit == cpc_4_digit: cpc_3_digit = random.randint(0, 9) while cpc_4_digit == cpc_1_digit or cpc_4_digit == cpc_2_digit or cpc_4_digit == cpc_3_digit: cpc_4_digit = random.randint(0, 9) while chances > 0: correct_correct = 0 correct_wrong = 0 answer = input("Enter a four-digit number with different digits (e.g 1476): ") p_1_digit = int(answer[0]) p_2_digit = int(answer[1]) p_3_digit = int(answer[2]) p_4_digit = int(answer[3]) if p_1_digit == cpc_1_digit: correct_correct = int(correct_correct) + 1 elif p_1_digit == cpc_2_digit or p_1_digit == cpc_3_digit or p_1_digit == cpc_4_digit: correct_wrong = int(correct_wrong) + 1 else: pass if p_2_digit == cpc_2_digit: correct_correct = correct_correct + 1 elif p_2_digit == cpc_1_digit or p_2_digit == cpc_3_digit or p_2_digit == cpc_4_digit: correct_wrong = int(correct_wrong) + 1 else: pass if p_3_digit == cpc_3_digit: correct_correct = int(correct_correct) + 1 elif p_3_digit == cpc_1_digit or p_3_digit == cpc_2_digit or p_3_digit == cpc_4_digit: correct_wrong = int(correct_wrong) + 1 else: pass if p_4_digit == cpc_4_digit: correct_correct = int(correct_correct) + 1 elif p_4_digit == cpc_1_digit or p_4_digit == cpc_3_digit or p_4_digit == cpc_2_digit: correct_wrong = int(correct_wrong) + 1 else: pass print("") if int(correct_correct) == 4: print("Congratsulations! You found the computer's number!") break elif int(correct_wrong) > 0 or int(correct_correct) >= 1 and int(correct_correct) < 4: print("You got " + str(correct_correct) + " correct digit(s) in the correct place, and " + str(correct_wrong) + " correct digit(s) but in wrong place.") elif int(correct_correct) == 0 and int(correct_wrong) == 0: print("You didn't guess any number, try again!") else: raise Exception("CheckError: line 69, something went wrong with the comparings.") exit() print("") chances = chances - 1 if chances == 0: print("You lost... The secret number was " + str(cpc_1_digit) + str(cpc_2_digit) + str(cpc_3_digit) + str(cpc_4_digit) + ". Try again by rerunning the program.") time.sleep(4)
Simulations in Evolutionary Biology - too many loops?
At the moment, I managed to code, successfully, a simulation for a work that I need to do. However, I'm fairly new to python. And so, I'm now in the process of making the simulation more efficient. For instance: if random.random() < mm: z = numpy.random.choice(pat) if random.random() < 0.5: if random.random() < mut: if maleadult[z][0] == 0: malejuv[y][x][0] = 1 elif maleadult[z][0] == 1: malejuv[y][x][0] = 0 else: malejuv[y][x][0] = maleadult[z][0] else: if random.random() < mut: if femaleadult[z][0] == 0: malejuv[y][x][0] = 1 elif femaleadult[z][0] == 1: malejuv[y][x][0] = 0 else: malejuv[y][x][0] = femaleadult[z][0] if random.random() < 0.5: if random.random() < mut: if maleadult[z][1] == 0: malejuv[y][x][1] = 1 elif maleadult[z][1] == 1: malejuv[y][x][1] = 0 else: malejuv[y][x][1] = maleadult[z][1] else: if random.random() < mut: if femaleadult[z][1] == 0: malejuv[y][x][1] = 1 elif femaleadult[z][1] == 1: malejuv[y][x][1] = 0 else: malejuv[y][x][1] = femaleadult[z][0] where: mm - male dispersal, mf - female dispersal, mut - mutations, pat - patch, maleadult - adult male, femaleadult - adult female, malejuv - juvenile male, femalejuv - juvenile female. As you can see, the code is big. And this is only for males and when they disperse. The rest of the code is very similar. These are standard genetic and demographic processes - but I feel like this can be improved. I feel like these processes are simple enough, so maybe code as big as this is not necessary. Does anyone have any ideas to shorten this and, by consequence, making it more efficient?
Your example does not have any loops but it looks like it could be simplified by one: if random.random() < mm: z = numpy.random.choice(pat) for i in range(2): if random.random() < 0.5: if random.random() < mut: if maleadult[z][i] == 0: malejuv[y][x][i] = 1 elif maleadult[z][i] == 1: malejuv[y][x][i] = 0 else: malejuv[y][x][i] = maleadult[z][i] else: if random.random() < mut: if femaleadult[z][i] == 0: malejuv[y][x][i] = 1 elif femaleadult[z][i] == 1: malejuv[y][x][i] = 0 else: malejuv[y][x][i] = femaleadult[z][i] It is also possible to pass a mutable object as reference to a function which can modify it, which allows further reduction of almost redundant code. I've added some data to test it: #!python3 #coding=utf-8 import random maleadult = [[["male adult"], ["another male adult"], ]] femaleadult = [[["female adult"], ["another female adult"], ]] malejuv = [[[["male juv"],["another male juv"]]]] mut = 0.5 mm = 1.0 x = 0 y = 0 z = 0 def some_logic(a, j): """ does something """ if random.random() < mut: if a[z][i] == 0: j[y][x][i] = 1 elif a[z][i] == 1: j[y][x][i] = 0 # added! else: j[y][x][i] = 0 else: j[y][x][i] = a[z][i] if random.random() < mm: z = 0 #numpy.random.choice(pat) for i in range(2): print(i) if random.random() < 0.5: some_logic(maleadult, malejuv) else: some_logic(femaleadult, malejuv) print(maleadult) print(malejuv) print(femaleadult)
Python does not start for loop
old = [[0 for x in range(3)] for y in range(10)] count =0 # check if the number has non-repeating digits def different(number): digit_list = [0] * 4 i = 0 while i: digit_list[i] = number%10 number /= 10 i += 1 for x in range(0,3): for y in range(x+1,3): if digit_list[x] == digit_list[y]: return False return True # save the tried numbers, plus and minus values # for prediction of the next number def save(number,plus,minus): global count old[count][0] = number old[count][1] = plus old[count][2] = minus count += 1 return # compare for plus values def get_plus(number1,number2): ret_value = 0 for x in range(0, 3): if number1 % 10 == number2 % 10: ret_value += 1 number1 /= 10 number2 /= 10 return ret_value # compare for minus values def get_minus(number1,number2): temp = [[0]*4 for i in range(2)] ret_value = 0 for x in range(0,3): temp[0][x] = number1 % 10 temp[0][x] = number2 % 10 number1 /= 10 number2 /= 10 for x in range(0,3): for y in range(0,3): if x != y: if temp[0][x] == temp[1][y]: ret_value += 1 return ret_value # compare the number to be asked with the numbers in the array def control(number): for x in range(0,count-1): if get_plus(old[x][0],number) != old[x][1]: return False if get_minus(old[x][0],number) != old[x][2]: return False return True def main(): flag = False print('1023 ??') plus = input('plus ?') minus = input('minus ?') save(1023, plus, minus) print('4567 ??') plus = input('plus ?') minus = input('minus ?') save(4567, plus, minus) for i in range(1024, 9876): if different(i): if control(i): print(i + ' ??') plus = input('plus ?') minus = input('minus ?') save(i, plus, minus) if plus == 4 and minus == 0: print('I WON !!!') flag = True break if not flag: print('False') return main() I am trying to make an AI for mindgame in python. But in this function it doesn't even start the for loop. Can anyone know why ?
The while loop in your different() function does nothing as while(0) will prevent the loop from running. Even if that would run, your different() function will always return false. At least in the last loop it will compare digit_list[3] == digit_list[3] as both loop range until 3. This is always true and the function will return false. Thus the code within your main loop will never be entered. def different(number): digit_list = [0] * 4 i = 0 while i: digit_list[i] = number%10 number /= 10 i += 1 for x in range(0,3): for y in range(x+1,3): if digit_list[x] == digit_list[y]: return False return True Try this one: import random def different(num): digits = [] while num >= 1: cur = num%10 if cur in digits: return False digits.append(cur) num = (num - cur) / 10 return True for i in range(0, 10000): rand = random.randrange(1000, 10000) if not different(rand): print(rand)
Getting the 983rd prime number instead of 1000th
I have just started coding, and I don't seem to be getting it quite right. I would like some feedback on my program. I am getting 7753 instead of 7919 primes = [] sk = [] # list for all None values def primtal(a): if ((2 ** a) - 2) % a == 0: return a t = 2 while len(primes) < 1001: kand = primtal(t) if kand == None: sk.append(kand) else: primt = kand primes.append(primt) t = t + 1 print primes[1000]
While loop not breaking under logical circumstances
I am making a code to simulate a dice and do other stuff, but there is a while loop which isn't breaking and I don't know why. import random import math #infinite loop while True: while True: a = 0 #input amount of dice att_die = raw_input('Attacking dice: ') def_die = raw_input('Defending dice: ') #att #if NaN if str(att_die).isdigit() == False: print('NaN') #if not NaN else: a += 1 #def #if NaN if str(def_die).isdigit() == False: print('NaN') #if not NaN else: a +=1 if a == 2: break if att_die >= def_die: no = def_die else: no = att_die print (no) x = 0 while x <= no: att_loss = 0 def_loss = 0 roll_att = random.randint(1,6) roll_def = random.randint(1,6) if roll_att <= roll_def: att_loss += 1 elif roll_att == roll_def: att_loss += 1 else: def_loss += 1 x += 1 print(x) print('Att: -' + str(att_loss) + '\nDef: -' + str(def_loss)) everything works up until the last while loop, which just continuously outputs the value of x increasing. Any help on how to fix this would be appreciated. Thanks in advance
no is a str, not an int. x is an int. In Python2, ints are always compare less than strs: In [187]: 9999 < '1' Out[187]: True The solution is to convert the str no into an int: no = int(no) In [188]: 9999 < int('1') Out[188]: False Note that in Python3, comparing an int with a str raises a TypeError, which will save many a programmer from this pitfall.
Here's a refactored version: import random import math DIE_SIDES = 6 WINNING_ATTACK_ODDS = 0.5 * (DIE_SIDES - 1) / DIE_SIDES def get_int(prompt): while True: try: return int(raw_input(prompt)) except ValueError: pass def attack(): """ Does the attacker win? """ return random.random() < WINNING_ATTACK_ODDS def main(): while True: att_die = get_int("Attacking dice: ") def_die = get_int("Defending dice: ") rolls = min(att_die, def_die) def_loss = sum(attack() for _ in range(rolls)) att_loss = rolls - def_loss print("Att: -{}\nDef: -{}".format(att_loss, def_loss)) if __name__=="__main__": main()