定期切片2D numpy数组



我有一个300x300的numpy数组,我想定期保存所有元素。具体来说,对于两个轴,我都想保留前5个元素,然后丢弃15个,保留5个,丢弃15个等等。这应该会产生一个75x75个元素的数组。如何做到这一点?

您可以创建一个1D掩码,用于执行保留/丢弃功能,然后重复该掩码并将该掩码应用于数组。下面是一个例子。

import numpy as np
size = 300
array = np.arange(size).reshape((size, 1)) * np.arange(size).reshape((1, size))
mask = np.concatenate((np.ones(5), np.zeros(15))).astype(bool)
period = len(mask)
mask = np.repeat(mask.reshape((1, period)), repeats=size // period, axis=0)
mask = np.concatenate(mask, axis=0)
result = array[mask][:, mask]
print(result.shape)

您可以将数组视为一系列20x20块,您希望保留其中左上角的5x5部分。假设你有

keep = 5
discard = 15

这仅适用于

assert all(s % (keep + discard) == 0 for s in arr.shape)

首先计算视图的形状并使用它:

block = keep + discard
shape1 = (arr.shape[0] // block, block, arr.shape[1] // block, block)
view = arr.reshape(shape1)[:, :keep, :, :keep]

以下操作将创建数据的副本,因为视图创建了一个不连续的缓冲区:

shape2 = (shape1[0] * keep, shape1[2] * keep)
result = view.reshape(shape2)

您可以使用类似的方法以更通用的方式计算shape1shape2

shape1 = tuple(
np.stack((np.array(arr.shape) // block,
np.full(arr.ndim, block)), -1).ravel())
shape2 = tuple(np.array(shape1[::2]) * keep)

我建议将其打包为一个函数。

这是我对解决方案的第一个想法。如果我想到一个行数更少的,稍后会更新。即使输入不是正方形,这也应该有效:

output = []
for i in range(len(arr)):
tmp = []
if i % (15+5) < 5:         # keep first 5, then discard next 15
for j in range(len(arr[i])):
if j % (15+5) < 5: # keep first 5, then discard next 15
tmp.append(arr[i,j])
output.append(tmp)

更新:

基于杨的回答,这里有另一种使用np.tile的方法,它沿着每个轴重复一个数组给定的次数。这取决于输入数组的大小是否为正方形。

import numpy as np
# Define one instance of the keep/discard box
keep, discard = 5, 15
mask = np.concatenate([np.ones(keep), np.zeros(discard)])
mask_2d = mask.reshape((keep+discard,1)) * mask.reshape((1,keep+discard))
# Tile it out -- overshoot, then trim to match size
count = len(arr)//len(mask_2d) + 1
tiled = np.tile(mask_2d, [count,count]).astype('bool')
tiled = tiled[:len(arr), :len(arr)]
# Apply the mask to the input array
dim = sum(tiled[0])
output = arr[tiled].reshape((dim,dim))

使用网格和模的另一个选项:

# MyArray = 300x300 numpy array
r      = np.r_[0:300]              # A slide from 0->300
xv, yv = np.meshgrid(r, r)         # x and y grid
mask   = ((xv%20)<5) & ((yv%20)<5) # We create the boolean mask
result = MyArray[mask].reshape((75,75)) # We apply the mask and reshape the final output

最新更新