Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/303.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 einsum椭圆的终极灵活性_Python_Numpy_Ellipsis_Numpy Einsum - Fatal编程技术网

Python einsum椭圆的终极灵活性

Python einsum椭圆的终极灵活性,python,numpy,ellipsis,numpy-einsum,Python,Numpy,Ellipsis,Numpy Einsum,我有一个关于einsum省略号的问题,我想它肯定会出现在StackExchange的某个地方,但不知怎么的,我似乎找不到 本质上,我有一些代码,它使用numpy的einsum进行大量的矩阵和向量压缩。输入通常是一些用于创建向量和矩阵的参数。代码运行良好,但现在我想对其进行概括,以便可以在一定范围内扫描输入参数。最好的办法是使它们成为向量,并修改我的einsum表达式,这样它们就可以接受任意数量的附加维度,而这些维度只需简单地执行即可。这个问题是问这是否可能,如果可能,如何实现 所以在我看来,这

我有一个关于einsum省略号的问题,我想它肯定会出现在StackExchange的某个地方,但不知怎么的,我似乎找不到

本质上,我有一些代码,它使用numpy的
einsum
进行大量的矩阵和向量压缩。输入通常是一些用于创建向量和矩阵的参数。代码运行良好,但现在我想对其进行概括,以便可以在一定范围内扫描输入参数。最好的办法是使它们成为向量,并修改我的
einsum
表达式,这样它们就可以接受任意数量的附加维度,而这些维度只需简单地执行即可。这个问题是问这是否可能,如果可能,如何实现


所以在我看来,这个问题归结为以下几点。假设我有一个
einsum
表达式,它创建了某种矩阵乘法,例如

c = np.einsum('ij,jk->ik', a, b)
现在我想在a和b中添加任意数量的索引,并简单地将它们作为额外的索引添加到最终矩阵中,例如

c = np.einsum('ijabc,jkde->ikabcde', a, b)
现在,当你只对a或b中的一个这样做时,你可以通过省略号很容易地做到这一点

c = np.einsum('ij...,jk->ik...', a, b)
所以我的问题是在
einsum
中是否可以有多个省略号,例如

c = np.einsum('ij...,jk...->ik...', a, b)
这当然会带来一个错误,但希望从示例中可以清楚地看出我的意思

einsum是否支持这种“多省略号”表示法?或者有没有其他方法可以在不循环的情况下实现此功能?


我的猜测是没有这样的方法,因为人们必须告诉einsum以什么顺序放置剩余的索引,也就是说,人们必须以某种方式标记椭圆。

由于没有要对齐的轴,我们可以简单地使用
tensordot
,让不参与求和的轴对齐使用附加的
滚动轴
“展开”,如下所示-

np.rollaxis(np.tensordot(a,b,axes=(1,0)),a.ndim-1,1)
如果您想使用
einsum
,我们可以将其重塑为
3D
,这样它们的最后一个轴就是合并的轴(第三个轴向前合并为一个轴),然后继续执行
einsum
,最后重塑回输出中展开的
ndim-1
形状,类似这样-

shp_a = a.shape
shp_b = b.shape
shp_a[:1] + shp_a[2:]
out_shp = shp_a[:1] + (shp_b[1],) + shp_a[2:] + shp_b[2:]

a3D = a.reshape(shp_a[:2]+(-1,))
b3D = b.reshape(shp_b[:2]+(-1,))
out = np.einsum('ijk,jlm->ilkm',a3D,b3D).reshape(out_shp)
import string

def einsum_spreadout(a,b,a_axes,b_axes,a_spread_axis,b_spread_axis):
    from numpy.core import numerictypes as nt

    if isinstance(a_axes, (int, nt.integer)):
        a_axes = (a_axes,)

    if isinstance(b_axes, (int, nt.integer)):
        b_axes = (b_axes,)

    s = string.ascii_letters

    a_str = s[:a.ndim]
    b_str = s[a.ndim:a.ndim+b.ndim]

    b_str_ar = np.frombuffer(b_str,dtype='S1').copy()
    for (i,j) in zip(a_axes,b_axes):
        b_str_ar[j] = a_str[i]
    b_str = ''.join(b_str_ar)    

    out_str = a_str[:a_spread_axis] + b_str[:b_spread_axis]
    out_str += a_str[a_spread_axis:] + b_str[b_spread_axis:]

    out_str_ar = np.frombuffer(out_str,dtype='S1').copy()
    out_str = ''.join(out_str_ar[~np.isin(out_str_ar,np.take(b_str_ar,b_axes))])
    einsum_str = a_str+','+b_str+'->'+out_str

    return np.einsum(einsum_str,a,b)
我们还可以生成相应的einsum字符串表示法本身,从而跳过所有数组操作,从而专注于字符串操作本身,以获得类似的结果-

shp_a = a.shape
shp_b = b.shape
shp_a[:1] + shp_a[2:]
out_shp = shp_a[:1] + (shp_b[1],) + shp_a[2:] + shp_b[2:]

a3D = a.reshape(shp_a[:2]+(-1,))
b3D = b.reshape(shp_b[:2]+(-1,))
out = np.einsum('ijk,jlm->ilkm',a3D,b3D).reshape(out_shp)
import string

def einsum_spreadout(a,b,a_axes,b_axes,a_spread_axis,b_spread_axis):
    from numpy.core import numerictypes as nt

    if isinstance(a_axes, (int, nt.integer)):
        a_axes = (a_axes,)

    if isinstance(b_axes, (int, nt.integer)):
        b_axes = (b_axes,)

    s = string.ascii_letters

    a_str = s[:a.ndim]
    b_str = s[a.ndim:a.ndim+b.ndim]

    b_str_ar = np.frombuffer(b_str,dtype='S1').copy()
    for (i,j) in zip(a_axes,b_axes):
        b_str_ar[j] = a_str[i]
    b_str = ''.join(b_str_ar)    

    out_str = a_str[:a_spread_axis] + b_str[:b_spread_axis]
    out_str += a_str[a_spread_axis:] + b_str[b_spread_axis:]

    out_str_ar = np.frombuffer(out_str,dtype='S1').copy()
    out_str = ''.join(out_str_ar[~np.isin(out_str_ar,np.take(b_str_ar,b_axes))])
    einsum_str = a_str+','+b_str+'->'+out_str

    return np.einsum(einsum_str,a,b)
很少有示例案例运行来展示其用法-

>>> a = np.random.rand(3,4,6,7,8)
>>> b = np.random.rand(4,5,9,10)
>>> einsum_spreadout(a,b,a_axes=1,b_axes=0,a_spread_axis=2,b_spread_axis=2).shape
(3, 5, 6, 7, 8, 9, 10)

>>> b = np.random.rand(4,5,6,10)
>>> einsum_spreadout(a,b,a_axes=(1,2),b_axes=(0,2),a_spread_axis=2,b_spread_axis=2).shape
(3, 5, 7, 8, 10)

>>> einsum_spreadout(a,b,a_axes=(1,2),b_axes=(0,2),a_spread_axis=4,b_spread_axis=4).shape
(3, 7, 5, 10, 8)

np.einsum('ij…,jk…->ik…',a,b)
当省略号用于表示要对齐的后轴时,可以正常工作。您是否计划将省略号用于其他用途?如果您打算让它们像
np.einsum('ijabc,jkde->ikabcde',a,b)那样“展开”
,不,您不能使用省略号,必须使用明确提到的索引字符串字符。@Divakar感谢您的洞察力!我确实希望它们像您所说的那样“展开”。或者换言之:将它们作为额外维度保留。这看起来已经很好了,谢谢!但是,我更喜欢einsum实现(如果可能的话,我知道可能不是)。问题中简单的矩阵收缩是为了举例说明。对于更复杂的einsum操作,您的解决方案不会泛化。@Wolpertinger添加了
einsum
one。@Wolpertinger并添加了einsum字符串符号操作一。