Python 在多个点上计算多个单项式
以下问题涉及在多个点上计算许多单项式(Python 在多个点上计算多个单项式,python,arrays,numpy,Python,Arrays,Numpy,以下问题涉及在多个点上计算许多单项式(x**k*y**l*z**m) 我想计算两个numpy数组的“内能”,即 import numpy a = numpy.random.rand(10, 3) b = numpy.random.rand(3, 5) out = numpy.ones((10, 5)) for i in range(10): for j in range(5): for k in range(3): out[i, j] *= a
x**k*y**l*z**m
)
我想计算两个numpy数组的“内能”,即
import numpy
a = numpy.random.rand(10, 3)
b = numpy.random.rand(3, 5)
out = numpy.ones((10, 5))
for i in range(10):
for j in range(5):
for k in range(3):
out[i, j] *= a[i, k]**b[k, j]
print(out.shape)
如果相反,该行将显示
out[i, j] += a[i, k]*b[j, k]
这将是许多内积,可以用一个简单的dot
或einsum
计算
是否可以在一条numpy行中执行上述循环?您可以在将这些数组扩展到3D
版本后使用-
(a[:,:,None]**b[None,:,:]).prod(axis=1)
简而言之-
(a[...,None]**b[None]).prod(1)
基本上,我们保持两个阵列的最后一个轴和第一个轴对齐,同时在两个输入的第一个轴和最后一个轴之间执行元素级幂运算。使用给定的示例示意性地放置在形状上-
10 x 3 x 1
1 x 3 x 5
从对数的角度来考虑呢
import numpy
a = numpy.random.rand(10, 3)
b = numpy.random.rand(3, 5)
out = np.exp(np.matmul(np.log(a), b))
既然c_ij=prod(a_ik**b_kj,k=1..k)
,那么log(c_ij)=sum(log(a_ik)*b_ik,k=1..k)
注意:a
中的零可能会弄乱结果(也可能是负数,但结果无论如何也不会很好地定义)。我试了一下,但它似乎并没有真的断裂;我不知道NumPy是否保证这种行为,但为了安全起见,您可以在末尾添加一些内容,如:
out[np.logical_or.reduce(a < eps, axis=1)] = 0
out[np.logical\u或.reduce(a
还有两种解决方案:
内联
numpy.array([
numpy.prod([a[:, i]**bb[i] for i in range(len(bb))], axis=0)
for bb in b.T
]).T
并使用power.outer
:
numpy.prod([numpy.power.outer(a[:, k], b[k]) for k in range(len(b))], axis=0)
两者都比广播解决方案慢一点
即使有一些逻辑来适应零值和负值,exp
-log
解决方案也占了上风
复制绘图的代码:
import numpy
import perfplot
def loop(data):
a, b = data
m = a.shape[0]
n = b.shape[1]
out = numpy.ones((m, n))
for i in range(m):
for j in range(n):
for k in range(3):
out[i, j] *= a[i, k]**b[k, j]
return out
def broadcasting(data):
a, b = data
return (a[..., None]**b[None]).prod(1)
def log_exp(data):
a, b = data
neg_a = numpy.zeros(a.shape, dtype=int)
neg_a[a < 0.0] = 1
odd_b = numpy.zeros(b.shape, dtype=int)
odd_b[b % 2 == 1] = 1
negative_count = numpy.dot(neg_a, odd_b)
out = (-1)**negative_count * numpy.exp(
numpy.matmul(
numpy.log(abs(a), where=abs(a) > 0.0),
b
))
zero_a = numpy.zeros(a.shape, dtype=int)
zero_a[a == 0.0] = 1
pos_b = numpy.zeros(b.shape, dtype=int)
pos_b[b > 0] = 1
zero_count = numpy.dot(zero_a, pos_b)
out[zero_count > 0] = 0.0
return out
def inline(data):
a, b = data
return numpy.array([
numpy.prod([a[:, i]**bb[i] for i in range(len(bb))], axis=0)
for bb in b.T
]).T
def outer_power(data):
a, b = data
return numpy.prod([
numpy.power.outer(a[:, k], b[k]) for k in range(len(b))
], axis=0)
perfplot.show(
setup=lambda n: (
numpy.random.rand(n, 3) - 0.5,
numpy.random.randint(0, 10, (3, n))
),
n_range=[2**k for k in range(11)],
repeat=10,
kernels=[
loop,
broadcasting,
inline,
log_exp,
outer_power
],
logx=True,
logy=True,
xlabel='len(a)',
)
导入numpy
导入性能图
def循环(数据):
a、 b=数据
m=a.shape[0]
n=b.形状[1]
out=numpy.one((m,n))
对于范围内的i(m):
对于范围(n)内的j:
对于范围(3)内的k:
out[i,j]*=a[i,k]**b[k,j]
返回
def广播(数据):
a、 b=数据
返回(a[…,无]**b[无]).prod(1)
def log_exp(数据):
a、 b=数据
neg_a=numpy.zeros(a.shape,dtype=int)
负α[a<0.0]=1
奇数b=numpy.zero(b.shape,dtype=int)
奇数b[b%2==1]=1
负计数=整数点(负a,奇数b)
out=(-1)**负计数*numpy.exp(
努比·马特穆尔(
numpy.log(abs(a),其中=abs(a)>0.0),
B
))
zero_a=numpy.zeros(a.shape,dtype=int)
零a[a==0.0]=1
pos_b=numpy.zero(b.shape,dtype=int)
位置b[b>0]=1
零计数=整数点(零a,位置b)
out[零计数>0]=0.0
返回
def内联(数据):
a、 b=数据
返回numpy.array([
numpy.prod([a[:,i]**bb[i]表示范围内的i(len(bb))],轴=0)
b.T.中的bb
])T
def外部动力(数据):
a、 b=数据
return numpy.prod([
范围(len(b))内k的整数幂外(a[:,k],b[k])
],轴=0)
perfplot.show(
设置=λn:(
numpy.random.rand(n,3)-0.5,
numpy.random.randint(0,10,(3,n))
),
n_范围=[2**k表示范围(11)中的k],
重复10次,
果仁=[
环
广播,
内联,
log_exp,
外电源
],
logx=True,
逻辑=正确,
xlabel='len(a)',
)
从美学角度来说,我真的很喜欢这个答案。而且非常快地利用了matmul
!我想问题在于a>1
@Divakar witha>1
?在这种情况下会出现什么问题?这里有一个ideone运行-输出是最大绝对差异误差。
import numpy
a = numpy.random.rand(10, 3)
b = numpy.random.rand(3, 5)
out = [[numpy.prod([a[i, k]**b[k, j] for k in range(3)]) for j in range(5)] for i in range(10)]