使用numpy random和pandas样本从DF中进行随机选择,而不是在100k运行后随机分布选择

问题描述 投票:0回答:1

我为我的 D&D 小组制作了一个小脚本,当施放咒语时,选择是否施放另一个随机咒语、施放顺序咒语或什么都不发生(比例为 50%、25%、25%) ,分别)。

为了做到这一点,我对游戏中每个可能的咒语进行了

pd.DataFrame
(使用来自http://dnd5e.wikidot.com/spells的数据),然后附加了两个数据框(其中一个显示“咒语名称中的“Original Cast”,另一个写着“Nothing Happens”),每个都带有
len  == len(df)/2
,以便拥有两倍于原始大小的完整
df
,如下面的代码所示。

import pandas as pd
import numpy as np
from os import urandom

def create_df():

    df = pd.read_csv("all_spells.csv", encoding="utf-8")
    df = df.dropna(axis=0, subset="Spell Name")
    df_b = df[~df["Spell Name"].str.contains(r"\((.*?)\)")].reset_index(drop=True)


    OG_cast = ['Orginal Cast' for i in range(int(len(df.index)/2))]
    No_Magic = ['Nothing Happens' for i in range(int(len(df.index)/2))]
    Nadda = [None for i in range(int(len(df.index)/2))]

    df_same = pd.DataFrame(columns=df.columns,
                           data={
                               df.columns[0]: OG_cast,
                               df.columns[1]: Nadda,
                               df.columns[2]: Nadda,
                               df.columns[3]: Nadda,
                               df.columns[4]: Nadda
                           })
    df_nothing = pd.DataFrame(columns=df.columns,
                           data={
                               df.columns[0]: No_Magic,
                               df.columns[1]: Nadda,
                               df.columns[2]: Nadda,
                               df.columns[3]: Nadda,
                               df.columns[4]: Nadda
                           })

    df_full = pd.concat([df_b, df_same, df_nothing], axis=0).reset_index(drop=True)

    return df_full

df_full.sample(n=10)
如下所示,供参考。

+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+
|     | Spell Name                 | School        | Casting Time   | Range   | Duration                       | Components   |
+=====+============================+===============+================+=========+================================+==============+
|  12 | Psychic Scream             | Enchantment   | 1 Action       | 90 feet | Instantaneous                  | S            |
+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+
|  18 | True Polymorph             | Transmutation | 1 Action       | 30 feet | Concentration up to 1 hour     | V S M        |
+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+
| 670 | Orginal Cast               |               |                |         |                                | nan          |
+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+
| 193 | Conjure Woodland Beings    | Conjuration   | 1 Action       | 60 feet | Concentration up to 1 hour     | V S M        |
+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+
| 795 | Orginal Cast               |               |                |         |                                | nan          |
+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+
| 218 | Otilukes Resilient Sphere | Evocation     | 1 Action       | 30 feet | Concentration up to 1 minute   | V S M        |
+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+
| 353 | Levitate                   | Transmutation | 1 Action       | 60 feet | Concentration up to 10 minutes | V S M        |
+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+
| 839 | Nothing Happens            |               |                |         |                                | nan          |
+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+
| 459 | Silent Image               | Illusion      | 1 Action       | 60 feet | Concentration up to 10 minutes | V S M        |
+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+
| 719 | Orginal Cast               |               |                |         |                                | nan          |
+-----+----------------------------+---------------+----------------+---------+--------------------------------+--------------+       

然后我调用下面的脚本来了解施放咒语时会发生什么。

    df = create_df()

    seed = int(np.random.uniform(0, len(df.index)*10))
    spell = df.sample(1, random_state=seed)['Spell Name'].values[0]
    print("The spell cast is:", spell)

为了测试这是否给了我想要的分布(50%的时间,有一个随机咒语施放,25%没有任何反应,25%的咒语按预期工作),我跑了

    OC = 0
    NH = 0
    N = 0
    for i in range(100000):
        seed = int(np.random.uniform(0, len(df.index)*10))
        arb = df.sample(1, random_state=seed)['Spell Name'].values[0]
        # print(arb)
        if arb == 'Orginal Cast':
            OC += 1
        elif arb == 'Nothing Happens':
            NH += 1
        else: N += 1


    print(OC, NH, N)

我得到的不是 50/25/25(对于上述内容),而是极其一致的 47/26.5/26.5。有谁知道为什么会发生这种情况?有没有人有更好的想法和随机抽样,以便更一致地获得正确的比率?

python pandas numpy random
1个回答
0
投票

你的方法似乎不必要地复杂。

最后你希望“施放咒语时,随机选择是否施放该咒语,施放另一个随机咒语,或者什么也不发生。”。

所以就这样做,不需要创建复杂的 pandas 结构:

import numpy as np
import pandas as pd

# load dataset
df = pd.read_html('http://dnd5e.wikidot.com/spells')[0]

def cast_spell(df, spell, p=[0.25, 0.5, 0.25]):
    # check the input is valid
    assert spell in df['Spell Name'].values
    
    # randomly pick one of the outcomes
    match np.random.choice(['Original Spell', 'Other Spell', 'Nothing happens'], p=p):
        case 'Original Spell':
            return f'The "{spell}" spell was successfully cast.'
        case 'Nothing happens':
            return f'The "{spell}" spell failed: nothing happens.'
        case _:
            other = df.loc[df['Spell Name'].ne(spell), 'Spell Name'].sample(1).item()
            return f'The "{spell}" spell failed. "{other}" was cast instead.'

cast_spell(df, 'True Strike')

呼叫20次的例子

cast_spell(df, 'True Strike')
:

The "True Strike" spell failed. "Poison Spray" was cast instead.
The "True Strike" spell was successfully cast.
The "True Strike" spell failed. "Lightning Lure" was cast instead.
The "True Strike" spell failed. "Thaumaturgy" was cast instead.
The "True Strike" spell was successfully cast.
The "True Strike" spell was successfully cast.
The "True Strike" spell failed. "Light" was cast instead.
The "True Strike" spell failed. "Infestation" was cast instead.
The "True Strike" spell was successfully cast.
The "True Strike" spell failed. "Mind Sliver" was cast instead.
The "True Strike" spell failed: nothing happens.
The "True Strike" spell failed. "Lightning Lure" was cast instead.
The "True Strike" spell failed: nothing happens.
The "True Strike" spell failed: nothing happens.
The "True Strike" spell failed. "Mage Hand" was cast instead.
The "True Strike" spell was successfully cast.
The "True Strike" spell failed: nothing happens.
The "True Strike" spell was successfully cast.
The "True Strike" spell failed. "Primal Savagery" was cast instead.
The "True Strike" spell failed. "Frostbite" was cast instead.
© www.soinside.com 2019 - 2024. All rights reserved.