【问题标题】:How to insert one array into another where only zeros are (with Numpy)如何将一个数组插入另一个只有零的数组(使用 Numpy)
【发布时间】:2019-09-10 21:59:00
【问题描述】:

我在 NumPy 中有两个矩阵。一个比另一个大。我想将较小的二维数组(随机)插入到只有零的较大二维数组中(因此较大的二维数组中没有实际信息丢失)。示例:

大数组:

[0 0 0 9] 
[0 0 0 7]
[0 0 0 2]
[2 3 1 5]

小数组:

[3 3]
[3 3]

(可能的)结果:

[3 3 0 9] 
[3 3 0 7]
[0 0 0 2]
[2 3 1 5]

【问题讨论】:

  • 您要插入较小的数组并在大数组中保留其形状吗?还是随机选择大数组中的 0 个条目并用小数组中的随机条目填充它?你需要更具体
  • 它应该保持它的形状,是的。抱歉,我认为这个例子可以澄清这一点。
  • 第一个重要的任务是找到可能的插槽。首先,我会编写一个小函数来测试 (i,j) 索引是否是可能的插槽。然后迭代所有对,收集可能的情况。最后随机选择一个。如果您一次迈出一小步,实际上并没有那么困难。
  • 所以没有内置的方式说:“放在A中,值为0”?
  • @hpaulj 我原以为像你这样的人可以使用一些 “步幅技巧” 将每个矩形的像素与填充数组的大小相同,以及它们在哪里总和为零填充数组将适合...

标签: python arrays numpy matrix


【解决方案1】:

我觉得你可以用二维卷积在大数组a中找到小数组b可以去的地方。如果您将scipy.signal.convolve2dmode='valid' 一起使用,您只会得到小数组“适合”的位置。我认为使用数组的abs 可以绕过正负值(在任一数组中)取消,但我还没有非常严格地测试过这些。

这就是我所做的,使用@CypherX 的fill_a_with_b 函数进行填充步骤:

import numpy as np
import scipy.signal

# Your input data.
a = np.array([[0, 0, 0, 9], 
              [0, 0, 0, 7],
              [0, 0, 0, 2],
              [2, 3, 1, 5]])
b = np.ones((2, 2)) * 3

# Find places where b can go.
allowed = scipy.signal.convolve2d(np.abs(a), np.abs(b), mode='valid')

# Get these locations as (row, col) pairs.
coords = np.stack(np.where(allowed==0)).T

# Choose one of the locations at random.
choice = coords[np.random.randint(coords.shape[0])]

# Use @CypherX's 'fill' function.
def fill_a_with_b(a, b, pos=[0, 0]):
    aa = a.copy()
    aa[slice(pos[0], pos[0] + b.shape[0]), 
       slice(pos[1], pos[1] + b.shape[1])] = b.copy()
    return aa

# Do the fill thing.
fill_a_with_b(a, b, choice)

这会导致(例如)...

array([[0, 0, 0, 9],
       [0, 3, 3, 7],
       [0, 3, 3, 2],
       [2, 3, 1, 5]])

【讨论】:

  • 哇,这看起来比我要写的要少得多。我有很多东西要学,但是你的提交很有帮助,非常感谢!我以前从未使用过 scipy,但我会试一试! :)
【解决方案2】:

我会试着给你一个例子。但这将基于一些假设:

  1. 您知道,0 跨越一个连续的矩形块。
  2. a 中没有其他零。

如果您想填充一个不连续的零块,或者在您有一些其他非零值的列/行上有零,您将不得不考虑更复杂的解决方案。

解决方案:将数组b随机插入数组a,其中a==0

假设:我们知道a 为零的位置是一组具有矩形形状的连续位置。

进口

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
%config InlineBackend.figure_format = 'svg' # 'svg', 'retina'
plt.style.use('seaborn-white')

制作数据

# Make a
shape = (5,5)
a = np.zeros(shape)
a[:,-1] = np.arange(shape[0]) + 10
a[-1,:] = np.arange(shape[1]) + 10
# Make b
b = np.ones((2,2))*2

预处理

在这里我们确定ab 左上角元素的可能槽位置。

# Get range of positions (rows and cols) where we have zeros
target_indices = np.argwhere(a==0)
minmax = np.array([target_indices.min(axis=0), target_indices.max(axis=0)])
# Define max position (index) of topleft element of b on a
maxpos = np.dot(np.array([-1,1]), minmax) + minmax[0,:] - (np.array(b.shape) -1)
# Define min position (index) of topleft element of b on a
minpos = minmax[0,:]

列出ba 上的左上角位置

函数get_rand_topleftpos() 接受minposmaxpos 上定义可能槽位置的a 上的行和列,并为@ 返回一个随机选择的有效槽位置 987654341@。我使用size=20 创建了很多有效的随机插槽位置,然后只选择唯一的位置,这样我们就可以将它们视为图像。如果您一次只需要一个插槽位置,请选择size=1

def get_rand_topleftpos(minpos, maxpos, size=1):
    rowpos = np.random.randint(minpos[0], high=maxpos[0] + 1, size=size)
    colpos = np.random.randint(minpos[1], high=maxpos[1] + 1, size=size)
    pos = np.vstack([rowpos, colpos]).T
    return (rowpos, colpos, pos)

# Make a few valid positions where the array b could be placed
rowpos, colpos, pos = get_rand_topleftpos(minpos, maxpos, size=20)
# Select the Unique combinations so we could visualize them only
pos = np.unique(pos, axis=0)

b 放在a 上并制作数字

我们创建了一个自定义函数fill_a_with_b(),在a 的某个位置用b 填充a。此位置将接受b 的左上角单元格。

def fill_a_with_b(a, b, pos = [0,0]):
    aa = a.copy()
    aa[slice(pos[0], pos[0] + b.shape[0]), 
       slice(pos[1], pos[1] + b.shape[1])] = b.copy()
    return aa

# Make a few figures with randomly picked position 
# for topleft position of b on a

if pos.shape[0]>6:
    nrows, ncols = int(np.ceil(pos.shape[0]/6)), 6
else:
    nrows, ncols = 1, pos.shape[0]
fig, axs = plt.subplots(nrows = nrows, 
                        ncols = ncols, 
                        figsize=(2.5*ncols,2.5*nrows))
for i, ax in enumerate(axs.flatten()):    
    if i<pos.shape[0]:
        aa = fill_a_with_b(a, b, pos[i,:]) 

        sns.heatmap(aa, 
                    vmin=np.min(aa), 
                    vmax=np.max(aa), 
                    annot=True, 
                    cbar=False,
                    square=True,
                    cmap = 'YlGnBu_r', 
                    ax = ax
                   ); 

        ax.set_title('TopLeftPos: {}'.format(tuple(pos[i,:])), 
                     fontsize=9);
    else:
        ax.axis('off')

plt.tight_layout()        
plt.show()

结果

将数组a定义为:

shape = (5,5)
a = np.zeros(shape)
a[:,-1] = np.arange(shape[0]) + 10
a[-1,:] = np.arange(shape[1]) + 10

将数组a定义为:

shape = (6,5)
a = np.zeros(shape)
a[:,0] = np.arange(shape[0]) + 10
a[:,-1] = np.arange(shape[0]) + 10
a[-1,:] = np.arange(shape[1]) + 10

【讨论】:

  • 非常感谢!您提交的内容非常有帮助,我实际上从中学到了很多东西!
猜你喜欢
  • 1970-01-01
  • 2015-08-24
  • 1970-01-01
  • 2014-04-04
  • 2015-09-19
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
相关资源
最近更新 更多