将numpy解决方案转换为dask(numpy索引在dask中不起作用)

时间:2018-08-23 11:50:27

标签: python numpy dask dask-distributed

我正在尝试将蒙特卡洛模拟从numpy转换为dask,因为有时数组太大,无法容纳到内存中。因此,我在云中建立了一个计算机集群:先进的集群由24个核心和94 GB的内存组成。我为此问题准备了代码的简化版本。

我的原始numpy代码如下:

def numpy_way(sim_count, sim_days, hist_days):
   historical_data = np.random.normal(111.51, 10, hist_days)
   historical_multidim = np.empty(shape=(1, 1, sim_count, hist_days))
   historical_multidim[:, :, :, :] = historical_data


   random_days_panel = np.random.randint(low=1,
                                      high=hist_days,
                                      size=(1, 1, sim_count, sim_days))
   future_panel = historical_multidim[np.arange(1)[:, np.newaxis, np.newaxis, np.newaxis],
                                      np.arange(1)[:, np.newaxis, np.newaxis],
                                      np.arange(sim_count)[:, np.newaxis],
                                      random_days_panel]
   return future_panel.shape
  

注意:我只是在这里返回numpy数组的形状(但是因为它是numpy,所以future_panel的元素被存储在内存中。

有关此功能的一些话:

  • 我正在创建一个随机数组historical_data-这只是一维
  • 然后,将该数组“广播”到4D数组(historical_multidim)。前两个尺寸在这里未使用(但在我的最终应用程序中)
    • 第3维代表完成了多少次仿真
    • 第4维是未来forecasted的天数
  • random_days_panel-只是随机选择的ndarray天。因此,该数组的最后一个shape为:1、1,sim_count,sim_days(在上一点中有解释)
  • future_panel是一个ndarray,具有从historical_multidim中随机选取的值。即从具有预期形状(1、1、1,sim_count,sim_days)的历史数据生成的数组

现在,问题在于,其中一些步骤未在dask中实现:

  • historical_multidim[:, :, :, :] = historical_data-stack或 建议使用broadcast_to
  • future_panel中使用的切片不可能在黄昏时完成

所以我想出了这个解决方案:

def dask_way_1d(sim_count, sim_days, hist_days):
    historical_data = da.random.normal(111.51, 10, size=hist_days, chunks='auto')
    def get_random_days_1d():
        return np.random.randint(low=1, high=HIST_DAYS, size=sim_days)
    future_simulations = [historical_data[get_random_days_1d()] for _ in range(sim_count)]
    future_panel =  da.stack(future_simulations)
    future_panel = da.broadcast_to(future_panel, shape=(1, 1, sim_count, sim_days))
    future_panel.compute()
    return future_panel.shape

此解决方案有效,但是它比numpy解决方案慢得多。问题是get_random_days_1d()返回一个numpy数组。我尝试使用dask数组,但是在计算historical_data[get_random_days_1d()]-> KilledWorker: ("('normal-932553ab53ba4c7e908d61724430bbb2', 0)", ...

时遇到错误

另一个解决方案如下:

    def dask_way_nd(sim_count, sim_days, hist_days):
        historical_data_1d = da.random.normal(111.51, 10, size=hist_days, chunks='auto')
        historical_data_2d = da.broadcast_to(historical_data_1d, shape=(sim_count, hist_days))

        random_days_panel = np.random.randint(low=1,
                                      high=hist_days,
                                      size=(sim_count, sim_days))

        future_panel = historical_data_2d[np.arange(sim_count)[:, np.newaxis], random_days_panel]
        future_panel = da.broadcast_to(future_panel, shape=(1, 1, sim_count, sim_days))
        future_panel.compute()
        return future_panel.shape

此解决方案在future_panel = historical_data_2d[np.arange(sim_count)[:, np.newaxis], random_days_panel]->处停止,错误是:NotImplementedError: Don't yet support nd fancy indexing

所以我的问题是,有什么方法可以实现与numpy代码相同的行为?但是我当然希望获得更好的性能(即更快的执行时间)

1 个答案:

答案 0 :(得分:0)

您可以尝试以下操作:

>>> import numpy as np
>>> import dask.array as da
>>> d = np.arange(10)
>>> d
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> x = da.from_array(d, chunks=(10))
>>> x
dask.array<array, shape=(10,), dtype=int32, chunksize=(10,)>

我已阅读文档:Reference

希望这会帮助你。