Return to JUNTO

JUNTO Practice: Probability, NCAA Basketball Pool

Discussed on July 28, 2020.

From "Twenty problems in probability":

There are 64 teams who play single elimination tournament, hence 6 rounds, and you have to predict all the winners in all 63 games. Your score is then computed as follows, 32 points for correctly predicting the final winner, 16 points for each correct finalist, and so on, down to 1 point for every correctly predicted winner for the first round. (The maximum number of points you can get is thus 192.) Knowing nothing about any team, you flip fair coins to decide every one of your 63 bets. Compute the expected number of points.

Please provide an answer and a justification.

Solutions

Click to see:

Oscar Martinez

I believe that the expected number of points is 31.5.

import numpy as np
from numba import jit


@jit
def play_tourney(teams=64):
    rounds = int(np.log(teams / 2) / np.log(2))

    bracket = [np.arange(teams)]
    remaining_teams = teams
    for i in range(rounds + 1):
        remaining_teams = remaining_teams // 2
        match_arr = np.random.randint(
            0, 2, (remaining_teams)
        ) + (np.arange(remaining_teams) * 2)
        match_arr = bracket[i][match_arr]
        bracket.append(match_arr)

    return bracket[1:]


vec_play_tourney = np.vectorize(play_tourney)


@jit
def score(results, bets, max_points=32):
    points = 0
    for i, r in enumerate(results):
        points += np.sum(r == bets[i]) * (
            max_points // r.shape[0]
        )

    return points


vec_score = np.vectorize(score)


@jit
def simulate(simulations, teams=64, max_points=32):
    points = 0
    for i in range(simulations):
        bets = play_tourney(teams)
        results = play_tourney(teams)
        points += score(results, bets, max_points)
    return points / simulations


print(simulate(10000))
31.2232

John Lekberg

I believe that the expected number of points is about 31.5.

I created a Python function that simulates the betting and took the mean of 1,000,000 samples:

import numpy as np

N_TEAM = 64
N_ROUND = 6

ROUND_POINTS = np.array(
    [
        2 ** n
        for n in range(N_ROUND)
        for _ in range(2 ** (N_ROUND - (n + 1)))
    ]
)


def random_outcome(N):
    """Sample the random variable 'the outcomes of the
    single-elimination tournament'.
    """
    teams = np.repeat([np.arange(N_TEAM)], N, axis=0)

    rounds = []
    for _ in range(N_ROUND):
        dim = list(teams.shape)
        dim[1] //= 2
        #
        group_offset = np.arange(dim[1]) * 2
        win_offset = np.random.randint(2, size=dim)
        win_index = group_offset + win_offset
        teams = np.take_along_axis(teams, win_index, axis=1)
        #
        rounds.append(teams)

    return np.concatenate(rounds, axis=1)


def random_total_points(N):
    """Sample the random variable 'the total number of points
    from randomly betting'.
    """
    bet = random_outcome(N)
    result = random_outcome(N)
    correct = bet == result
    total_points = correct @ ROUND_POINTS
    return total_points

random_total_points(1_000_000).mean()
31.519703

Daniel Bassett

I believe that the expected number of points is about 31.55.

import numpy as np


def simulate(n):
    i = 0
    results = [0 for i in range(n)]
    while i < len(results):
        round1 = np.random.choice(
            [0, 1], size=(32,), p=[63.0 / 64, 1.0 / 64]
        )
        round2 = np.random.choice(
            [0, 2], size=(16,), p=[31.0 / 32, 1.0 / 32]
        )
        round3 = np.random.choice(
            [0, 4], size=(8,), p=[15.0 / 16, 1.0 / 16]
        )
        round4 = np.random.choice(
            [0, 8], size=(4,), p=[7.0 / 8, 1.0 / 8]
        )
        round5 = np.random.choice(
            [0, 16], size=(2,), p=[3.0 / 4, 1.0 / 4]
        )
        round6 = np.random.choice([0, 32], size=(1,))

        tournament = [
            sum(round1),
            sum(round2),
            sum(round3),
            sum(round4),
            sum(round5),
            sum(round6),
        ]
        results[i] = sum(tournament)

        i += 1

    return sum(results) / len(results)


print(simulate(100000))
31.55746