2

让我通过一个小例子来解释它:

>>> x = np.array([[1,2], [3,4], [5,6], [7,8]])
>>> x
array([[1, 2],
       [3, 4],
       [5, 6],
       [7, 8]])

我想要一个具有以下形式的新数组

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

在这里,上下文的大小为 +/-1,但我想让它保持可变。

到目前为止,我正在做的是将零附加到原始数组:

>>> y = np.concatenate((np.zeros((1, 2)), x, np.zeros((1, 2))), axis=0)
>>> y
array([[ 0.,  0.],
       [ 1.,  2.],
       [ 3.,  4.],
       [ 5.,  6.],
       [ 7.,  8.],
       [ 0.,  0.]])

并通过读取新大小的行将值放入新数组中:

>>> z = np.empty((x.shape[0], x.shape[1]*3))
>>> for i in range(x.shape[0]): z[i] = y[i:i+3].flatten()

那种作品,但我发现它缓慢,丑陋和不合时宜。你能想出一个更好的方法来进行这种重新排列吗?就地解决方案的额外赞许:)

4

2 回答 2

2

There is the option of using stride_tricks, but I will not say that this is the best answer, because while it is "the most efficient way", that way is not always the best when considering readability and that it is playing with fire.

# We make it flat (and copy if necessary) to be on the safe side, and because
# it is more obvious this way with stride tricks (or my function below):
y = y.ravel()

# the new shape is (y.shape[0]//2-2, 6). When looking at the raveled y, the first
# dimension takes steps of 2 elements (so y.strides[0]*2) and the second is
# just the old one:
z = np.lib.stride_tricks.as_strided(y, shape=(y.shape[0]//2-2, 6),
                                       strides=(y.strides[0]*2, y.strides[0]))

Note that z here is only a view, so use z.copy() to avoid any unexpected things before editing it, otherwise in your example all 1s will change if you edit one of them. On the up side, if you mean this by "in-place", you can now change elements in y and z will change too.

If you want to do more of this magic, maybe check out my rolling_window function from https://gist.github.com/3430219, which replaces the last line with:

# 6 values long window, but only every 2nd step on the original array:
z = rolling_window(y, 6, asteps=2)

Important: np.lib.stride_tricks.as_strided by itself is generally not safe and must be used with care as it can create segmentation faults.

于 2012-08-23T19:55:41.983 回答
1

索引应该工作:

y = np.concatenate(([0, 0], x.flat, [0, 0]))  # or use np.pad with NumPy 1.7
i = np.tile(np.arange(6), (4, 1)) + np.arange(4)[:, None] * 2
z = y[i]

显然,如果您愿意,这是就地的!

要了解它是如何工作的,请查看i索引数组:

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

使其灵活:

context = 1
h, w = x.shape
zeros = np.zeros((context, w), dtype=x.dtype)
y = np.concatenate((zeros, x, zeros), axis=0).flat
i = np.tile(np.arange(w + 2 * context * w), (h, 1)) + np.arange(h)[:, None] * w
z = y[i]
于 2012-08-23T19:35:15.160 回答