Loading
Keunyoung Yoon

Data Engineer

Data Scientist

Data Analyst

Keunyoung Yoon

Data Engineer

Data Scientist

Data Analyst

Blog Post

Probability Simulation & Optimal Strategy for Users

11/26/2023 Portfolio

A. Simulated a probability-based item that follows the sequence below in Python

  1. Participate in the online store with participation rights (1 for 9,000 KRW).
  2. When a total of 50 people gather, each person is assigned a number, and the draw begins,
  3. Out of the 50 people, 10 people win a “reward” & earn “1 point”.
  4. Out of the 50 people, the remaining 40 people receive only “1 point” as they did not win.
  5. The 40 people who didn’t win can spend 500 KRW to make an additional selection.
    5-1) Choose one from the remaining 49 options, excluding your own number, and if the selected number matches the winning number, receive an additional 1 point (total of 2 points).
    5-2) If successful in 5-1), choose one from the remaining 48 options, excluding your own number and the previous matching number, and if the selected number matches the winning number, receive an additional 1 point (total of 3 points).

    5-10) If successful in 5-9), choose one from the remaining 40 options, excluding your own number and the previous matching numbers, and if the selected number matches the winning number, receive an additional 1 point (total of 11 points).

  6. If you fail at any stage from 5-1) to 5-9), you cannot proceed to the next stage.
  7. Participants can collect points obtained from unsuccessful attempts, and they can use these points to purchase items at the bottom of the page (1 / 2 / 5 / 10 / 30 points).

import random
import seaborn as sns
import matplotlib.pyplot as plt
#Selling price
cash = 9000

#In-game value of the rewards
product_price = {"winning":250000000, "1":45000000, "2":100000000, "5":300000000, "10":650000000, "30":20000000000}
total_games = int(1e4)                                              # Total number of games
total_people = int(1e3)                                             # Total number of users

point_list = [0 for _ in range(total_people)]                       # Store points acquired by users
paid_list = [0 for _ in range(total_people)]                        # Store the amount spent by users
price_list = [0 for _ in range(total_people)]                       # Store the value of products acquired by users
result_list = [[0, 0] for _ in range(total_people)]                 # Store the game results of users

for game in range(total_games):
    total_game_numbers = list(range(0, 49))
    npc_choice = random.sample(total_game_numbers, 10)              # Selected winning numbers in the game
    
    for user in range(total_people):
        user_cnt = 0
        user_game_numbers = total_game_numbers.copy()
        
        # Adjusting the probability of continuing the game based on the amount of spending
        # Most users make a purchase at least once, and the number of users making additional purchases after one round decreases significantly. 
        # Then, there is a gradual decrease in willingness to purchase, and in the high-spending user segment, there is very little resistance to additional spending. 
        # This has been implemented with approximate probabilities.
        if (paid_list[user] >= 100000):
            limit_prob = 0.90
        elif (paid_list[user] >= 50000) and (paid_list[user] < 100000):
            limit_prob = 0.95
        elif (paid_list[user] >= 9000) and (paid_list[user] < 50000):
            limit_prob = 0.95
        else:
            limit_prob = 0.3
        
        if random.random() >= limit_prob:                            # Randomly decide whether to play the game
            paid_list[user] += 9000                                  # Cost based on the user's first choice 
            user_choice = random.sample(user_game_numbers, 1)[0]     # User's first choice
            
            if user_choice in npc_choice:                            # Check if the user won
                price_list[user] += product_price["winning"]         # Receive the Rewards if the user wins
                point_list[user] += 1                                # Earn 1 point if the user wins
                result_list[user][0] += 1                            # Record the winning result
                
                continue
            else:
                point_list[user] += 1                                # Earn 1 point even if not winning
                user_game_numbers.remove(user_choice)
                
                if random.random() > limit_prob:                     # Case 1: Continue the game
                    stop_or_go = 1
                else:                                                # Case 2: Discontinue the game
                    stop_or_go = 0
                    
                while stop_or_go == 1:
                    paid_list[user] += 500                           # Cost for additional games
                    user_cnt += 1
                    
                    if user_cnt == 11:
                        break
                    
                    user_choice = random.sample(user_game_numbers, 1)[0]  # User's choice
                    
                    if user_choice in npc_choice:
                        point_list[user] += 1                        # Earn points
                        result_list[user][1] += 1                    # Increase the number of correct guesses
                        
                        if random.random() > limit_prob:             # Case 1: Winning the game and continuing
                            stop_or_go = 1
                        else:                                        # Case 2: Winning the game and not continuing
                            stop_or_go = 0
                    else:
                        stop_or_go = 0                               # When losing the game, cannot draw again
        else:
            continue
# Exchange for items with pt.s
product_list = [30, 10, 5, 2, 1]

for user in range(total_people):
    left_point = point_list[user]
    
    for product in product_list:
        products = left_point // product
        left_point = left_point % product

        price_list[user] += products * product_price[str(product)]

Final item value obtained by each user

sns.histplot(price_list, kde=True)
plt.show()

Final Spending Amounts by each user

sns.histplot(paid_list, kde=True)
plt.show()
price_list[user] / paid_list[user].       # The in-game currency value per 1 KRW

16006.339144215532

Utilized in the actual probability item configuration

By changing the item value, base purchase amount (9000 KRW), and additional selection purchase amount (500 KRW), I found a value for the in-game currency that is almost identical to what was previously sold. The probability item scheme itself is simple, but calculating the expected value is relatively complex, so I found Python implementation to be very helpful.

B. Examined user’s optimal strategies

Strategy 1: Participate in all games and do not make additional selections.
total_games = int(1e2)                                              # Total number of games
total_people = int(1e4)                                             # Total number of users

point_list = [0 for _ in range(total_people)]                       # Store points acquired by users
paid_list = [0 for _ in range(total_people)]                        # Store the amount spent by users
price_list = [0 for _ in range(total_people)]                       # Store the value of products acquired by users
result_list = [[0, 0] for _ in range(total_people)]                 # Store the game results of users

for game in range(total_games):
    total_game_numbers = list(range(0, 49))
    npc_choice = random.sample(total_game_numbers, 10)              # Selected winning numbers in the game
    
    for user in range(total_people):
        user_cnt = 0
        user_game_numbers = total_game_numbers.copy()
        
        # the probability of continuing the game
        limit_prob = 0
        
            if random.random() >= limit_prob:                        # Randomly decide whether to play the game
            paid_list[user] += 9000                                  # Cost based on the user's first choice 
            user_choice = random.sample(user_game_numbers, 1)[0]     # User's first choice
            
            if user_choice in npc_choice:                            # Check if the user won
                price_list[user] += product_price["winning"]         # Receive the Rewards if the user wins
                point_list[user] += 1                                # Earn 1 point if the user wins
                result_list[user][0] += 1                            # Record the winning result
                
                continue
            else:
                point_list[user] += 1                                # Earn 1 point even if not winning
                user_game_numbers.remove(user_choice)
        else:
            continue
product_list = [30, 10, 5, 2, 1]

for user in range(total_people):
    left_point = point_list[user]               
    
    for product in product_list:
        products = left_point // product
        left_point = left_point % product

        price_list[user] += products * product_price[str(product)]
sns.histplot(price_list, kde=True)
plt.show()
price_list[user] / paid_list[user]          # The in-game currency value per 1 KRW

12388.888888888889

Less efficient than the overall average.

The overall in-game currency value per 1 KRW was 16,006, but Strategy 1 is lower at 12,388.
*I ran overall simulation considering high-spending users (1,000 people, 10,000 tries each). However, for personal strategies, I assumed that most are low/medium spenders (1,000 people, 100 tries each). This makes direct comparison of overall efficiency difficult, requiring comparison by each strategy’s efficiency.

Strategy 2: Participate in all games and make an additional selection only once.
total_games = int(1e2)                                              # Total number of games
total_people = int(1e4)                                             # Total number of users

point_list = [0 for _ in range(total_people)]                       # Store points acquired by users
paid_list = [0 for _ in range(total_people)]                        # Store the amount spent by users
price_list = [0 for _ in range(total_people)]                       # Store the value of products acquired by users
result_list = [[0, 0] for _ in range(total_people)]                 # Store the game results of users

for game in range(total_games):
    total_game_numbers = list(range(0, 49))
    npc_choice = random.sample(total_game_numbers, 10)              # Selected winning numbers in the game
    
    for user in range(total_people):
        user_cnt = 0
        user_game_numbers = total_game_numbers.copy()
        
        # the probability of continuing the game
        limit_prob = 0
        
            if random.random() >= limit_prob:                        # Randomly decide whether to play the game
            paid_list[user] += 9000                                  # Cost based on the user's first choice 
            user_choice = random.sample(user_game_numbers, 1)[0]     # User's first choice
            
            if user_choice in npc_choice:                            # Check if the user won
                price_list[user] += product_price["winning"]         # Receive the Rewards if the user wins
                point_list[user] += 1                                # Earn 1 point if the user wins
                result_list[user][0] += 1                            # Record the winning result
                
                continue
            else:
                point_list[user] += 1                                # Earn 1 point even if not winning
                user_game_numbers.remove(user_choice)
                
                stop_or_go = 1
                    
                while stop_or_go == 1:
                    paid_list[user] += 500                           # Cost for additional games
                    user_choice = random.sample(user_game_numbers, 1)[0]  # User's Choice
                    user_cnt += 1
                    limit_game = 2                                   # Limit Game
                    
                    if user_cnt == limit_game:
                        break
                    
               if user_choice in npc_choice:
                        point_list[user] += 1                        # Earn points
                        result_list[user][1] += 1                    # Increase the number of correct guesses
                        
                        if random.random() > limit_prob:             # Case 1: Winning the game and continuing
                            stop_or_go = 1
                        else:                                        # Case 2: Winning the game and not continuing
                            stop_or_go = 0
                    else:
                        stop_or_go = 0                               # When losing the game, cannot draw again
        else:
            continue
product_list = [30, 10, 5, 2, 1]

for user in range(total_people):
    left_point = point_list[user]               
    
    for product in product_list:
        products = left_point // product
        left_point = left_point % product

        price_list[user] += products * product_price[str(product)]
sns.histplot(price_list, kde=True)
plt.show()
price_list[user] / paid_list[user]          # The in-game currency value per 1 KRW

13157.894736842105

Better than Strategy 1.

Strategy 2(efficiency of 13,157) was better than Strategy 1, which had an efficiency of 12,388.

Strategy 3: Participate in all games and make an additional selection only Twice.
total_games = int(1e2)                                              # Total number of games
total_people = int(1e4)                                             # Total number of users

point_list = [0 for _ in range(total_people)]                       # Store points acquired by users
paid_list = [0 for _ in range(total_people)]                        # Store the amount spent by users
price_list = [0 for _ in range(total_people)]                       # Store the value of products acquired by users
result_list = [[0, 0] for _ in range(total_people)]                 # Store the game results of users

for game in range(total_games):
    total_game_numbers = list(range(0, 49))
    npc_choice = random.sample(total_game_numbers, 10)              # Selected winning numbers in the game
    
    for user in range(total_people):
        user_cnt = 0
        user_game_numbers = total_game_numbers.copy()
        
        # the probability of continuing the game
        limit_prob = 0
        
            if random.random() >= limit_prob:                        # Randomly decide whether to play the game
            paid_list[user] += 9000                                  # Cost based on the user's first choice 
            user_choice = random.sample(user_game_numbers, 1)[0]     # User's first choice
            
            if user_choice in npc_choice:                            # Check if the user won
                price_list[user] += product_price["winning"]         # Receive the Rewards if the user wins
                point_list[user] += 1                                # Earn 1 point if the user wins
                result_list[user][0] += 1                            # Record the winning result
                
                continue
            else:
                point_list[user] += 1                                # Earn 1 point even if not winning
                user_game_numbers.remove(user_choice)
                
                stop_or_go = 1
                    
                while stop_or_go == 1:
                    paid_list[user] += 500                           # Cost for additional games
                    user_choice = random.sample(user_game_numbers, 1)[0]  # User's Choice
                    user_cnt += 1
                    limit_game = 3                                   # Limit Game
                          
               if user_cnt == limit_game:
                        break
                    
               if user_choice in npc_choice:
                        point_list[user] += 1                        # Earn points
                        result_list[user][1] += 1                    # Increase the number of correct guesses
                        
                        if random.random() > limit_prob:             # Case 1: Winning the game and continuing
                            stop_or_go = 1
                        else:                                        # Case 2: Winning the game and not continuing
                            stop_or_go = 0
                    else:
                        stop_or_go = 0                               # When losing the game, cannot draw again
        else:
            continue
product_list = [30, 10, 5, 2, 1]

for user in range(total_people):
    left_point = point_list[user]               
    
    for product in product_list:
        products = left_point // product
        left_point = left_point % product

        price_list[user] += products * product_price[str(product)]
sns.histplot(price_list, kde=True)
plt.show()
price_list[user] / paid_list[user]          # The in-game currency value per 1 KRW

14013.749338974088

Better than Strategy 1/2.

Strategy 3(efficiency of 14,013) was better than Strategy 1(efficiency of 12,388) and Strategy 2(efficiency of 13,157).

Strategy 4: Participate in all games and make additional choices as much as possible.
total_games = int(1e2)                                              # Total number of games
total_people = int(1e4)                                             # Total number of users

point_list = [0 for _ in range(total_people)]                       # Store points acquired by users
paid_list = [0 for _ in range(total_people)]                        # Store the amount spent by users
price_list = [0 for _ in range(total_people)]                       # Store the value of products acquired by users
result_list = [[0, 0] for _ in range(total_people)]                 # Store the game results of users

for game in range(total_games):
    total_game_numbers = list(range(0, 49))
    npc_choice = random.sample(total_game_numbers, 10)              # Selected winning numbers in the game
    
    for user in range(total_people):
        user_cnt = 0
        user_game_numbers = total_game_numbers.copy()
        
        # the probability of continuing the game
        limit_prob = 0
        
            if random.random() >= limit_prob:                        # Randomly decide whether to play the game
            paid_list[user] += 9000                                  # Cost based on the user's first choice 
            user_choice = random.sample(user_game_numbers, 1)[0]     # User's first choice
            
            if user_choice in npc_choice:                            # Check if the user won
                price_list[user] += product_price["winning"]         # Receive the Rewards if the user wins
                point_list[user] += 1                                # Earn 1 point if the user wins
                result_list[user][0] += 1                            # Record the winning result
                
                continue
            else:
                point_list[user] += 1                                # Earn 1 point even if not winning
                user_game_numbers.remove(user_choice)
                
                stop_or_go = 1
                    
                while stop_or_go == 1:
                    paid_list[user] += 500                           # Cost for additional games
                    user_choice = random.sample(user_game_numbers, 1)[0]  # User's Choice
                    user_cnt += 1
                    limit_game = 3                                   # Limit Game
                          
               if user_cnt == limit_game:
                        break
                    
               if user_choice in npc_choice:
                        point_list[user] += 1                        # Earn points
                        result_list[user][1] += 1                    # Increase the number of correct guesses
                        
                        if random.random() > limit_prob:             # Case 1: Winning the game and continuing
                            stop_or_go = 1
                        else:                                        # Case 2: Winning the game and not continuing
                            stop_or_go = 0
                    else:
                        stop_or_go = 0                               # When losing the game, cannot draw again
        else:
            continue
product_list = [30, 10, 5, 2, 1]

for user in range(total_people):
    left_point = point_list[user]               
    
    for product in product_list:
        products = left_point // product
        left_point = left_point % product

        price_list[user] += products * product_price[str(product)]
sns.histplot(price_list, kde=True)
plt.show()
price_list[user] / paid_list[user]          # The in-game currency value per 1 KRW

14062.5

Better than Strategy 1/2. Similar to Strategy 3.

Strategy 4(efficiency of 14,062) was better than Strategy 1(efficiency of 12,388), Strategy 2(efficiency of 13,157). But its efficiency was similar to Strategy 3(efficiency of 14,013).

Conclusion

It was difficult to clearly state how many additional choices would be advantageous, but it can be said that neither avoiding extra choices altogether like in Strategy 1 nor making just one additional choice like in Strategy 2 is an efficient option.