让我用一个小例子解释一下:
>>> 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()
这种作品,但我发现它缓慢,丑陋和unpythonic。 你能想到一个更好的方法来进行这种重新排列吗?对于现场解决方案的额外赞成:)
答案 0 :(得分:2)
可以选择使用stride_tricks
,但我不会说这是最好的答案,因为虽然它是“最有效的方式”,但在考虑可读性时这种方式并不总是最好的它正在玩火。
# 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]))
请注意z
这里只是一个视图,因此在编辑之前使用z.copy()
可以避免任何意外的事情,否则在您的示例中,如果您编辑其中一个,则所有1都会更改。从好的方面来说,如果你的意思是“就地”,你现在可以更改y
中的元素,而z
也会改变。
如果你想要做更多这样的魔术,可以从https://gist.github.com/3430219查看我的rolling_window
函数,该函数将最后一行替换为:
# 6 values long window, but only every 2nd step on the original array:
z = rolling_window(y, 6, asteps=2)
重要提示: np.lib.stride_tricks.as_strided
本身通常不安全,必须小心使用,因为它可能会造成细分错误。
答案 1 :(得分: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]