我目前有一个输入网格和函数,我想传递到网格的每个元素(取决于原始网格的维数)。问题是,我目前有几种不同的传递函数的实现,取决于维度,我想找到一种更好的实现方法。以下是一些例子:
import numpy as np
# 1D
grid1 = np.array(
[ 1, 2, 3]
)
# Function
foo1 = lambda x: x**2
print(grid1.shape)
print(len(grid1.shape))
f_grid1 = np.zeros_like(grid1)
for i in range(grid1.shape[0]):
f_grid1[i] = foo1(grid1[i])
print(f_grid1)
# 2D
grid2 = np.array(
[
[[1, 0.1], [1, 0.2], [1, 0.3]],
[[2, 0.1], [2, 0.2], [2, 0.3]],
[[3, 0.1], [3, 0.2], [3, 0.3]],
[[4, 0.1], [4, 0.2], [4, 0.3]]
]
)
# Function
foo2 = lambda x, y: x**2 - y
print(grid2.shape)
print(len(grid2.shape))
bins = grid2.shape[0] # bins will always the same between dimensions.
f_grid2 = np.empty(grid2.shape[:-1], dtype=np.float64)
for i in range(grid2.shape[0]):
for j in range(grid2.shape[1]):
f_grid2[i, j] = foo2(grid2[i, j, 0], grid2[i, j, 1])
print(f_grid2)
# 3D
grid3 = np.array(
[
[ [[1, 0.1, 0.0001], [1, 0.2, 0.0001], [1, 0.3, 0.0001]],
[[2, 0.1, 0.0001], [2, 0.2, 0.0001], [2, 0.3, 0.0001]],
[[3, 0.1, 0.0001], [3, 0.2, 0.0001], [3, 0.3, 0.0001]] ],
[ [[1, 0.1, 0.0002], [1, 0.2, 0.0002], [1, 0.3, 0.0002]],
[[2, 0.1, 0.0002], [2, 0.2, 0.0002], [2, 0.3, 0.0002]],
[[3, 0.1, 0.0002], [3, 0.2, 0.0002], [3, 0.3, 0.0002]] ],
[ [[1, 0.1, 0.0003], [1, 0.2, 0.0003], [1, 0.3, 0.0003]],
[[2, 0.1, 0.0003], [2, 0.2, 0.0003], [2, 0.3, 0.0003]],
[[3, 0.1, 0.0003], [3, 0.2, 0.0003], [3, 0.3, 0.0003]] ],
]
)
# Function
foo3 = lambda x, y, z: x**2 - y + z
bins = grid3.shape[0] # bins will always the same between dimensions.
print(grid3.shape)
print(len(grid3.shape))
f_grid3 = np.empty(grid3.shape[:-1], dtype=np.float64)
for i in range(grid3.shape[0]):
for j in range(grid3.shape[1]):
for k in range(grid3.shape[2]):
f_grid3[i, j, k] = foo3(grid3[i, j, k, 0], grid3[i, j, k, 1], grid3[i, j, k, 2])
print(f_grid3)
如何将其扩展到任意维度?以上各项的产出如下:
(3,)
1
[1 4 9]
(4, 3, 2)
3
[[ 0.9 0.8 0.7]
[ 3.9 3.8 3.7]
[ 8.9 8.8 8.7]
[15.9 15.8 15.7]]
(3, 3, 3, 3)
4
[[[0.9001 0.8001 0.7001]
[3.9001 3.8001 3.7001]
[8.9001 8.8001 8.7001]]
[[0.9002 0.8002 0.7002]
[3.9002 3.8002 3.7002]
[8.9002 8.8002 8.7002]]
[[0.9003 0.8003 0.7003]
[3.9003 3.8003 3.7003]
[8.9003 8.8003 8.7003]]]
目前,我认为最终的函数看起来像:
def apply_function(grid, func):
shape = grid.shape
if len(shape) == 1:
grid = grid[np.newaxis].T
out_grid = np.empty(grid.shape[:-1], dtype=np.float64)
# calculate the corresponding out_grid here
1条答案
按热度按时间xdnvmnnf1#
正如我在评论最近类似的问题时所说(我记得@hpaulj也评论过),真正的问题是:你真的需要这个吗你必须意识到,无论是否特定于维度,任何将python函数应用于数组的所有元素的方法都将是非常低效的方法。这是否定整个麻木点。整个numpy点是如何不这样做(经验法则:如果你有一个
for
循环,你可能做错了)在你的例子中
是应用于整个向量的方式,而不需要for循环(至少不需要显式循环)。显然,它们被numpy代码中的隐式代码所取代。但这些都是C语言,所以速度更快)。
还要注意的是,你似乎把数组的维数(也就是你要应用foo的N × N × N数据的维数k)和foo函数的变量数对齐了。这可能有一个应用的原因(我们不知道,这是你的应用)。但没有数学或无聊的理由。
例如,1D网格可以包含x,y,z值,如下所示:
其可以沿着1维阵列应用。要么与
用你的方法或者与
使用我的(好吧,这不是我的:每个人都在做同样的事情)。所以,你想调整代码的不是网格的维数,而是foo函数的变量数(也就是网格最后一个轴的大小,换句话说,也不是强制的其他维数)
同样,如果函数是向量化的(并且你所有的例子都是;大多数数学函数只从一堆独立的标量中返回一个标量),那么,适应网格的维数根本不是问题;你什么都没做这已经被矢量化处理了。矢量化函数不关心它们是否应用于标量,一维数组,二维数组等。他们只是重复所有数据沿所有轴所需的时间。
例如,1参数函数foo可以应用于3D网格的所有数据:
无论网格的尺寸如何
所以,让我们忘记一次你的目标网格的维数。要关注你的函数的变量的数量,也就是说,在多个一维网格中,最后一个轴的大小。好吧,让我们不要忘记它,因为尽管如此,第二个问题(事实上K个变量是沿着最后一个轴),导致了一个问题(代码是不完全相同的取决于维数N-再次没有理由假设N = K:我们需要在代码中N
:
)但是@hpaulj给出了摆脱那些N
:
的方法。将我的3个示例的初始代码替换为你看,现在维数N没有影响。只有最后一个轴的大小K,即参数的数量。除了1D的情况,这是不同的。我们更愿意称之为
坚持相同的模式。这很容易解决:确保在1D情况下,网格是2D阵列(尺寸为1作为最后一个轴),与您的3D示例完全相同,网格是一个4D阵列(以尺寸3作为最后一个轴),或者一般来说,在K个参数的函数的情况下,生成N维的网格,
grid
是(N +1)D数组,最后一个轴的大小为K(在所有K = N的例子中,大小为N)。因为你保证了。或者是因为我们添加了一个代码来处理那个特殊的情况
这段代码的第一行添加了一个假的、大小为1的轴,当网格是1D时,这样,和所有其他示例一样,网格有1个额外的维度来保存K个变量。
现在,你可以看到共同的模式开始变得明显。
我们可以用这种方法产生所有维度的呼叫
这与参数的数量
K=grid.shape[-1]
和维数无关。我知道,我说了“不要循环”。但这一点并不重要:它仅沿着
foo
的参数的数量迭代。除非你缩进一个foo
函数,它有无数的参数(在这种情况下,你有一个问题),否则for循环是可以忽略的。它不迭代数据。只是数据的维度。它只是1、2或3次迭代。