以下代码有效。但是,计算rez的行很可能不是按照numpy开发人员的预期方式编写的。如何在不转换到列表和从列表转换的情况下以高效的方式重写它?
另外,如果你碰巧知道如何在python中编写数学函数的好指南,这对数字和np.arrays同样有用,请分享:)
import numpy as np
from matplotlib import pyplot as plt
def L2normSquared(X, Y, x, y):
return sum((X-x)**2 + (Y-y)**2)
X = np.random.normal(0, 1, 10)
Y = np.random.normal(0, 1, 10)
PX = np.arange(-1, 1, 0.1)
PY = np.arange(-1, 1, 0.1)
PXm, PYm = np.meshgrid(PX, PY)
rez = np.array([[L2normSquared(X, Y, x, y) for y in PY] for x in PX])
print(rez.shape)
plt.imshow(rez, cmap='jet', interpolation='nearest', origin='lower', extent=[-1, 1, -1, 1])
plt.show()
修改:让我解释一下我要做的事情
我在2D中生成10个随机点。然后我为2D中的任意点(x,y)定义一个损失函数。该函数的结果是所有10个固定点与该任意点的欧几里德距离之和。最后,我想用2d imshow方法绘制这个损失函数
编辑2 :根据Nils Werner的回答,可以使用3D数组和广播,生成以下代码
import numpy as np
from matplotlib import pyplot as plt
def L2normSquared(X, Y, x, y):
return np.sum((X-x)**2 + (Y-y)**2, axis=0)
X = np.random.normal(0, 1, 10)
Y = np.random.normal(0, 1, 10)
PX = np.arange(-1, 1, 0.1)
PY = np.arange(-1, 1, 0.1)
PXm, PYm = np.meshgrid(PX, PY)
rez = L2normSquared(X[:, None, None], Y[:, None, None], PXm, PYm)
print(rez.shape)
plt.imshow(rez, cmap='jet', interpolation='nearest', origin='lower', extent=[-1, 1, -1, 1])
plt.show()
然而,这段代码实际上比列表理解慢(对于10000随机坐标,步骤0.01,它大约慢2-3倍)。对于更大的输入,存在内存崩溃,这使我相信此方法在内部导致3D阵列动态编程,这在内存分配方面不能很好地扩展。
编辑3 : 我很抱歉,但我的最小例子太少了。在我面临的原始问题中,坐标X和Y不会解耦以允许它们单独计算。其中一个原始功能是
def gaussian(X, Y, x, y):
return sum(np.exp(-(X-x)**2 -(Y-y)**2))
答案 0 :(得分:1)
meshgrid
背后的想法是你得到两个或更多的数组,你可以自己简单地传递给一个操作。理想情况下,我们根本不需要for循环。
但是,因为你正在做一个"外部差异"在X
和PX
之间,在X
轴上进行求和后,您还需要使用broadcasting来首先执行外部产品,最后总结正确的轴:
import numpy as np
from matplotlib import pyplot as plt
def L2normSquared(X, Y, x, y):
return np.sum((X-x)**2 + (Y-y)**2, axis=0)
X = np.random.normal(0, 1, 10)
Y = np.random.normal(0, 1, 10)
PX = np.arange(-1, 1, 0.1)
PY = np.arange(-1, 1, 0.1)
PXm, PYm = np.meshgrid(PX, PY)
rez = L2normSquared(X[:, None, None], Y[:, None, None], PXm, PYm)
答案 1 :(得分:1)
更系统的方法是将总和与规范区分开来,因为你的
L2normSquared
函数无法查看x
vs X
的特定角色。
def normSquared(X, Y, x, y):
return (X-x)**2 + (Y-y)**2
X = np.random.normal(0, 1, 10)
Y = np.random.normal(0, 1, 10)
x = y = np.arange(-1, 1, 0.1)
rez=normSquared(*np.meshgrid(X,Y,x,y)).sum(axis=(0,1))
normedSquared
了解数组和数字,sum
这里含糊不清。
无需重新发明meshgrid
。
修改强>
要推迟记忆问题,你可以提前求和,以及稀疏网格:
n=1000000
X = np.random.normal(0, 1, n)
Y = np.random.normal(0, 1, n)
x = np.arange(-1, 1, 0.1)
y = np.arange(-1, 1, 0.1)
Xm,Ym,xm,ym = mesh = np.meshgrid(X,Y,x,y,sparse=True)
rez=((Xm-xm)**2).sum((0,1))+((Ym-ym)**2).sum((0,1))
这可以在1秒内解决问题,因为n = 1,000,000。
答案 2 :(得分:1)
使用Images.xcassets
魔法与numpy.dot
同时提高内存效率和性能而不会弄乱matrix-multiplication
,就像这样 -
meshgrids
<强>基准强>
方法和相关功能 -
a = np.exp(-(PX[:,None]-X)**2)
b = np.exp(-(PY[:,None]-Y)**2)
out = a.dot(b.T)
计时和验证 -
def gaussian(X, Y, x, y):
return sum(np.exp(-(X-x)**2 -(Y-y)**2))
def org_method(PX, X, PY, Y):
PXm, PYm = np.meshgrid(PX, PY)
return np.array([[gaussian(X, Y, x, y) for y in PY] for x in PX])
def matmult_method(PX, X, PY, Y):
a = np.exp(-(PX[:,None]-X)**2)
b = np.exp(-(PY[:,None]-Y)**2)
return a.dot(b.T)
因此,我们正在加速 In [256]: X = np.random.normal(0, 1, 1000)
...: Y = np.random.normal(0, 1, 1000)
...:
...: PX = np.arange(-1, 1, 0.01)
...: PY = np.arange(-1, 1, 0.01)
In [257]: np.allclose(org_method(PX, X, PY, Y), matmult_method(PX, X, PY, Y))
Out[257]: True
In [258]: %timeit org_method(PX, X, PY, Y)
1 loop, best of 3: 3.76 s per loop
In [259]: %timeit matmult_method(PX, X, PY, Y)
100 loops, best of 3: 12.2 ms per loop
。