numpy:通过沿新轴滚动并以第二个数组中给出的变量移位来广播数组

时间:2018-11-06 16:40:58

标签: python arrays numpy

我知道numpy.roll可以沿一个或多个现有轴移动数组。我该如何在阵列x上创建一个新轴,以使其沿着阵列shift滚动其自身的视图或副本?

示例:

x = np.arange(10)
shift = np.array([2, 4])

#input
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

#output
array(
  [[8, 6],
   [9, 7],
   [0, 8],
   [1, 9],
   [2, 0],
   [3, 1],
   [4, 2],
   [5, 3],
   [6, 4],
   [7, 5]])

编辑:我正在寻找一种通用解决方案(理想情况下没有循环),该解决方案也可以应用于高维数组。另一个例子:

x = np.arange(20).reshape(2, 10)
shift = np.array([2, 4])

#input
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])

#output
array(
  [[[ 8,  6],
    [ 9,  7],
    [ 0,  8],
    [ 1,  9],
    [ 2,  0],
    [ 3,  1],
    [ 4,  2],
    [ 5,  3],
    [ 6,  4],
    [ 7,  5]],

   [[18, 16],
    [19, 17],
    [10, 18],
    [11, 19],
    [12, 10],
    [13, 11],
    [14, 12],
    [15, 13],
    [16, 14],
    [17, 15]]])

2 个答案:

答案 0 :(得分:2)

这是一个利用broadcasting的矢量化解决方案,涵盖了通用n-dim数组的情况-

np.take(x,(-shift + np.arange(x.shape[-1])[:,None]),axis=-1)

示例运行

1)x1D-

In [114]: x = np.arange(10)
     ...: shift = np.array([2, 4])

In [115]: np.take(x,(-shift + np.arange(x.shape[-1])[:,None]),axis=-1)
Out[115]: 
array([[8, 6],
       [9, 7],
       [0, 8],
       [1, 9],
       [2, 0],
       [3, 1],
       [4, 2],
       [5, 3],
       [6, 4],
       [7, 5]])

2)x2D-

In [116]: x = np.arange(20).reshape(2, 10)
     ...: shift = np.array([2, 4])

In [117]: np.take(x,(-shift + np.arange(x.shape[-1])[:,None]),axis=-1)
Out[117]: 
array([[[ 8,  6],
        [ 9,  7],
        [ 0,  8],
        [ 1,  9],
        [ 2,  0],
        [ 3,  1],
        [ 4,  2],
        [ 5,  3],
        [ 6,  4],
        [ 7,  5]],

       [[18, 16],
        [19, 17],
        [10, 18],
        [11, 19],
        [12, 10],
        [13, 11],
        [14, 12],
        [15, 13],
        [16, 14],
        [17, 15]]])

答案 1 :(得分:0)

我几乎不愿意提供这种替代方法,因为我认为@BenT的答案很简单且合乎逻辑

np.array([np.roll(x,sh) for sh in shift]).T
np.stack([np.roll(x,sh) for sh in shift], axis=1)  # may be easier to generalize

但是我可以用x=np.arange(10)做原始的as_strided情况:

执行所有班次:

In [352]: arr = np.lib.stride_tricks.as_strided(np.hstack((x,x)),shape=(10,10), strides=(8,8))
In [353]: arr
Out[353]: 
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
       [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
       [2, 3, 4, 5, 6, 7, 8, 9, 0, 1],
       [3, 4, 5, 6, 7, 8, 9, 0, 1, 2],
       [4, 5, 6, 7, 8, 9, 0, 1, 2, 3],
       [5, 6, 7, 8, 9, 0, 1, 2, 3, 4],
       [6, 7, 8, 9, 0, 1, 2, 3, 4, 5],
       [7, 8, 9, 0, 1, 2, 3, 4, 5, 6],
       [8, 9, 0, 1, 2, 3, 4, 5, 6, 7],
       [9, 0, 1, 2, 3, 4, 5, 6, 7, 8]])

然后选择所需的对象:

In [358]: arr[::-1][shift-1]
Out[358]: 
array([[8, 9, 0, 1, 2, 3, 4, 5, 6, 7],
       [6, 7, 8, 9, 0, 1, 2, 3, 4, 5]])

我曾经尝试编写并测试过stack版本,但是不得不尝试几件事才能使as_strided正确。

我也希望将列表理解推广到更高的维度。


针对您的2d x

np.stack([np.roll(x,sh, axis=1) for sh in shift],2)