在我的国家,有一个每周一次的乐透游戏,参与者从 37 个号码池中选择 6 个号码,然后从 7 个号码池中选择另一个号码。让我们关注游戏的第一部分,忽略从 1 个号码池中选择一个额外号码。 7.
当涉及 k/N 形式的彩票时,其中 k 是 N 个号码总数(在我们的例子中为 37)中所需选择的数量(在我们的例子中为 6),一个常见的问题是每个这些数字有相同的机会成为获胜组合的一部分。
我们来研究一下这个问题。
我从他们的网站上收集了 2009 年至 2023 年 1609 张图画的统计数据。
随后,我将 CSV 文件中的数据转换为对象:
{ '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], ... }
对象中的键对应于抽奖日期,关联值是作为该特定抽奖的获胜组合出现的数字的数组。
之后,我创建了一个数组,其中包含从图纸中获得的所有数字:
numbers = np.array(list(lotto.values())).flatten() [13, 17, 24, 30, 35, 37, 7, 17, 19, 25, 35, 37, 2, 3, 5, 9, 36, ...]
接下来,我计算了数组中每个值的出现次数(频率):
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]
这些结果表明,数字 1 被抽取了 268 次,数字 2 被抽取了 256 次,依此类推。
看来,开奖结果中的号码分布还是比较均匀的。为了进一步证实这一点,我们可以进行测试来验证分布的均匀性。
要测试 N 个单独数字的等概率,可以遵循以下方法:
执行统计检验(例如卡方检验)以确定计算的卡方值是否具有统计显着性。这将帮助您评估数字的分布是否与等概率下的预期显着不同。
如果计算出的卡方值在统计上不显着,则表明数字分布合理均匀,支持等概率假设。但是,如果 X^2 值显着,则表明偏离等概率。
让我们创建一个函数来执行数字等概率的卡方检验:
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
该函数返回由卡方统计量和以概率1 - 2 * p-value
接受的等概率结果组成的元组,即该离散均匀分布的极值概率较低。
N = 37 chi2(count, len(numbers), N) (25.183136523720748, True)
当然,您可以使用 SciPy 库的内置功能来执行等概率的卡方检验:
from scipy import stats chi2_statistic, p_value = stats.chisquare(count) (25.18313652372074, 0.9115057832606053)
让我们从成对开始探索这些数字的组合:
from itertools import combinations pairs = list(combinations(range(1, N), 2))
在此步骤之后,我们构建一个二维矩阵来跟踪这些对的出现:
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:]
这形成了一个三角矩阵,因为它说明了 (a, b) 和 (b, a) 等价的事实,并且我们只计算 (a, b) 对的出现次数。
我的函数产生:
counts = pairs_count.flatten() counts = counts[counts > 0] chi2(counts, sum(counts), len(counts)) (589.2721893491138, True)
SciPy 提供:
chi2_statistic, p_value = stats.chisquare(counts) (589.2721893491124, 0.8698507423203673)
考虑三胞胎怎么样:
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)
出了问题,可能是由于矩阵的高度稀疏性。卡方值低于下临界卡方阈值:
6457.575829383709 < 6840.049842653838
然而,当使用SciPy时,结果是:
chi2_statistic, p_value = stats.chisquare(counts) (6457.575829383886, 0.9999997038479482)
现在,让我们找出最常抽奖的号码:
count.argmax() or list(count).index(max(count)) 11
我们先不要急于下结论。我们可以看看这个数字多年来是如何演变的:
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 }
或者,我们可以分析随时间推移的累积变化:
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 }
最后,我们还可以调查是否曾经出现过相同的图画:
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'] }
有趣的是,这些事件几乎连续发生。
当我们结束彩票数据世界的旅程时,这是一次数字和概率的疯狂之旅。我们发现了一些有趣的花絮——从成对和三胞胎到发现最受欢迎的数字。
彩票充满了不可预测性,但窥视幕后并探索这些游戏的怪癖是很有趣的。无论您是玩家还是好奇的观察者,数字世界总有一两个惊喜。