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 with
a>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)]