Python分析一下双色球,中大奖指日可待

一、需求简介

之前偶然见到一位网友提出了关于双色球数据的分析需求,感觉颇有趣味,便着手操作了一番。如下为某双色球发布站的页面,可以看到每期会产生红/蓝两种颜色的数字,其中红球为 33 选 6,蓝球为 16 选 1,一共是从 49 个球中选 7 个。假如想对某一色号球下注,比如红1 球,要先分析一下该球以往的产出情况。
在这里插入图片描述
可以从以下 3 个方面来分析,以史明鉴,看看最新一期是否值得选取该球:

1、遗漏情况

统计遗漏 n 期后命中的次数,如上图:遗漏 1 期后中的次数有 2 次,遗漏 2 期后中的次数有 1 次,遗漏 5 期后中的次数有 2 次,遗漏 7 期后中的次数有 1 次。
在这里插入图片描述

2、连续重号情况

如图,连续重号 3 期的有 1 次。
在这里插入图片描述

3、重号前的遗漏情况

如图,重号前遗漏 2 期的有 1 次。
在这里插入图片描述

二、源数据

节选源数据如下,数据是以 html 表格形式储存的,<td> 标签中 class=“yl01” 表示未命中,class=“chartBall01” 表示命中红球,class=“chartBall02” 表示命中蓝球(文末获取近 100 期数据样本)。

					<tr>

							<td class="c_fbf5e3 bd_rt_a">2021090</td>

							<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">8</td>

									<td class="yl01" style="font-size:xx-small">2</td>

									<td class="chartBall01">05</td>

										<td class="chartBall01">06</td>

										<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">4</td>

									<td class="yl01" style="font-size:xx-small">6</td>

									<td class="yl01" style="font-size:xx-small">4</td>

									<td class="yl01" style="font-size:xx-small">5</td>

									<td class="chartBall01">12</td>

										<td class="yl01" style="font-size:xx-small">1</td>

									<td class="chartBall01">14</td>

										<td class="yl01" style="font-size:xx-small">2</td>

									<td class="yl01" style="font-size:xx-small">2</td>

									<td class="yl01" style="font-size:xx-small">13</td>

									<td class="yl01" style="font-size:xx-small">9</td>

									<td class="yl01" style="font-size:xx-small">2</td>

									<td class="yl01" style="font-size:xx-small">5</td>

									<td class="yl01" style="font-size:xx-small">6</td>

									<td class="yl01" style="font-size:xx-small">9</td>

									<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">7</td>

									<td class="yl01" style="font-size:xx-small">2</td>

									<td class="chartBall01">27</td>

										<td class="chartBall01">28</td>

										<td class="yl01" style="font-size:xx-small">4</td>

									<td class="yl01" style="font-size:xx-small">13</td>

									<td class="yl01" style="font-size:xx-small">12</td>

									<td class="yl01" style="font-size:xx-small">8</td>

									<td class="yl01" style="font-size:xx-small">7</td>

									<td class="v_line"></td>

							<td class="yl01" style="font-size:xx-small">4</td>

									<td class="yl01" style="font-size:xx-small">5</td>

									<td class="yl01" style="font-size:xx-small">42</td>

									<td class="yl01" style="font-size:xx-small">3</td>

									<td class="yl01" style="font-size:xx-small">8</td>

									<td class="yl01" style="font-size:xx-small">2</td>

									<td class="yl01" style="font-size:xx-small">16</td>

									<td class="chartBall02">08</td>

										<td class="yl01" style="font-size:xx-small">10</td>

									<td class="yl01" style="font-size:xx-small">13</td>

									<td class="yl01" style="font-size:xx-small">54</td>

									<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">11</td>

									<td class="yl01" style="font-size:xx-small">31</td>

									<td class="yl01" style="font-size:xx-small">18</td>

									<td class="yl01" style="font-size:xx-small">25</td>

									</tr>

						<tr>

							<td class="c_fbf5e3 bd_rt_a">2021091</td>

							<td class="yl01" style="font-size:xx-small">2</td>

									<td class="yl01" style="font-size:xx-small">2</td>

									<td class="yl01" style="font-size:xx-small">9</td>

									<td class="chartBall01">04</td>

										<td class="yl01" style="font-size:xx-small">1</td>

									<td class="chartBall01">06</td>

										<td class="yl01" style="font-size:xx-small">2</td>

									<td class="yl01" style="font-size:xx-small">5</td>

									<td class="yl01" style="font-size:xx-small">7</td>

									<td class="yl01" style="font-size:xx-small">5</td>

									<td class="yl01" style="font-size:xx-small">6</td>

									<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">2</td>

									<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">3</td>

									<td class="chartBall01">16</td>

										<td class="yl01" style="font-size:xx-small">14</td>

									<td class="yl01" style="font-size:xx-small">10</td>

									<td class="yl01" style="font-size:xx-small">3</td>

									<td class="yl01" style="font-size:xx-small">6</td>

									<td class="yl01" style="font-size:xx-small">7</td>

									<td class="yl01" style="font-size:xx-small">10</td>

									<td class="yl01" style="font-size:xx-small">2</td>

									<td class="chartBall01">24</td>

										<td class="yl01" style="font-size:xx-small">8</td>

									<td class="chartBall01">26</td>

										<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">5</td>

									<td class="yl01" style="font-size:xx-small">14</td>

									<td class="yl01" style="font-size:xx-small">13</td>

									<td class="yl01" style="font-size:xx-small">9</td>

									<td class="chartBall01">33</td>

										<td class="v_line"></td>

							<td class="yl01" style="font-size:xx-small">5</td>

									<td class="yl01" style="font-size:xx-small">6</td>

									<td class="yl01" style="font-size:xx-small">43</td>

									<td class="yl01" style="font-size:xx-small">4</td>

									<td class="yl01" style="font-size:xx-small">9</td>

									<td class="yl01" style="font-size:xx-small">3</td>

									<td class="yl01" style="font-size:xx-small">17</td>

									<td class="yl01" style="font-size:xx-small">1</td>

									<td class="yl01" style="font-size:xx-small">11</td>

									<td class="yl01" style="font-size:xx-small">14</td>

									<td class="yl01" style="font-size:xx-small">55</td>

									<td class="yl01" style="font-size:xx-small">2</td>

									<td class="yl01" style="font-size:xx-small">12</td>

									<td class="yl01" style="font-size:xx-small">32</td>

									<td class="yl01" style="font-size:xx-small">19</td>

									<td class="chartBall02">16</td>

										</tr>

三、解析实现

1、数据结构

为了便于表示球的命中与颜色、数值,我们可以按以下规则映射:
在这里插入图片描述
那么先用美丽汤把需要的内容捞出来,把所有 <td> 标签中表示名字与色号的内容取出,按上述规则映射表示。

soup = BeautifulSoup(res_table, "html.parser")
item_lst = []
for td in soup.find_all('td'):
	cls = td['class'][0]
	num = td.string
	if cls in ['yl01', 'chartBall01', 'chartBall02']:
	    item_lst.append('-'.join([cls, num]))
print(item_lst[:10])

输出前 10 个预览如下:

[‘yl01-3’, ‘yl01-5’, ‘chartBall01-03’, ‘yl01-5’, ‘yl01-1’, ‘yl01-5’, ‘chartBall01-07’, ‘yl01-9’, ‘yl01-6’, ‘yl01-6’]

但这仅仅是一个超长列表,在此基础上处理起来还找不到头绪,至少要转变成和网页上结构一致的矩阵才好理解吧,那么可以想到利用 numpy 矩阵。先是用 np.array 将普通列表转为 numpy 数组,再利用 reshape 将一维数组转为二维数组,即 100 期 X 49 个球的矩阵。

array = np.array(item_lst).reshape(100, 49)

如图,numpy 矩阵的每一行与原页面结构对应。
在这里插入图片描述
但我们想要进行的是纵向比较分析,比较各期之间的关系,所以还需要再对矩阵进行行列转置。

array_T = array.T  # 矩阵转置,一个元素对应一列

在这里插入图片描述
此时,array_T 中的每一个元素即表示某一色号的近 100 期情况。如果想看红1 球,则是 array_T[0];如果想看红2 球,则是 array_T[1];如果想看蓝1 球,则是 array_T[33](因为红球总共有 33 个,故第一个蓝球列的索引为 33)。为了便于选球,我们可以写一个映射方法:

def trans_col(txt):  # 翻译列索引号,如红1=0,红33=32,蓝1=33,蓝16=48
    if "红" in txt:
        col = int(txt.replace('红', '')) - 1
    else:
        col = int(txt.replace('蓝', '')) + 32
    return col

接下来就可以正式开始实现统计分析的需求啦!

2、遗漏统计

将转置矩阵和指定色号球所在列传入,获取该列后加入一个结束标记,因至少要出现 1 次未命中 +1 次命中才判定为遗漏 1 期,所以从该列的第二项数据开始判断,若其不等于前一项的值,且当前项为命中,则记录前一项的值(遗漏期数)。之后将记录列表中的表示遗漏的标记 yl01 去除,仅保留期数。

def fun_miss(array, col):  # 统计该列中遗漏后命中的次数
    line = array[col].tolist()
    order_grp = []
    for i, v in enumerate(line):
        if i > 0:
            if v != line[i - 1] and 'chart' in v:
                order_grp.append(line[i - 1])
    order_grp = [i.replace('yl01-', '') for i in order_grp]
    c = dict(Counter(order_grp))
    result = sorted(c.items(), key=lambda x: int(x[0]))
    for i in result:
        print(f"遗漏{i[0]}期后中的次数有{i[1]}次")
     
fun_miss(array_T, trans_col("红1"))  # 执行

在这里插入图片描述
统计排序后输出如下:

遗漏1期后中的次数有4次
遗漏2期后中的次数有2次
遗漏3期后中的次数有3次
遗漏5期后中的次数有2次
遗漏7期后中的次数有2次
遗漏8期后中的次数有1次
遗漏9期后中的次数有2次
遗漏13期后中的次数有1次

3、连续重号统计

与遗漏统计相同,传入两个参数,先确定要选取的色号列。当前项等于前一项,且当前项为命中时表示重号,连续重号时 count 计数 +1,当出现不满足重号条件时表示连续重号中断,记录连续次数,并将计数清零,待下一轮重号出现时重新计数。

def fun_repeat(array, col):  # 统计该列中的重号次数
    line = array[col].tolist()
    count_grp = []
    count = 0
    for i, v in enumerate(line):
        if i > 0:
            if v == line[i-1] and 'chart' in v:
                count += 1
            elif count > 0:
                count_grp.append(count)
                count = 0
    c = dict(Counter(count_grp))
    result = sorted(c.items(), key=lambda x: x[0])
    for i in result:
        print(f"连续重号{i[0]}次的有{i[1]}次")

fun_repeat(wt, trans_col("红2"))  # 执行

在这里插入图片描述
统计排序后输出如下:

连续重号1次的有1次
连续重号2次的有1次

4、重号前的遗漏统计

因要出现重号+遗漏才算入,所以至少从第三项数据开始判定。

def fun_return(array, col):  # 统计该列中重号前的遗漏次数
    line = array[col].tolist()
    order_grp = []
    for i, v in enumerate(line):
        if i > 1:
            if v == line[i - 1] and v != line[i - 2] and 'chart' in v:
                order_grp.append(line[i - 2])
    order_grp = [i.replace('yl01-', '') for i in order_grp]
    c = dict(Counter(order_grp))
    result = sorted(c.items(), key=lambda x: int(x[0]))
    for i in result:
        print(f"重号前遗漏{i[0]}期的有{i[1]}次")
       
fun_return(wt, trans_col("红1"))  # 执行

在这里插入图片描述
统计排序后输出如下:

重号前遗漏2期的有1次

四、小结

源数据自取:度盘,提取码:1gla
完整分析代码如下:

from bs4 import BeautifulSoup
import numpy as np
from collections import Counter


def get_array(res_table):  # 获取转置矩阵
	soup = BeautifulSoup(res_table, "html.parser")
	item_lst = []
	for td in soup.find_all('td'):
		cls = td['class'][0]
		num = td.string
		if cls in ['yl01', 'chartBall01', 'chartBall02']:
		    item_lst.append('-'.join([cls, num]))
	array = np.array(item_lst).reshape(100, 49)
	array_T = array.T
	return array_T

def trans_col(txt):  # 翻译列索引号,如红1=0,红33=32,蓝1=33,蓝16=48
    if "红" in txt:
        col = int(txt.replace('红', '')) - 1
    else:
        col = int(txt.replace('蓝', '')) + 32
    return col

def fun_miss(array, col):  # 统计该列中遗漏后命中的次数
    line = array[col].tolist()
    order_grp = []
    for i, v in enumerate(line):
        if i > 0:
            if v != line[i - 1] and 'chart' in v:
                order_grp.append(line[i - 1])
    order_grp = [i.replace('yl01-', '') for i in order_grp]
    c = dict(Counter(order_grp))
    result = sorted(c.items(), key=lambda x: int(x[0]))
    for i in result:
        print(f"遗漏{i[0]}期后中的次数有{i[1]}次")

def fun_repeat(array, col):  # 统计该列中的重号次数
    line = array[col].tolist()
    count_grp = []
    count = 0
    for i, v in enumerate(line):
        if i > 0:
            if v == line[i-1] and 'chart' in v:
                count += 1
            elif count > 0:
                count_grp.append(count)
                count = 0
    c = dict(Counter(count_grp))
    result = sorted(c.items(), key=lambda x: x[0])
    for i in result:
        print(f"连续重号{i[0]}次的有{i[1]}次")

def fun_return(array, col):  # 统计该列中重号前的遗漏次数
    line = array[col].tolist()
    order_grp = []
    for i, v in enumerate(line):
        if i > 1:
            if v == line[i - 1] and v != line[i - 2] and 'chart' in v:
                order_grp.append(line[i - 2])
    order_grp = [i.replace('yl01-', '') for i in order_grp]
    c = dict(Counter(order_grp))
    result = sorted(c.items(), key=lambda x: int(x[0]))
    for i in result:
        print(f"重号前遗漏{i[0]}期的有{i[1]}次")
       
       
if __name__ == '__main__':
    with open("res_table.txt", "r", encoding="utf-8-sig") as f:
        r = f.read()
    wt = get_array(r, 100)
    choose = "红1"
    fun_miss(wt, trans_col(choose))
    fun_repeat(wt, trans_col(choose))
    fun_return(wt, trans_col(choose))

emmmm…不过如此看来,单单分析一个球是不够滴,还要和其他色号深入对比,有兴趣的同学自己尝试吧哈哈哈!~这里是我命由天不由我的 Seon塞翁,下篇再见!

温馨提示:赌博有风险,本文仅做数据处理技术讨论,不构成任何资金投入建议!不要怪我标题党啦

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值