Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何通过多维数组优化循环?_Python - Fatal编程技术网

Python 如何通过多维数组优化循环?

Python 如何通过多维数组优化循环?,python,Python,在Python3上收集了一些3D netCDF数据之后,我正在遍历每个x,y数据点来计算另一个变量。该变量的计算取决于给定x,y点的z。代码似乎运行正常,但速度非常慢;我想知道是否有人对如何优化代码以使其运行得更快提出了建议 我已经从一段较长的代码(定义了许多中间变量)变成了一些非常简单的东西,如图所示。即使在修剪代码之后,它也会缓慢运行(即,外部for循环中的每个i都会运行几分钟) 范围(0217)内的i的: 印刷品(一) 对于范围(0301)内的j: 对于范围(10,30)内的k: 如果(d

在Python3上收集了一些3D netCDF数据之后,我正在遍历每个x,y数据点来计算另一个变量。该变量的计算取决于给定x,y点的z。代码似乎运行正常,但速度非常慢;我想知道是否有人对如何优化代码以使其运行得更快提出了建议

我已经从一段较长的代码(定义了许多中间变量)变成了一些非常简单的东西,如图所示。即使在修剪代码之后,它也会缓慢运行(即,外部for循环中的每个i都会运行几分钟)

范围(0217)内的i的
:
印刷品(一)
对于范围(0301)内的j:
对于范围(10,30)内的k:

如果(data.variables[longvars[v][2][0][k][i][j]-data.variables[longvars[v][3][0][i][j])逻辑看起来不错,但我们可以使用生成器和理解进一步优化它

让我们将内部逻辑隔离到一个名为
findZValue
的函数中

def findZValue(v, i, j, variables, longvars, np):
如果我读错了,请原谅,但看起来您正在试图找到最接近3000的值的索引?如果是这样,首先我们将创建一个生成器,返回一个元组,其中包含索引和“variable-variable-3000”的绝对值:

为了获得我们想要的值,我们将整个内容包装在一个
min
函数中(该键表示我们希望它按第二个值排序),并指定我们想要获得索引(即
min
返回的元组中的第一个值):

对于输入到“newd”中的值,它看起来像是取平方和的根(即,其规格化或大小)。幸运的是,numpy(我假设“np”是什么)有一个内置的方法来查找数组的大小/规格化:np.linalg.norm。我们所要做的就是将其他值放入np.array中,然后调用它们:

def findZValue(v, i, j, variables, longvars, np):
    lev = min(((k, abs(variables[longvars[v][2]][0][k][i][j] - variables[longvars[v][3]][0][i][j] - 3000)) for k in range(10, 30)), key = lambda t: t[1])[0]
    return np.linalg.norm(np.array(variables[longvars[v][0]][0][lev][i][j]-variables[longvars[v][4]][0][0][i][j], variables[longvars[v][1]][0][lev][i][j]-variables[longvars[v][5]][0][0][i][j]))
现在,我们可以将整个循环放入嵌套理解中:

newd = [[findZValue(v, i, j, data.variables, longvars, np) for j in range(301)] for i in range(217)]

def findZValue(v, i, j, variables, longvars, np):
    lev = min(((k, abs(variables[longvars[v][2]][0][k][i][j] - variables[longvars[v][3]][0][i][j] - 3000)) for k in range(10, 30)), key = lambda t: t[1])[0]

    return np.linalg.norm(np.array(variables[longvars[v][0]][0][lev][i][j]-variables[longvars[v][4]][0][0][i][j], variables[longvars[v][1]][0][lev][i][j]-variables[longvars[v][5]][0][0][i][j]))
使用生成器和理解应该比使用for循环更快。但是如果你真的想把事情搞糟,我们可以使用“多处理”。具体来说,是一个多处理池。为此,我们需要创建第二个函数来处理每个向量(这是由于对多处理池工作方式的限制):


您可以更改为池创建的“进程”的数量,以查看什么可以提供最佳结果。

逻辑看起来很合理,但我们可以使用生成器和理解进一步优化它

让我们将内部逻辑隔离到一个名为
findZValue
的函数中

def findZValue(v, i, j, variables, longvars, np):
如果我读错了,请原谅,但看起来您正在试图找到最接近3000的值的索引?如果是这样,首先我们将创建一个生成器,返回一个元组,其中包含索引和“variable-variable-3000”的绝对值:

为了获得我们想要的值,我们将整个内容包装在一个
min
函数中(该键表示我们希望它按第二个值排序),并指定我们想要获得索引(即
min
返回的元组中的第一个值):

对于输入到“newd”中的值,它看起来像是取平方和的根(即,其规格化或大小)。幸运的是,numpy(我假设“np”是什么)有一个内置的方法来查找数组的大小/规格化:np.linalg.norm。我们所要做的就是将其他值放入np.array中,然后调用它们:

def findZValue(v, i, j, variables, longvars, np):
    lev = min(((k, abs(variables[longvars[v][2]][0][k][i][j] - variables[longvars[v][3]][0][i][j] - 3000)) for k in range(10, 30)), key = lambda t: t[1])[0]
    return np.linalg.norm(np.array(variables[longvars[v][0]][0][lev][i][j]-variables[longvars[v][4]][0][0][i][j], variables[longvars[v][1]][0][lev][i][j]-variables[longvars[v][5]][0][0][i][j]))
现在,我们可以将整个循环放入嵌套理解中:

newd = [[findZValue(v, i, j, data.variables, longvars, np) for j in range(301)] for i in range(217)]

def findZValue(v, i, j, variables, longvars, np):
    lev = min(((k, abs(variables[longvars[v][2]][0][k][i][j] - variables[longvars[v][3]][0][i][j] - 3000)) for k in range(10, 30)), key = lambda t: t[1])[0]

    return np.linalg.norm(np.array(variables[longvars[v][0]][0][lev][i][j]-variables[longvars[v][4]][0][0][i][j], variables[longvars[v][1]][0][lev][i][j]-variables[longvars[v][5]][0][0][i][j]))
使用生成器和理解应该比使用for循环更快。但是如果你真的想把事情搞糟,我们可以使用“多处理”。具体来说,是一个多处理池。为此,我们需要创建第二个函数来处理每个向量(这是由于对多处理池工作方式的限制):


您可以更改为池创建的“进程”的数量,以查看什么能给您带来最好的结果。

感谢您的详细回复!当包含多处理函数时,我收到一个错误:“变量[指netCDF4变量,data.variables]不可拾取”。是否应首先将其转换为数组?@donutwx对延迟回复表示歉意。只要相关数据保持不变,我会说是的。“不可拾取”只是意味着对象很复杂(可能有对其他对象的引用),因此无法转换为简单的串行对象,以便
map
处理。由于我们所关心的只是data.variables中的值,因此将其转换为数组,然后传递所述值仍然可以得到您想要的结果。感谢您的详细回复!当包含多处理函数时,我收到一个错误:“变量[指netCDF4变量,data.variables]不可拾取”。是否应首先将其转换为数组?@donutwx对延迟回复表示歉意。只要相关数据保持不变,我会说是的。“不可拾取”只是意味着对象很复杂(可能有对其他对象的引用),因此无法转换为简单的串行对象,以便
map
处理。由于我们所关心的只是data.variables中的值,因此将其转换为数组,然后传递所述值仍然可以得到所需的结果。
from multiprocessing import Pool

def findZValue(v, i, j, variables, longvars, np):
    lev = min(((k, abs(variables[longvars[v][2]][0][k][i][j] - variables[longvars[v][3]][0][i][j] - 3000)) for k in range(10, 30)), key = lambda t: t[1])[0]

    return np.linalg.norm(np.array(variables[longvars[v][0]][0][lev][i][j]-variables[longvars[v][4]][0][0][i][j], variables[longvars[v][1]][0][lev][i][j]-variables[longvars[v][5]][0][0][i][j]))

def findZValuesForVector(vector):
    return [findZValue(*values) for values in vector]

with Pool(processes=4) as pool:
    newd = pool.map(findZValuesForVector, [[[v, i, j, data.variables, longvars, np] for j in range(301)] for i in range(217)])