paint-brush
Уточните лотерейные номерак@alexthoughts
30,826 чтения
30,826 чтения

Уточните лотерейные номера

к Alex6m2023/10/01
Read on Terminal Reader
Read this story w/o Javascript

Слишком долго; Читать

Лотереи всегда непредсказуемы, но интересно заглянуть за кулисы и изучить особенности этих игр. Независимо от того, являетесь ли вы игроком или просто любопытным наблюдателем, в мире чисел всегда есть сюрприз или два в рукаве.
featured image - Уточните лотерейные номера
Alex HackerNoon profile picture


В моей стране еженедельно проводится лотерея, в которой участники выбирают 6 номеров из группы 37 и еще одно число из группы 7. Давайте сосредоточимся на первой части игры и не будем рассматривать выбор одного дополнительного номера из группы 7. 7.


Когда речь идет о лотереях вида k/N, где k — количество желаемых выборов (в нашем случае 6) из общего пула из N чисел (в нашем случае 37), общий вопрос заключается в том, каждый ли из них эти числа имеют равные шансы стать частью выигрышной комбинации.


Давайте исследуем этот вопрос.


Я собрал с их сайта статистику по 1609 рисункам с 2009 по 2023 год.


Впоследствии я преобразовал данные из файла 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 отдельных чисел, вы можете использовать следующий подход:


  • Вычислите наблюдаемую частоту (Oi), с которой каждое число i = 1, ..., N выпадало в n тиражах лотереи.


  • Вычислите ожидаемое количество подсчетов (Ei) для каждого номера по формуле Ei = (nk)/N, где n — общее количество тиражей лотереи, k — количество номеров, выбранных в каждом тираже (в данном случае 6), и N — общее количество возможных чисел (в данном случае 37).


  • Используйте статистику Пирсона или статистику хи-квадрат, чтобы сравнить наблюдаемое количество (Oi) с ожидаемым количеством (Ei). Формула статистики Пирсона часто выражается как:

  • Рассчитайте статистику хи-квадрат, используя наблюдаемые и ожидаемые значения.


  • Выполните статистический тест, например тест хи-квадрат, чтобы определить, является ли вычисленное значение хи-квадрат статистически значимым. Это поможет вам оценить, значительно ли распределение чисел отличается от ожидаемого при равновероятности.


Если вычисленное значение хи-квадрат не является статистически значимым, это предполагает, что числа распределены достаточно равномерно, что подтверждает гипотезу равновероятности. Однако, если значение 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'] }


Забавно отметить, что эти события произошли почти один за другим.


Завершая наше путешествие в мир лотерейных данных, мы столкнулись с безумным путешествием по числам и вероятностям. Мы обнаружили несколько интересных фактов – от пар и троек до определения самых популярных чисел.


Лотереи всегда непредсказуемы, но интересно заглянуть за кулисы и изучить особенности этих игр. Независимо от того, являетесь ли вы игроком или просто любопытным наблюдателем, в мире чисел всегда есть один или два сюрприза в рукаве.