No meu país, há um jogo de loteria semanal onde os participantes selecionam 6 números de um conjunto de 37 e outro número de um conjunto de 7. Vamos nos concentrar na primeira parte do jogo e desconsiderar a seleção de um número adicional de um conjunto de 7. 7.
Quando se trata de loterias da forma k/N, onde k é o número de seleções desejadas (no nosso caso, 6) de um conjunto total de N números (no nosso caso, 37), uma questão comum é se cada um dos esses números têm chances iguais de fazer parte da combinação vencedora.
Vamos investigar esta questão.
Reuni estatísticas do site deles para 1.609 desenhos de 2009 a 2023.
Posteriormente, converti os dados do arquivo CSV em um objeto:
{ '09/09/2023': [13, 17, 24, 30, 35, 37], '07/09/2023': [7, 17, 19, 25, 35, 37], '05/09/2023': [2, 3, 5, 9, 36, 37], '02/09/2023': [4, 12, 22, 27, 30, 34], '29/08/2023': [6, 8, 15, 19, 26, 31], '26/08/2023': [6, 7, 14, 21, 25, 34], '22/08/2023': [2, 6, 10, 23, 24, 29], ... }
A chave no objeto corresponde à data do sorteio e o valor associado é uma matriz de números que surgiram como a combinação vencedora daquele sorteio específico.
Depois, criei um array contendo todos os números obtidos nos desenhos:
numbers = np.array(list(lotto.values())).flatten() [13, 17, 24, 30, 35, 37, 7, 17, 19, 25, 35, 37, 2, 3, 5, 9, 36, ...]
Em seguida, calculei a contagem de ocorrências (frequência) para cada valor do array:
count = np.bincount(numbers)[1:] [268, 256, 257, 242, 255, 273, 247, 277, 260, 267, 289, 294, 271, 239, 254, 255, 263, 243, 246, 271, 265, 254, 252, 243, 291, 271, 258, 264, 275, 258, 251, 244, 263, 256, 267, 251, 264]
Esses resultados indicam que o número 1 foi sorteado 268 vezes, o número 2 foi sorteado 256 vezes e assim por diante.
Parece que a distribuição dos números nos resultados da loteria é relativamente uniforme. Para confirmar isso ainda mais, podemos realizar um teste para validar a uniformidade da distribuição.
Para testar a equiprobabilidade dos N números individuais, você pode seguir esta abordagem:
Execute um teste estatístico, como um teste qui-quadrado, para determinar se o valor qui-quadrado calculado é estatisticamente significativo. Isto irá ajudá-lo a avaliar se a distribuição dos números é significativamente diferente do que seria esperado sob equiprobabilidade.
Se o valor qui-quadrado calculado não for estatisticamente significativo, isso sugere que os números estão razoavelmente distribuídos de maneira uniforme, apoiando a hipótese de equiprobabilidade. No entanto, se o valor X^2 for significativo, indicaria um afastamento da equiprobabilidade.
Vamos criar uma função para realizar o teste qui-quadrado de equiprobabilidade de números:
def chi2(data, size, expect, p_value = 0.05): pl = size * 1/expect df = expect - 1 x2_crit_1 = stats.chi2.ppf(p_value, df) x2_crit_2 = stats.chi2.ppf(1 - p_value, df) x2 = 0 for i in range(expect): x2 += ((data[i] - pl) ** 2)/pl accepted = x2_crit_1 < x2 < x2_crit_2 if x2_crit_1 < x2_crit_2 else x2_crit_2 < x2 < x2_crit_1 return x2, accepted
Esta função retorna a tupla composta pela estatística qui-quadrado e resulta que a equiprobabilidade aceita com a probabilidade 1 - 2 * p-value
, ou seja, valores extremos desta distribuição uniforme discreta possuem baixa probabilidade.
N = 37 chi2(count, len(numbers), N) (25.183136523720748, True)
Certamente, você pode usar a funcionalidade integrada da biblioteca SciPy para realizar o teste qui-quadrado de equiprobabilidade:
from scipy import stats chi2_statistic, p_value = stats.chisquare(count) (25.18313652372074, 0.9115057832606053)
Vamos explorar combinações desses números, começando com pares:
from itertools import combinations pairs = list(combinations(range(1, N), 2))
Seguindo esta etapa, construímos uma matriz 2D que rastreia as ocorrências desses pares:
pairs_count = np.zeros([N] * 2, dtype=int) for pair in pairs: for draw in lotto.values(): if pair[0] in draw and pair[1] in draw: pairs_count[pair[0]][pair[1]] += 1 pairs_count = pairs_count[1:, 1:]
Isso forma uma matriz triangular, pois leva em conta o fato de que os pares (a, b) e (b, a) são equivalentes, e contabilizamos apenas as ocorrências dos pares (a, b).
Minha função produz:
counts = pairs_count.flatten() counts = counts[counts > 0] chi2(counts, sum(counts), len(counts)) (589.2721893491138, True)
e o SciPy fornece:
chi2_statistic, p_value = stats.chisquare(counts) (589.2721893491124, 0.8698507423203673)
Que tal considerar trigêmeos:
comb3 = list(combinations(range(1, N), 3)) comb3_count = np.zeros([N] * 3, dtype=int) for comb in comb3: for draw in lotto.values(): contains = comb[0] in draw and comb[1] in draw and comb[2] in draw if contains: comb3_count[comb[0]][comb[1]][comb[2]] += 1 comb3_count = comb3_count[1:, 1:, 1:] counts = comb3_count.flatten() counts = counts[counts > 0] chi2(counts, sum(counts), len(counts)) (6457.575829383709, False)
Algo deu errado, possivelmente devido à alta dispersão da matriz. O valor do qui-quadrado fica abaixo do limite crítico inferior do qui-quadrado:
6457.575829383709 < 6840.049842653838
No entanto, ao usar o SciPy, o resultado é:
chi2_statistic, p_value = stats.chisquare(counts) (6457.575829383886, 0.9999997038479482)
Agora, vamos identificar o número que foi sorteado com mais frequência:
count.argmax() or list(count).index(max(count)) 11
Não vamos tirar conclusões precipitadas ainda. Podemos examinar como esse número evoluiu ao longo dos anos:
year_result = dict() for year in range(2009, 2024): new_dict = {k:v for (k,v) in lotto.items() if str(year) in k} year_result[year] = np.bincount(np.array(list(new_dict.values())).flatten())[1:].argmax() { 2009: 16, 2010: 10, 2011: 11, 2012: 24, 2013: 32, 2014: 34, 2015: 21, 2016: 25, 2017: 5, 2018: 10, 2019: 24, 2020: 11, 2021: 12, 2022: 14, 2023: 11 }
Ou, alternativamente, podemos analisar as mudanças cumulativas ao longo do tempo:
year_result = dict() arr = [] for year in range(2009, 2024): new_dict = {k:v for (k,v) in lotto.items() if str(year) in k} arr += list(np.array(list(new_dict.values())).flatten()) year_result['2009 - ' + str(year) if year > 2009 else str(year)] = np.bincount(arr)[1:].argmax() { '2009': 16, '2009 - 2010': 10, '2009 - 2011': 11, '2009 - 2012': 20, '2009 - 2013': 20, '2009 - 2014': 20, '2009 - 2015': 34, '2009 - 2016': 20, '2009 - 2017': 10, '2009 - 2018': 10, '2009 - 2019': 10, '2009 - 2020': 10, '2009 - 2021': 10, '2009 - 2022': 24, '2009 - 2023': 11 }
Por último, também podemos investigar se já ocorreram desenhos idênticos:
lotto_counts = {} for k, v in lotto.items(): v_str = str(v) if v_str in lotto_counts: lotto_counts[v_str] += [k] else: lotto_counts[v_str] = [k] result = {k: v for k, v in lotto_counts.items() if len(lotto_counts[k]) > 1} { '[13, 14, 26, 32, 33, 36]': ['16/10/2010', '21/09/2010'] }
É divertido notar que essas ocorrências aconteceram quase consecutivas.
Ao encerrarmos nossa jornada no mundo dos dados de loteria, temos sido uma jornada louca por números e probabilidades. Descobrimos algumas informações interessantes – desde pares e trigêmeos até identificar os números mais populares.
As loterias têm tudo a ver com imprevisibilidade, mas é divertido espiar por trás da cortina e explorar as peculiaridades desses jogos. Quer você seja um jogador ou apenas um observador curioso, o mundo dos números sempre traz uma ou duas surpresas na manga.