Python 生成大型模拟并将同一阵列多次插入不同位置的另一阵列

Python 生成大型模拟并将同一阵列多次插入不同位置的另一阵列,python,arrays,pandas,numpy,numba,Python,Arrays,Pandas,Numpy,Numba,我正在为油井进行蒙特卡罗模拟。最终目标是使所有油井具有平滑的概率生产曲线。我已经尽我所能优化了,但是当我使用我的完整数据集和我想要的模拟数量时,我列出的3条apply语句中的每一条都花费了很多时间。(小时)我包含的代码有10次迭代。如果你把它提高到10000,这是目标,它真的开始拖 我已经生成了一个熊猫,它拥有我想要建模的所有未来油井,并且有可能选择下一个要钻探的油井 然后我创建了一个panda,在这里我将所有的东西都分为我想要用来计算模型选择井的顺序的类别。所以我的“计时”熊猫包含了我的分类,

我正在为油井进行蒙特卡罗模拟。最终目标是使所有油井具有平滑的概率生产曲线。我已经尽我所能优化了,但是当我使用我的完整数据集和我想要的模拟数量时,我列出的3条apply语句中的每一条都花费了很多时间。(小时)我包含的代码有10次迭代。如果你把它提高到10000,这是目标,它真的开始拖

我已经生成了一个熊猫,它拥有我想要建模的所有未来油井,并且有可能选择下一个要钻探的油井

然后我创建了一个panda,在这里我将所有的东西都分为我想要用来计算模型选择井的顺序的类别。所以我的“计时”熊猫包含了我的分类,以及这些分类中的每一个油井指数的数组,以及油井概率的数组

这一切都在几秒钟内完成。下一部分工作正常,但速度非常慢

接下来,我使用一个带有百分比的numpy生成器选项来随机生成用于I模拟的井的顺序。正如其他帖子所指出的,@njit不适用于概率数组。结果是,阵列的1维是每个类别选择井的顺序,另一维是每个模拟。大约有150个类别,每个类别中有10000口井。我希望运行10000次模拟

  • a是可以选择的油井索引数组
  • size是该数组的长度
  • per是每口井被选中的概率
接下来,我把我的计时熊猫和我的熊猫连接起来,所有的井都在里面。这会将上一个数组附加到wells数组。然后我在这个数组中搜索油井索引,以确定每次模拟的具体油井何时开始运行。这将生成一个一维阵列,该阵列在每次模拟中的钻井顺序

这个函数在100000个井上被调用,随着我增加模拟的数量,它的速度真的变慢了

  • 顺序是每个模拟钻井顺序的数组
  • 指数是那口井的指数
我遇到的最后一个困难是平均出油井的生产曲线。我有每月每口井的产油量。我需要在钻井时将该曲线插入阵列中的每个点,然后将所有这些值相加求平均值,以获得给定所有模拟的油井平均产量

我还尝试过使用np.insert函数创建一个np.zeros数组,但我无法想出如何在没有循环的情况下多次插入数组,并且生成0的初始数组所花费的时间比我目前使用的方法更长。(我克服了多次插入数组的困难,将所有内容都覆盖到一个字符串中,将类型曲线作为一个字符串插入,然后再转换回一个数字数组,但这似乎并不有效)。我需要有前导0的编号

  • 订单是每口井钻井的时间(以月为单位)
  • 曲线是作为列表传递的生产曲线
  • m是所有模拟中钻井月份的最高值
谢谢你能提供的任何帮助。如果你能想出任何方法来加速我的代码,我愿意对其进行重大修改。不确定是否有更好的方法应用概率并平滑生产曲线,这才是最终目标


干杯。

这显然是一个经过充分研究的问题,但它不是最小的或可复制的。如果我是你,我会分析代码,找到瓶颈并提出相关问题,包括一些其他人可以使用的虚假数据。从更实际的角度来看,
np。选择
可能很慢,无需更换。请参阅,了解一种可能的解决方法。最后一件事-将numba装饰器应用于诸如TimingGenerator或OrderGenerator之类的高级函数可能会增加很少的速度,甚至会使程序变慢。Numba无法神奇地重写numpy代码以提高效率。你可以在有或没有装饰器的情况下测试每一个函数,看看什么最有效。谢谢@hilberts\u。我使用了jit,你在其中两个函数上都是正确的,速度稍微慢了一点。不过,我可以申请njit的速度要快得多。我为随机选择更新了np.generator,它确实将10000次模拟的速度从9分钟提高到了8分钟。我还试图得到一套工作的代码。不确定它是否符合您的标准。干杯
import numpy as np
from numba import njit
import datetime
import math

def TimingGenerator(a, size, p):
  i = 10
  g = np.random.Generator(np.random.PCG64())
  order = np.concatenate([g.choice(a=a, size=size, replace=False, p=p) for z in range(i)]).reshape(i, size)
  return order

@njit
def OrderGenerator(order, index):
  result = np.where(order == index)[1]
  return result

def CurveAverager(order, curve, m):
  matrix = np.array([[0] * math.ceil(i) + curve + [0] * int((m - math.ceil(i))) for i in order])
  result = np.mean(matrix, axis=0)
  return result

begin_time = datetime.datetime.now()

size = 8000
g = np.random.Generator(np.random.PCG64())
a = g.choice(20_000, size=size, replace=False)
p = np.random.randint(1,100, size=size)
p = p/np.sum(p)

for i in range(150):
  q = TimingGenerator(a,size,p)

print(datetime.datetime.now() - begin_time)

index = np.amin(q)
for i in range(100000):
  order = OrderGenerator(q, index)

print(datetime.datetime.now() - begin_time)

order = order / 15
curve = list(range(600, 0, -1))

for i in range(20000):
  avgcurve = CurveAverager(order, curve, size)

print(datetime.datetime.now() - begin_time)