首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python中多个条目的Monte模拟

Python中多个条目的Monte模拟
EN

Stack Overflow用户
提问于 2018-09-26 02:08:48
回答 1查看 1.3K关注 0票数 1

我一直在努力创建一个蒙特卡罗模拟,它将贯穿我的数据的每个ID,并产生它们各自的均值和标准偏差。我已经能够为任何一个ID编写代码来获取它,但是不能迭代我的dataframe中的整个ID列表。因此,我可以单独编写每一行,但我需要代码来迭代任何可更改的I列表。

在这里,我尝试创建一个列表,其中可以存储每一组Monte观测结果(平均值和std可以从中提取)。我不相信这将是最有效的编码方式,但这是我现在所知道的。是否在每个Is上运行Monte模拟(而不具体调用每个Is)?我需要能够从列表中添加和删除各种ID和相应的数据。

这是对Utilizing Monte Carlo to Predict Revenue in Python的后续跟进

代码语言:javascript
复制
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np


ID = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Revenue = [1000, 1200, 1300, 100 ,500, 0, 800, 950, 4321, 800, 1000, 1200, 1300, 100 ,500, 0, 800, 950, 4321, 800]
odds = [0.5, 0.6, 0.33, 0.1, 0.9, 0.87, 0.37, 0.55, 0.97, 0.09, 0.5, 0.6, 0.33, 0.1, 0.9, 0.87, 0.37, 0.55, 0.97, 0.09]

d = {'ID': ID, 'Revenue': Revenue, 'Odds': odds}
df = pd.DataFrame(d)
df['Expected Value'] = df['Revenue']*df['Odds']

print(df)

num_samples = 100
df['Random Number'] = np.random.rand(len(df))

def monte_carlo_array(df):
    for _ in range(len(df)):
        yield []

mc_arrays = list(monte_carlo_array(df))

# Fill each list with 100 observations (no filtering necessary)
id_1 = []
filter_1 = (df['ID'] == 5)

for _ in range(num_samples):
    sample = df['Revenue'] * np.where(np.random.rand(len(df)) < \
                          df['Odds'], 1, 0)
    for l in monte_carlo_array(df):
        for i in l:
        mc_arrays[i].append(sample.sum())
    id_1.append(sample.loc[filter_1].sum())


# Plot simulation results.
n_bins = 10
plt.hist([id_1], bins=n_bins, label=["ID: 1"])
plt.legend()
plt.title("{} simulations of revenue".format(num_samples))

print(mc_arrays)

df['Monte Carlo Mean'] = np.mean(mc_arrays[0])
print(df['Monte Carlo Mean'])
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-26 05:33:51

IIUC,这就是你要做的:

  • 对于每一行(代表一个ID),您需要对该行是否实现其Revenue进行总计的num_samples蒙特卡罗模拟。
  • 确定给定的模拟实例是否实现其Revenue的方法是将[0,1]中随机绘制的值与该行的Odds (以标准蒙特卡罗方式)进行比较。
  • 您希望了解所有样本中每一行的Revenue的平均值和标准差。

如果是这样的话,您可以通过利用二项分布的抽样功能来做到这一点,而不是从一个统一的、然后基于Odds的过滤。我将在这个答案的末尾发布一个使用这种方法的解决方案。

但是,由于您已经开始使用统一绘制方法:我建议首先由s_draws num_samples (在下面的代码中称为n_draws )创建一个抽样矩阵。然后将Odds检查应用于s_draws每一行中的所有示例。然后乘以Revenue,取每行的平均值和sd。如下所示:

首先,绘制抽样矩阵:

代码语言:javascript
复制
np.random.seed(42)

n_rows = len(df)
n_draws = 5
s_draws = pd.DataFrame(np.random.rand(n_rows, n_draws))

# the matrix of random values between [0,1]
# note: only showing the first 3 rows for brevity
s_draws
           0         1         2         3         4
0   0.374540  0.950714  0.731994  0.598658  0.156019
1   0.155995  0.058084  0.866176  0.601115  0.708073
2   0.020584  0.969910  0.832443  0.212339  0.181825
...

现在,找出哪些采样实例“达到”了目标Revenue

代码语言:javascript
复制
s_rev = s_draws.apply(lambda col: col.lt(df.Odds) * df.Revenue)

# the matrix of sampled revenue
s_rev
       0     1     2     3     4
0   1000     0     0     0  1000
1   1200  1200     0     0     0
2   1300     0     0  1300  1300
...

最后,计算每一行/ID的汇总统计信息:

代码语言:javascript
复制
s_result = pd.DataFrame({"avg": s_rev.mean(axis=1), "sd": s_rev.std(axis=1)})

# the summary statistics of each row of samples
s_result
       avg          sd
0    400.0  547.722558
1    480.0  657.267069
2    780.0  712.039325
...

下面是使用二项式抽样的版本:

代码语言:javascript
复制
draws = pd.DataFrame(
    np.random.binomial(n=1, p=df.Odds, size=(n_draws, n_rows)).T
).multiply(df.Revenue, axis=0)

pd.DataFrame({"avg": draws.mean(axis=1), "sd": draws.std(axis=1)})

注意:如果IDdf中跨多个行重复,那么这一切的工作方式就会有所不同。在这种情况下,您可以使用groupby,然后进行汇总统计。但是在你的例子中,ID永远不会被重复,所以我将把答案保留为-就是现在。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52508956

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档