2014-10-22 191 views
1

我对熊猫(和python ...和编程)相对较新,我试图做一个蒙特卡洛模拟,但我一直没能找到一个解决方案,需要一个合理的数量时间随机采样与熊猫数据帧

的数据存储在一个名为“YTDSales”它有每天的销售数据帧,每个产品

Date   Product_A  Product_B  Product_C  Product_D  ... Product_XX 
01/01/2014   1000   300   70   34500  ...   780 
02/01/2014   400   400   70   20  ...   10 
03/01/2014   1110   400   1170   60  ...   50 
04/01/2014   20   320    0   71300  ...   10 
     ... 
15/10/2014   1000   300   70   34500  ...   5000 

什么,我想要做的是模拟不同的情形,使用的休息年份(从10月15日到年底)每个产品的历史分布。例如与给出的数据,我会想,以填补今年余下时间在20至1100

之间销售我所做的是以下

# creates range of "future dates" 
last_historical = YTDSales.index.max() 
year_end = dt.datetime(2014,12,30) 
DatesEOY = pd.date_range(start=last_historical,end=year_end).shift(1) 

# function that obtains a random sales number per product, between max and min 
f = lambda x:np.random.randint(x.min(),x.max()) 

# create all the "future" dates and fill it with the output of f 
for i in DatesEOY: 
    YTDSales.loc[i]=YTDSales.apply(f) 

解决方案的工作,但需要约3秒,这是很多,如果我打算重复1000次......有没有办法迭代?

感谢

回答

0

使用size选项np.random.randint获得所需大小的样品的一次。 我会考虑的一种方法简要如下。

  1. 分配,你需要进入一个新的阵列,将有来自原始数据帧从DatesEOY索引值,列的空间,和所有NaN值。然后连接到原始数据。

  2. 现在您知道您需要的每个随机样本的长度,请使用numpy.random.randint中的额外size关键字来一次对所有列进行采样,而不是循环采样。

  3. 用此批量采样覆盖数据。

这里的,这可能是什么样子:

new_df = pandas.DataFrame(index=DatesEOY, columns=YTDSales.columns) 

num_to_sample = len(new_df) 

f = lambda x: np.random.randint(x[1].min(), x[1].max(), num_to_sample) 

output = pandas.concat([YTDSales, new_df], axis=0) 

output[len(YTDSales):] = np.asarray(map(f, YTDSales.iteritems())).T 

一路上,我选择做一个全新的数据帧,通过连接旧与新的“占位符”之一。这对于非常大的数据显然可能是低效的。

与您的for-loop解决方案一样,另一种方法是setting with enlargement

我没有玩弄这种方法足够长的时间来弄清楚如何一次“放大”批次的索引。但是,如果你知道这一点,可以用所有NaN值(索引值为DatesEOY)“放大”原始数据帧,然后将该函数应用于YTDSales而不是将它加入output