Skip to main content

Poker Analysis using Python (numpy and pandas)

In this I did an analysis on poker. I made my own dataset by randomly selecting 7 cards from the dataset. It does not gives the actual results. It is more of a simulation of actual data.


I have used jupyter-notebook for this you can use any IDE according to your liking.

Start by importing the modules.

import pandas as pd
import numpy as np
import random
import time


Then I created a function calculate_hand which takes hand as a list and returns a boolean list with the corresponding values [royal_flush, straight_flush, four_of_a_kind, full_house, flush, straight, three_of_a_kind, two_pairs, pair, highcard]. If the hand has three cards of same value three_of_a_kind will be True, also pair will be True because if a hand has three of a kind, it also has a pair. Highcard always return the high card.

ALL_CARDS_NUM = {'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, 'T': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14}
ALL_CARDS_NUM_TO_TEXT = {1:'A', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10:'T', 11:'J', 12:'Q', 13:'K', 14:'A'}
FACE_CARDS = {'T': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14}

def to_number(card):
    if card[0].isnumeric():
        return int(card[0])
    else:
        return FACE_CARDS[card[0]]
   
   
def is_straight(num):
    all_straights = []
    seqcount = np.zeros(7, dtype=np.int)
   
    for i in range(1,len(num)):
        if ALL_CARDS_NUM[num[i-1]] - ALL_CARDS_NUM[num[i]] == -1:
            seqcount[i] = seqcount[i-1] + 1 
        elif ALL_CARDS_NUM[num[i-1]] == ALL_CARDS_NUM[num[i]]:
            seqcount[i] = seqcount[i-1]

    for x in np.argwhere(seqcount >= 4):
        return (True, seqcount)
   
    try:
        if num[-1] == 'A' and seqcount[num.index('5')] >=3:
            return (True, seqcount)
    except:
        pass
   
    return (False, seqcount)


def count_cards(num):
    ptf = {}
    temp_count = np.zeros(13)
   
    for x in num:
        temp_count[ALL_CARDS_NUM[x]%13 - 1] += 1
   
    for x in np.argwhere(temp_count > 1):
        ptf[ALL_CARDS_NUM_TO_TEXT[x[0] + 1]] = int(temp_count[x[0]])
       
    return ptf

def count_suites(suite):
    suites_array = {'S': [],
                   'C': [],
                   'H': [],
                   'D': []}
       
    for i in range(len(suite)):
        suites_array[suite[i]].append(i)

    for key, value in suites_array.items():
        if len(value) >= 5:
            return value

    return []

def calculate_hand(temp_hand, show = False):
    hand = temp_hand.copy()
    hand.sort(key=to_number)
    num = []
    suite = []
   
    hand_value = {}
   
    for x in hand:       
        num.append(x[0])
        suite.append(x[1])
   
   
   
    #straight
    straight, seq = is_straight(num)
    pairs = count_cards(num)
    flushes = count_suites(suite)
   
    #straignt flush
    straight_flush = False
    straight_flush_sequence = []
   
    if straight and flushes:
        for i in range(len(flushes)-4):
            flush_seq = [num[z] for z in flushes[i:i+5]]
            temp, _ = is_straight(flush_seq)
           
            if temp:
                straight_flush = True
                straight_flush_sequence = flush_seq
   
    #royal flush
    royal_flush = False
   
    if straight_flush:
        if straight_flush_sequence[-1] == 'A':
            royal_flush = True
       
    #pairs
    pair_value = np.asarray([value for _,value in pairs.items()], dtype=np.int)

    #four of a kind
    four_of_a_kind = False
    if np.argwhere(pair_value >= 4).size != 0:
        four_of_a_kind = True
       
   
    #three of a kind
    three_of_a_kind = False
    if np.argwhere(pair_value >= 3).size != 0:
        three_of_a_kind = True

   
    #full house
    full_house = False
    if three_of_a_kind and np.argwhere(pair_value >= 2).size >= 2:
        full_house = True
       
    #flush
    flush = False
    if flushes:
        flush = True
   
    #two pairs
    two_pairs = False
   
    if np.argwhere(pair_value >= 2).size >= 2:
        two_pairs = True
       
    #pairs
    pair = bool(pairs)
   
    #high card
    highcard = num[-1]

    if show:
        print(num, suite)
        print("royal flush:\t\t",royal_flush)
        print("straight flush:\t\t", straight_flush)
        print("four of a kind:\t\t", four_of_a_kind)
        print("full house:\t\t", full_house)
        print("flush:\t\t\t", flush)
        print("straight:\t\t", straight)
        print("three of a kind:\t", three_of_a_kind)
        print("Two pairs:\t\t", two_pairs)
        print("Pair:\t\t\t", pair)
        print("High card: \t\t",highcard)
   
   
    return [royal_flush, straight_flush, four_of_a_kind, full_house, flush, straight, three_of_a_kind, two_pairs, pair, highcard]


The other functions here are the helping functions.

Now you can create your dataset:

card_num = ['A','2','3','4','5','6','7','8','9','T','J','Q','K']
suite = ['S','C','H','D']
main = []

def randCard():
    choosen_num = random.choice(card_num)
    choosen_suite = random.choice(suite)
   
    return str(choosen_num) + choosen_suite

start = time.time()

for i in range(1000000):
    temp = []
    for j in range(7):

        choosen_card = randCard()

        while (choosen_card in temp):
            choosen_card = randCard()

        temp.append(choosen_card)
       
    hand_val = calculate_hand(temp)
   
    try:
        top_val = hand_val.index(True)
    except:
        top_val = 9
   
    temp += hand_val
    temp.append(top_val)
   
    if i%100000 == 0:
        print("Time Elapsed",i,"=", time.time() - start)
   
    main.append(temp)

print("\n\nTotal Time Elapsed =", time.time() - start) 


The dataset is stored in the main variable now convert into a pandas dataframe.

x = pd.DataFrame(data=main, columns=["YC1", "YC2", "F1", "F2", "F3", "R", "T", "royal_flush", "straight_flush", "four_of_a_kind", "full_house", "flush", "straight", "three_of_a_kind", "two_pairs", "pair", "highcard", "top_val" ])

x.head()


Now you can either save your data set in csv format or create new dataset every time you decide to use this.

x.to_csv(file_name,index=False)
 
To read the csv file you can use read_csv function
 
x = pd.read_csv(file_name) 

Now we can start analysing the data. 
 
top_hand_value_dict = {
    0: "royal_flush", 
    1: "straight_flush", 
    2: "four_of_a_kind", 
    3: "full_house", 
    4: "flush", 
    5: "straight",
    6: "three_of_a_kind", 
    7: "two_pairs", 
    8: "pair", 
    9: "highcard" 
}

def calculate_hand_value(data, x1, x2):
    
    print("\nIndividuaized values\n")
    hands = data.loc[((data["YC1"] == x1) & (data["YC2"] == x2)) | ((data["YC1"] == x2) & (data["YC2"] == x1))]
    len_hand = len(hands)
    
    print("Length of the sample: ", len_hand, "\n")

    
    for i in range(9):
        perc_val = 100 * hands[top_hand_value_dict[i]].sum()/len_hand
        print(top_hand_value_dict[i] + ":\t", round( perc_val , 3))
    
    z = hands.loc[:, hands.columns[7:len(hands.columns)-1]].sum(axis = 1)
    print("\nNothing:\t\t" , 100 * len(z.loc[z == 0])/len(z) )
        
def calculate_top_values(data, x1, x2):
    
    print("\nTop Values:\n")
    hands = data.loc[((data["YC1"] == x1) & (data["YC2"] == x2)) | ((data["YC1"] == x2) & (data["YC2"] == x1))]
    len_hand = len(hands)
    
    print("Total number of rows:", len_hand)
    
    l = hands['top_val'].value_counts()
    
    for key, value in dict(l).items():
        print(top_hand_value_dict[key] + ":\t", round( (value/len_hand)*100, 3))
     
calculate_hand_value check the possibility of the value of the hand. x1 and x2 are the cards. 
calculate_top_values check the top value of the hand. x1 and x2 are the cards. 
calculate_hand_value(x, "8S", "8D")
calculate_top_values(x, "QH", "JS")

Use above functions to check outputs.
 
def hand_losing(data, YC1, YC2, delt_card):
    
    print("\nChances of loosing this hand: ")
    
    hand = [YC1, YC2] + delt_card
    
    len_delt_card = len(delt_card)
        
    delt_card_hands = data.loc[ data.iloc[:,0:7].isin(delt_card).sum(axis="columns") >= len_delt_card]

    if delt_card_hands.empty:
        print("Sorry no values present!!! Increase the rows database")
    else:
        
        len_hand = len(delt_card_hands)
    
        hand_val = calculate_hand(hand)

        try:
            top_val = hand_val.index(True)
        except:
            top_val = 9
            
        len_lost =  len(delt_card_hands.loc[data['top_val'] < top_val])
        print("Chances of losing by cards value: ", len_lost)
        
        hand_high_card = ALL_CARDS_NUM[hand_val[9]]

        len_lost_high_val = len(
            delt_card_hands.loc[
                (data['top_val'] == top_val) &
                (data['highcard'].apply(lambda i: ALL_CARDS_NUM[i]) > hand_high_card)
            ]
        )
        
        print("Chances of losing by highcard: ", len_lost_high_val)
        
        unpredicted = len(
            delt_card_hands.loc[
                (data['top_val'] == top_val) &
                (data['highcard'] == hand_val[9])
            ]
        )
        
        print("Unpredicted data: ", unpredicted)
        
        
        print("Chances of losing (w unpredicted): ",
              len_lost + len_lost_high_val, "/",len_hand)
        print("Percentage of losing (w unpredicted): ", 
              round(100 * (len_lost + len_lost_high_val)/len_hand,3))
        
        print("Chances of losing (w/o unpredicted): ", 
              len_lost + len_lost_high_val, "/",(len_hand - unpredicted))
        print("Percentage of losing (w/o unpredicted): ", 
              round(100 * (len_lost + len_lost_high_val)/(len_hand - unpredicted),3))
hand_losing gives the number of times your hand can loose given the dataset.
 
hand_losing(x, "8S", "8D", ["8C", "TS", "TH", "9S", "8H"])
 
You can change the number of cards in the list for turn,flop and river.
 
Hope you liked this. 
 

Comments

Popular posts from this blog

Social Influence: Some tips and tricks

In our previous posts, we have learnt about some of the techniques in Social Psychology. Now in this post I want to tell you about some techniques that you can use in real life to influence people or to protect yourself from being influence by other people and make rash decisions. Some of the tips are: People more likely to help you when you ask them to imagine or predict doing something. Telling some stranger your name first can also be helpful when asking a favour. One can say “Hello, I am ___ and I was wondering whether you do me a favour.” Talking with people is more helpful that talking at people when asking for something/favour. Engaging people in dialogues rather than a monologue. Now I would like to tell you about the most commonly used persuasion techniques. These techniques are: 1.       Foot-in-the-door technique 2.       Door-in-the-face technique 3.       Low-ball technique N...

Obedience to Authority.. Milgram experiment

Obedience is a form of social influence where an individual acts in response to a direct order from another individual, who is usually an authority figure. It is assumed that without such an order the person would not have acted in this way. But this obedience can be harmful in some situations. The most famous example of this can be the Holocaust in Nazi Germany. Do we believe that all of the people in Nazi Germany wanted to kill those six million European Jew? No, but they were bound and ordered by the authorities to do so. This obedience to authority figures is in our nature. This can happen to all of us.  In one of the famous experiment, the nurses were told by the doctor to give a certain medicine to the patients which the nurses didn't know about. Out of 22 nurses which participated 21 gave those medicines to the patients. Now let's talk about the Milgram experiment. It was a series of social psychology experiments conducted by Yale University psychologist Stanl...

Abilene paradox: Group think

According to Wikipedia: In the Abilene paradox, a group of people collectively decide on a course of action that is counter to the preferences of many or all of the individuals in the group. In simple words, Abilene paradox is when each member of a group is a against the popular choice of the group and mistakenly believe that opposing it will cause a problem. It is a major problem in a big organization as well as in real life. The term was introduced by management expert Jerry B. Harvey in his 1974 article "The Abilene Paradox: The Management of Agreement". It was named like this because one day he and his family were sitting outside playing and having fun. His father-in-law jokingly suggested taking a trip to Abilene which was 44 miles away for supper. They all agreed because everyone thought other person wanted to go. But it turns out that it was an awful trip and a waste of a perfect Sunday. So, whenever such situations occur he is always reminded of that trip to Abil...