<jupyter_start><jupyter_text>Lotomania  Informações Como jogarA Lotomania é fácil de jogar e de ganhar: basta escolher 50 números e então concorrer a prêmios para acertos de 20, 19, 18, 17, 16, 15 ou nenhum número.Além da opção de marcar no volante, você ainda pode marcar menos que 50 números e deixar que o sistema complete o jogo para você; não marcar nada e deixar que o sistema escolha todos os números na Surpresinha e/ou concorrer com a mesma aposta por 2, 4 ou 8 concursos consecutivos com a Teimosinha. Outra opção é efetuar uma nova aposta com o sistema selecionando os outros 50 números não registrados no jogo original, através da Aposta-Espelho. ApostasO preço da aposta é único e custa apenas R\$ 1,50. SorteiosOs sorteios são realizados às terças-feiras e às sextas-feiras, às 20h. PremiaçãoO prêmio bruto corresponde a 45,3\% da arrecadação, já computado o adicional destinado ao Ministério do Esporte. Dessa porcentagem são distribuídos:- 45\% entre os acertadores dos 20 números sorteados - 1ª faixa;- 16\% entre os acertadores de 19 dos 20 números sorteados - 2ª faixa;- 10\% entre os acertadores de 18 dos 20 números sorteados - 3ª faixa;- 7\% entre os acertadores de 17 dos 20 números sorteados - 4ª faixa;- 7\% entre os acertadores de 16 dos 20 números sorteados - 5ª faixa;- 7\% entre os acertadores de 15 dos 20 números sorteados - 6ª faixa;- 8\% entre os acertadores de nenhum dos 20 números sorteados - 7ª faixa; Recebimento de prêmiosVocê pode receber seu prêmio em qualquer casa lotérica credenciada ou nas agências da Caixa. Caso o prêmio líquido seja superior a R\$ 1.332,78 (bruto de R\$ 1.903,98) o pagamento pode ser realizado somente nas agências da Caixa. Valores iguais ou acima de R\$ 10.000,00 são pagos após 2 dias de sua apresentação na agência da Caixa. AcumulaçãoNão existindo aposta premiada na 7ª faixa (0 acerto), o prêmio acumula para o concurso subsequente, na 1ª faixa de premiação (20 acertos). Nas demais faixas, o prêmio acumula na respectiva faixa de premiação. Tabela de preços|Aposta única|Valor em R\$||::|::||50 números|1,50|  Probabilidade|Faixas|Probabilidade||::|::||20 números|1/11.372.635||19 números|1/352.551||18 números|1/24.235||17 números|1/2.776||16 números|1/472||15 números|1/112||00 números|1/11.372.635|<jupyter_code>from matplotlib import pyplot as plt

# local
from lottery.strategy import LoteryStrategyBase

import pandas as pd
import numpy as np
import random<jupyter_output><empty_output><jupyter_text>Data Cleaning<jupyter_code>data_path = 'data/lotomania.txt'
df = pd.read_csv(
    data_path, names=['id', 'date'] + list(range(20))
).drop_duplicates().sort_values('id').reset_index(drop=True)
df.info() 
df.tail()<jupyter_output><empty_output><jupyter_text>Strategies<jupyter_code>class HighFrequencyStrategy(LoteryStrategyBase):
    """
    
    """
    def pick_numbers(self, df_train: pd.DataFrame=None) -> [int]:
        """
        Pick number for the next game
        
        :param df_train: dataframe with training data
        :return: list of numbers
        """
        if df_train is None:
            df_train = self.data[self.k_results]
            
        values_train = pd.Series(df_train.values.flatten())
        se_choice = values_train.value_counts()[:self.n_choices]
        
        return sorted(se_choice.index.values.tolist())
class LowFrequencyStrategy(LoteryStrategyBase):
    """
    
    """
    def pick_numbers(self, df_train: pd.DataFrame=None) -> [int]:
        """
        Pick number for the next game
        
        :param df_train: dataframe with training data
        :return: list of numbers
        """
        if df_train is None:
            df_train = self.data[self.k_results]
        
        values_train = pd.Series(df_train.values.flatten())
        se_choice = values_train.value_counts()[-self.n_choices:]
        
        return sorted(se_choice.index.values.tolist())
class MedianFrequencyStrategy(LoteryStrategyBase):
    def pick_numbers(self, df_train: pd.DataFrame=None) -> [int]:
        """
        Pick number for the next game
        
        :param df_train: dataframe with training data
        :return: list of numbers
        """
        if df_train is None:
            df_train = self.data[self.k_results]

        values_train = pd.Series(df_train.values.flatten())
        se_choice = values_train.value_counts()
        i = int((se_choice.size - self.n_choices)/2)
        se_choice = se_choice[i:i+self.n_choices]
        
        return sorted(se_choice.index.values.tolist())
class RandomStrategy(LoteryStrategyBase):
    def pick_numbers(self, df_train: pd.DataFrame=None) -> [int]:
        """
        Pick number for the next game
        
        :param df_train: dataframe with training data
        :return: list of numbers
        """
        return sorted(
            random.sample(range(self.vmin, self.vmax), self.n_choices)
        )
class PickedMatchedLast3Strategy(LoteryStrategyBase):
    def pick_numbers(self, df_train: pd.DataFrame=None) -> [int]:
        """
        Pick number for the next game
        
        :param df_train: dataframe with training data
        :return: list of numbers
        """
        if df_train is None:
            df_train = self.data[self.k_results]

        
        se_last = (
            df_train.tail(1).values.flatten().tolist(),
            df_train.tail(2).head(1).values.flatten().tolist(),
            df_train.tail(3).head(1).values.flatten().tolist()
        )

        # number frequency
        se_counts = pd.Series(df_train.values.flatten()).value_counts()
        se_counts.name = 'counts'
        df_counts = pd.DataFrame(se_counts).reset_index().rename(
            columns={'index': 'num'}
        )

        choice = se_counts[:50].index.tolist()

        # comparison between last 3 results
        matched = (
            set(se_last[0]) & set(se_last[1]),
            set(se_last[1]) & set(se_last[2]),
            set(se_last[0]) & set(se_last[2])
        )

        matched_joined = matched[0] | matched[1] | matched[2]

        choice = sorted(se_counts.index.tolist())

        # remove the matched number from the las 3 results
        for i in matched_joined:
            choice.pop(choice.index(i))

        return choice[-50:]
    
class MixSimpleStrategy(LoteryStrategyBase):
    strategies = None  # list
    
    def __init__(self, *args, strategies: list, **kwargs):
        # should be informed more than 1 strategy class
        assert len(strategies) > 1
        
        self.strategies = [
            s(*args, **kwargs) for s in strategies
        ]
        
        super().__init__(*args, **kwargs)
        
    def pick_numbers(self, df_train: pd.DataFrame=None) -> [int]:
        """
        Pick number for the next game
        
        :param df_train: dataframe with training data
        :return: list of numbers
        """
        results = [
            s.pick_numbers(df_train) for s in self.strategies
        ]
        
        final_numbers_raw = None
        
        for i in range(len(results)-1):
            for j in range(i, len(results)):
                nums = set(results[i]) & set(results[j])
                if final_numbers_raw is None:
                    final_numbers_raw = nums
                else:
                    final_numbers_raw = final_numbers_raw | nums
        
        final_numbers = list(final_numbers_raw)[:self.n_choices]
        
        # assert number of numbers picked
        assert len(final_numbers) == self.n_choices
        
        return final_numbers
lotomania_settings = dict(
    n_picked=20,
    n_choices=50,
    vmin=0,
    vmax=99,
    n_train=10,
    hits_to_win=(0, 15, 16, 17, 18, 19, 20)
)
n_samples = 1000
next_game_numbers = []<jupyter_output><empty_output><jupyter_text>Test High Frequency Strategy<jupyter_code>model = HighFrequencyStrategy(data=df.tail(n_samples), **lotomania_settings)

print('Win results: ', model.win_results())
print('Next choice:', model.pick_numbers())

model.stats()
model.plot_stats()<jupyter_output>Win results:  8/990 (0.8080808080808081 %)
Next choice: [0, 1, 2, 3, 4, 6, 8, 9, 15, 16, 17, 19, 21, 26, 29, 31, 35, 36, 37, 38, 39, 40, 41, 43, 44, 45, 47, 48, 49, 53, 54, 55, 58, 60, 63, 66, 67, 70, 73, 74, 76, 77, 78, 79, 80, 82, 85, 87, 92, 93]
          results
count  990.000000
mean     9.966667
std      2.030082
min      4.000000
25%      9.000000
50%     10.000000
75%     11.000000
max     16.000000<jupyter_text>Test Low Frequency Strategy<jupyter_code>model = LowFrequencyStrategy(data=df.tail(n_samples), **lotomania_settings)

print('Win results: ', model.win_results())
print('Next choice:', model.pick_numbers())

model.stats()
model.plot_stats()<jupyter_output>Win results:  14/990 (1.4141414141414141 %)
Next choice: [5, 7, 10, 11, 12, 13, 14, 18, 20, 22, 23, 24, 25, 27, 28, 30, 32, 33, 34, 42, 46, 50, 51, 52, 56, 57, 59, 61, 62, 64, 65, 68, 69, 71, 72, 75, 81, 83, 84, 86, 88, 89, 90, 91, 94, 95, 96, 97, 98, 99]
          results
count  990.000000
mean     9.902020
std      2.083567
min      3.000000
25%      8.000000
50%     10.000000
75%     11.000000
max     17.000000<jupyter_text>Test Median Frequency<jupyter_code>model = MedianFrequencyStrategy(data=df.tail(n_samples), **lotomania_settings)

print('Win results: ', model.win_results())
print('Next choice:', model.pick_numbers())

model.stats()
model.plot_stats()<jupyter_output>Win results:  11/990 (1.1111111111111112 %)
Next choice: [0, 1, 7, 9, 10, 11, 18, 19, 20, 21, 23, 24, 27, 28, 30, 35, 36, 37, 38, 39, 42, 44, 45, 46, 47, 48, 50, 53, 55, 57, 60, 63, 64, 65, 67, 68, 69, 74, 76, 78, 80, 81, 82, 83, 86, 90, 91, 92, 95, 97]
          results
count  990.000000
mean     9.922222
std      2.029363
min      3.000000
25%      9.000000
50%     10.000000
75%     11.000000
max     15.000000<jupyter_text>Test Picked Matched Last 3 Strategy<jupyter_code>model = PickedMatchedLast3Strategy(data=df.tail(n_samples), **lotomania_settings)

print('Win results: ', model.win_results())
print('Next choice:', model.pick_numbers())

model.stats()
model.plot_stats()<jupyter_output>Win results:  13/990 (1.3131313131313131 %)
Next choice: [42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 56, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 78, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 95, 96, 97, 98, 99]
          results
count  990.000000
mean     9.821212
std      1.974907
min      4.000000
25%      8.250000
50%     10.000000
75%     11.000000
max     16.000000<jupyter_text>Mix Simples Strategy<jupyter_code>model = MixSimpleStrategy(
    data=df.tail(n_samples), 
    strategies=[
        LowFrequencyStrategy, 
        MedianFrequencyStrategy, 
        PickedMatchedLast3Strategy
    ], **lotomania_settings
)

print('Win results: ', model.win_results())
print('Next choice:', model.pick_numbers())

model.stats()
model.plot_stats()<jupyter_output>Win results:  13/990 (1.3131313131313131 %)
Next choice: [0, 1, 5, 7, 9, 10, 11, 12, 13, 14, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 30, 32, 33, 34, 35, 36, 37, 38, 39, 42, 44, 45, 46, 47, 48, 50, 51, 52, 53, 55, 56, 57, 59, 60, 61, 62, 63, 64, 65, 67]
          results
count  990.000000
mean    10.011111
std      2.051628
min      3.000000
25%      9.000000
50%     10.000000
75%     11.000000
max     16.000000<jupyter_text>Random Strategy<jupyter_code>model = RandomStrategy(data=df.tail(n_samples), **lotomania_settings)

print('Win results: ', model.win_results())
print('Next choice:', model.pick_numbers())

model.stats()
model.plot_stats()<jupyter_output>Win results:  11/990 (1.1111111111111112 %)
Next choice: [2, 6, 10, 11, 12, 13, 16, 18, 19, 21, 23, 27, 28, 29, 31, 32, 36, 39, 41, 42, 43, 44, 45, 46, 47, 50, 51, 52, 56, 57, 59, 63, 64, 65, 68, 69, 70, 72, 74, 77, 82, 84, 85, 88, 89, 90, 93, 95, 97, 98]
          results
count  990.000000
mean     9.939394
std      2.002618
min      4.000000
25%      9.000000
50%     10.000000
75%     11.000000
max     17.000000
{'fraction_non_alphanumeric': 0.11713738232108639, 'fraction_numerical': 0.1105556944097309, 'mean_word_length': 2.9177545691906004, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 84, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '666400', 'license': 'MIT', 'n_tokens_mistral': 5314, 'n_tokens_neox': 4170, 'n_words': 1215, 'path': 'notebooks/br/Lotomania.ipynb', 'repo_name': 'xmnlab/lottery', 'size': '12003'}