Найти в Dataframe повторяющиеся значения через каждые три строчки

Есть задача по комбинаторике:

В ящике 5 апельсинов и 4 яблока. Наудачу выбираются 3 фрукта. Какова вероятность, что все три фрукта – апельсины?

Необходимо проверить экспериментально в Python. (вероятность - 0.119)

import pandas as pd
import numpy as np
import random

U = ["orange"]*5 + ['apple']*4
# наполняем урну
n = 120000
# количество экспериментов
A = pd.DataFrame({"A":list(map(lambda a: random.choice([random.choice(U)]), range(n)))})
# формируем выборку

Есть ли способ посчитать значения Dataframe через каждые три элемента, которые будут содержать только 'orange' ? Планировал полученное число разделить на 40000, чтобы получить вероятность.


Ответы (5 шт):

Автор решения: strawdog

Я не совсем уверен, что вы в принципе правильно пытаетесь проверить вероятность опытным путём, но что касается выборки, я бы советовал использовать не каждый третий ряд

(A.iloc[::3,0] == "orange").sum()

, а воспользоваться методом sample:

random.seed(42)
# количество экспериментов
A = pd.DataFrame({"A":list(map(lambda a: random.choice([random.choice(U)]), range(n)))})
res = A.sample(frac=0.33, replace=False, random_state=42).value_counts()["orange"]

22179

→ Ссылка
Автор решения: CrazyElf

ПОДХОД К ЭКСПЕРИМЕНТУ У ВАС НЕПРАВИЛЬНЫЙ.

Можете посмотреть тут код, чтобы чему-то научиться. Но для правильного результата смотрите другой мой ответ.

Поменял несколько ваш код.

  • чтобы упростить дальнейшие вычисления я сразу проверяю, что выпал именно orange и ставлю 1 если да
  • я делаю в датафрейме группы по 3 элемента с помощью groupby
  • дальше я суммирую те единички по группам
  • если в группе получилось три единички, то это то, что мы ищем
  • результат варьируется, но не похож на тот, который вы предполагали
import pandas as pd
import random

# наполняем урну
data = ["orange"]*5 + ['apple']*4

# количество экспериментов
n = 120_000

# формируем выборку
df = pd.DataFrame({"data": [random.choice(data) == 'orange' for _ in range(n)], "group": [i // 3 for i in range(n)]})

# вычисляем
print((df.groupby("group").sum() == 3).sum()['data'] / 40_000)

Пример вывода:

0.1725

Тот же эксперимент без пандас. С таким же результатом:

import random

# наполняем урну
data = ["orange"]*5 + ['apple']*4

# количество экспериментов
n = 120_000

# выборка
k = 3

print(sum(sum(random.choice(data) == 'orange' for _ in range(k)) == 3 for _ in range(n)) / n)

Пример вывода:

0.17134166666666667
→ Ссылка
Автор решения: CrazyElf

А, я понял. У вас подход к эксперименту неправильный, результат поэтому получается не тот, который ожидается. Фактически, вы не соблюдаете условие, что у вас есть ящик из которого вы вынимаете фрукты. У вас есть склад с ящиками и вы вынимаете 3 фрукта из любых ящиков, а не только из одного, из-за этого получается не верный результат. Если брать фрукты из одного ящика, то с каждым взятым апельсином вероятность следующего апельсина сильно уменьшается. А если брать со склада, то вероятность падает не настолько сильно.

Как посчитать верный результат:

  • брать для эксперимента строго один ящик, а не множество ящиков
  • перемешивать каждый раз фрукты в ящике
  • брать три первых фрукта
  • проверять, что все они апельсины
  • разделить число получившихся случаев "3 апельсина" на число экспериментов
import random

# наполняем урну
data = ["orange"]*5 + ['apple']*4

# количество экспериментов
n = 120_000

# выборка
k = 3

positive = 0
for _ in range(n):
    random.shuffle(data)
    result = all(x == 'orange' for x in data[:k])
    positive += result
print(positive/n)

Пример вывода:

0.118875

Вот это уже похоже на искомый результат.

Проверим цифры аналитически. Если мы берём апельсины из ящика, где их изначально 5 из 9, то вероятность взять 3 апельсина подряд будет:

print(5/9 * 4/8 * 3/7)
# 0.11904761904761905

А если мы берём апельсины из большого склада, то вероятность с каждым взятым апельсином будет падать очень незначительно, можно сказать вообще не будет падать:

print((5/9)**3)
# 0.1714677640603567

Именно эти цифры мы и наблюдаем в правильном и в неправильном экспериментах.

→ Ссылка
Автор решения: MarianD

Не надо никаких датафреймов, у Питона самого есть модуль random:

import random

INBOX = 5 * ["O"] + 4 * ["A"]
WANTED = 3 * ["O"]
N = 100_000

wanted = 0

for __ in range(N):
    if random.sample(INBOX, k=3) == WANTED:
        wanted += 1 
       
print(f"Вероятность, что все три фрукта – апельсины: {wanted/N}") 

Вывод (например):

 Вероятность, что все три фрукта – апельсины: 0.11821
→ Ссылка
Автор решения: SergFSM

по сути это реализация метода Монте-Карло, немного подправил ваш код:

from random import sample

U = [0]*5 + [1]*4
n = 120000

df = pd.DataFrame({"A":list(map(lambda a: sum(sample(U,3))==0, range(n)))})
print(df.head())
'''
       A
0  False
1  False
2   True
3   True
4  False
'''

# вероятность
df['A'].mean()
0.11896666666666667
→ Ссылка