使用Keras编写神经网络预测大乐透彩票,并利用历史数据回测

写在最前面

首先郑重声明,这个赚不了钱!赚不了钱!赚不了钱!重要的话说三遍!

纯粹出于兴趣和技术做了个小实验,指望这个赚钱不太可能鸭!emmm,但可能会让你赔钱赔的少一点?

image.png

转载请注明出处:https://blog.csdn.net/aaronjny/article/details/103276212

前言

以前从没买过彩票,前几天一时兴起,随机买了几注,然后兴致勃勃地等开奖。中奖序列出来后,比对一下,握草?!

果然没中~

image.png

然后我就在考虑机器选彩票的技术可行性。

首先,大乐透的中奖序列为35选5+12选2,每个球的选取是随机的,因此,想使用机器学习精准地预测出获奖序列是很难(或者说基本不可能)的。为什么这么说呢?我们可以类比于机器学习选股票。目前有很多机器学习应用在股票选择上的例子,并能够实现盈利。但机器学习选股和选彩票有几点显著差异:

  • 股票只需要预测涨幅(回归)或者简单预测涨跌(二分类),但大乐透中奖序列需要从 C 35 5 ∗ C 12 2 C_{35}^5*C_{12}^2 C355C122种(我不是资深彩民,就是兴致一起随手买了两注,所以对各种彩票的规则了解不是很清楚,不清楚是否还有隐含规则,这个是根据字面意思计算得来的)组合中预测出一种,难度完全不是一个量级的
  • 股票的涨跌存在各种因子、k线、舆情等参数用于评估和训练,但彩票的中奖序列是随机产生的,可供参考的可能仅有时间上的序列的概率分布。

所谓的概率分布指的是,假设彩票的中奖序列是完全随机产生的话,序列中每一个球在一次开奖过程中出现的概率应该是相同的(前区和后区要分开算),并且从时间序列上来看,连续的很多次开奖中,每一个球的出现与否也应当满足某种规律(当然,这是宏观上讲,实际上肯定不会严格满足,但能够体现某种趋势或倾向)。

而我们又不打算靠这个中大奖,目标不是预测出头等奖的开奖序列,而是尽可能多的预测出可能会出现在中奖序列中的球。听上去好像没什么区别,但在模型设计上能够体现出差异——如果是前者,我们的模型应该是一个分类器,从 C 35 5 ∗ C 12 2 C_{35}^5*C_{12}^2 C355C122种类别中预测出其中一个,但考虑数据集规模和概率问题,根本不现实;而后者,我们则设计一个多输入、多输出的模型,输入是七个球的时间序列,输出是每个位置出现某个球的概率,这样就靠谱的多~emmm,我们不求赚钱,少输点就行~!

image.png

行嘛,想了想好像没什么问题,那就开搞?于是,就有了这篇文章。

一、获取数据

想训练个模型的话,第一步肯定是获取数据啦。

我在网上找了一下,很快从[江苏体彩网](https://www.js-lottery.com/Pla 
yZone/lottoData.html)找到了历史开奖记录,可以直接下载,文件格式为csv。

这就很舒服啦,不用写爬虫到处一点点爬了。把文件下载下来看一下,数据是以这种形式组织的:

image.png

很明显,最前面是期号,然后是前区的五个号码,最后是后区的两个号码。

ok,下面让我们来写一个下载数据集的脚本,以便于我们对数据进行更新:

# -*- coding: utf-8 -*-
# @File  : update_data.py
# @Author: AaronJny
# @Date  : 2019/10/29
# @Desc  :
import requests
import settings

print('开始尝试从 {} 获取最新的大乐透数据...'.format(settings.LOTTO_DOWNLOAD_URL))
try:
    resp = requests.get(settings.LOTTO_DOWNLOAD_URL)
    if resp.status_code == 200:
        # 解析数据,查看数据集中最新的数据期数
        lines = resp.content.decode('utf-8').split('\n')
        index = lines[0].replace('"', '').split(',')[0]
        print('获取成功!开始更新文件...')
        with open(settings.DATASET_PATH, 'wb') as f:
            f.write(resp.content)
        print('完成!当前最新期数为{}期,请确认期数是否正确!'.format(index))
    else:
        raise Exception('获取数据失败!')
except Exception as e:
    print(e)

我把一些常量提取出来了,放到了settings.py里,需要对照的话请看:

# -*- coding: utf-8 -*-
# @File  : settings.py
# @Author: AaronJny
# @Date  : 2019/10/29
# @Desc  :

# 训练epochs数量
EPOCHS = 60
# 训练批大小
BATCH_SIZE = 128
# 输入的连续时间序列长度
MAX_STEPS = 256
# 前区号码种类数
FRONT_VOCAB_SIZE = 35
# 后区号码种类数
BACK_VOCAB_SIZE = 12
# dropout随机失活比例
DROPOUT_RATE = 0.5
# 长短期记忆网络单元数
LSTM_UNITS = 64
# 前区需要选择的号码数量
FRONT_SIZE = 5
# 后区需要选择的号码数量
BACK_SIZE = 2
# 保存训练好的参数的路径
CHECKPOINTS_PATH = 'checkpoints'
# 预测下期号码时使用的训练好的模型参数的路径,默认使用完整数据集训练出的模型
PREDICT_MODEL_PATH = '{}/model_checkpoint_x'.format(CHECKPOINTS_PATH)
# 预测的时候,预测几注彩票,默认5注
PREDICT_NUM = 5
# 数据集路径
DATASET_PATH = 'lotto.csv'
# 数据集下载地址
LOTTO_DOWNLOAD_URL = 'https://www.js-lottery.com/PlayZone/downLottoData.html'
# 大乐透中奖及奖金规则(没有考虑浮动情况,税前)
AWARD_RULES = {
   
    (5, 2): 10000000,
    (5, 1): 800691,
    (5, 0): 10000,
    (4, 2): 3000,
    (4, 1): 300,
    (3, 2): 200,
    (4, 0): 100,
    (3, 1): 15,
    (2, 2): 15,
    (3, 0): 5,
    (2, 1): 5,
    (1, 2): 5,
    (0, 2): 5
}

我们尝试运行一下,看看效果:

image.png

很好,没有问题。

二、处理数据

虽然数据已经获取到了,但显然,这个数据无法直接应用于训练。我们需要对数据做一下简单的处理。

现在,我们为中奖序列中的数字(或者说球)编一下号,从前往后它们的编号分别为1到7,其中1-5是前区的5个球,6-7是后区的2个球。

好的,我们现在先考虑另外一个问题,假如我们有近一年以来的气温数据,需要预测明天的气温,应该怎么做?

你可能会脱口而出,用循环神经网络做序列的预测。假设按顺序给这近一年来的气温分别编号为1-365,其中t1表示第一天的气温,t365表示今天的气温。气温的变化应该是有规律的(一般情况下),我们想让机器来学习这种规律。我们选定一个合适的时间长度,比如30天,然后将这30天的连续数据作为输入(x),将接下来一天的气温数据作为输出(y),就构成了一条数据。然后使用长度为31天的扫描框,对一年的数据进行一次遍历,我们就得到了一组数据集。用它进行训练,完成后,输入30天前到今天的气温序列,即可预测明天的气温。

回到这个问题上来,其实和预测气温差不多,我们使用连续若干期的球1的数据来预测下期球1的分布概率,球2-球7都是同样的方法。单从输入输出看来就是这样,实际上实现起来肯定会有更多的处理和优化,在这里不讨论,说到模型的时候再细说。

和预测气温的例子不同,气温预测时只有一种因子参与,就是当天的气温值。而在这个例子里,输入的是7个球,输出的也是7个概率分布,所以这是个多输入、多输出的模型。我准备使用keras来实现模型,按照keras的接口,我需要把输入数据处理成这个格式:

x={
   'x1': [1序列1,1序列2, ... ,1序列n], 'x2': [2序列1,2序列2, ... ,2序列n], ... , 'x7': [7序列1,7序列2, ... ,7序列n]}

相应的,输出数据整理成这个格式:

y={
   'y1': [序列1的下一期球1, 序列2的下一期球1, ... 序列n的下一期球1], 'y2': [序列1的下一期球2, 序列2的下一期球2, ... 序列n的下一期球2], ... ,'y7': [序列1的下一期球7, 序列2的下一期球7, ... 序列n的下一期球7], }

开搞!

# -*- coding: utf-8 -*-
# @File  : dataset.py
# @Author: AaronJny
# @Date  : 2019/10/29
# @Desc  : 对数据集进行相关处理
import time
import numpy as np
import settings


class LottoDataSet:

    def __init__(self, path=settings.DATASET_PATH, train_data_rate=0.9, shuffle=True):
        # 数据集路径
        self.path &#
  • 50
    点赞
  • 205
    收藏
    觉得还不错? 一键收藏
  • 38
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值