2016-12-14 2 views
5

numpyでは、配列の最後をスライスしている場合、ゼロピットのエントリがあり、目的のスライスのサイズを取得できますか?numpyの配列の末尾にあるゼロパディングスライス

例えば、

>>> x = np.ones((3,3,)) 
>>> x 
array([[ 1., 1., 1.], 
     [ 1., 1., 1.], 
     [ 1., 1., 1.]]) 
>>> x[1:4, 1:4] # would behave as x[1:3, 1:3] by default 
array([[ 1., 1., 0.], 
     [ 1., 1., 0.], 
     [ 0., 0., 0.]]) 
>>> x[-1:2, -1:2] 
array([[ 0., 0., 0.], 
     [ 0., 1., 1.], 
     [ 0., 1., 1.]]) 

視覚的に、私は外の境界領域は、ゼロパディングになりたい:

enter image description here

私は画像を扱うことだし、希望します私のアプリケーションのために画像を動かすことを意味するゼロパッドまで。

私の現在の計画は、スライスする前に配列全体を大きくするためにnp.padを使用することですが、インデックス作成はややこしいと思われます。潜在的に簡単な方法はありますか?

+1

私は手動で怖いですNumPy配列で '[]'の動作を変更することはできません( 'numpy.ndarray'はC言語で実装されているため、paddingはあなたの唯一のオプションです) y numpy.ndarray .__ getitem__'を置き換えます)。 –

答えて

4

は、私の知る限りでは、このような問題にはnumpyの溶液(も私が知っている任意のパッケージでは)ありません:それは使い方だとここで

class CustomArray(): 

    def __init__(self, numpy_array): 
     self._array = numpy_array 

    def __getitem__(self, val): 

     # Get the shape you wish to return 
     required_shape = [] 
     for i in range(2): 
      start = val[i].start 
      if not start: 
       start = 0 
      required_shape.append(val[i].stop - start) 

     get = self._array[val] 

     # Check first dimension 
     while get.shape[0] < required_shape[0]: 
      get = np.concatenate((get, np.zeros((1, get.shape[1])))) 

     # Check second dimension 
     get = get.T 
     while get.shape[0] < required_shape[1]: 
      get = np.concatenate((get, np.zeros((1, get.shape[1])))) 
     get = get.T 

     return get 

は一例です。あなたはそれを自分で行うことができますが、基本的なスライスだけをしたい場合でも、本当に複雑なものになります。私は手動で np.padあなたの配列を示唆し、単にあなたが実際にスライスする前にあなたのスタート/ストップ/ステップをオフセットします。しかし

あなたがサポートするために必要なすべてのステップなしで私は、このためのいくつかの「作業コード」を持っている整数とスライスされている場合:

import numpy as np 

class FunArray(np.ndarray): 
    def __getitem__(self, item): 

     all_in_slices = [] 
     pad = [] 
     for dim in range(self.ndim): 
      # If the slice has no length then it's a single argument. 
      # If it's just an integer then we just return, this is 
      # needed for the representation to work properly 
      # If it's not then create a list containing None-slices 
      # for dim>=1 and continue down the loop 
      try: 
       len(item) 
      except TypeError: 
       if isinstance(item, int): 
        return super().__getitem__(item) 
       newitem = [slice(None)]*self.ndim 
       newitem[0] = item 
       item = newitem 
      # We're out of items, just append noop slices 
      if dim >= len(item): 
       all_in_slices.append(slice(0, self.shape[dim])) 
       pad.append((0, 0)) 
      # We're dealing with an integer (no padding even if it's 
      # out of bounds) 
      if isinstance(item[dim], int): 
       all_in_slices.append(slice(item[dim], item[dim]+1)) 
       pad.append((0, 0)) 
      # Dealing with a slice, here it get's complicated, we need 
      # to correctly deal with None start/stop as well as with 
      # out-of-bound values and correct padding 
      elif isinstance(item[dim], slice): 
       # Placeholders for values 
       start, stop = 0, self.shape[dim] 
       this_pad = [0, 0] 
       if item[dim].start is None: 
        start = 0 
       else: 
        if item[dim].start < 0: 
         this_pad[0] = -item[dim].start 
         start = 0 
        else: 
         start = item[dim].start 
       if item[dim].stop is None: 
        stop = self.shape[dim] 
       else: 
        if item[dim].stop > self.shape[dim]: 
         this_pad[1] = item[dim].stop - self.shape[dim] 
         stop = self.shape[dim] 
        else: 
         stop = item[dim].stop 
       all_in_slices.append(slice(start, stop)) 
       pad.append(tuple(this_pad)) 

     # Let numpy deal with slicing 
     ret = super().__getitem__(tuple(all_in_slices)) 
     # and padding 
     ret = np.pad(ret, tuple(pad), mode='constant', constant_values=0) 

     return ret 

次のようにこれを使用することができます。

>>> x = np.arange(9).reshape(3, 3) 
>>> x = x.view(FunArray) 
>>> x[0:2] 
array([[0, 1, 2], 
     [3, 4, 5]]) 
>>> x[-3:2] 
array([[0, 0, 0], 
     [0, 0, 0], 
     [0, 0, 0], 
     [0, 1, 2], 
     [3, 4, 5]]) 
>>> x[-3:2, 2] 
array([[0], 
     [0], 
     [0], 
     [2], 
     [5]]) 
>>> x[-1:4, -1:4] 
array([[0, 0, 0, 0, 0], 
     [0, 0, 1, 2, 0], 
     [0, 3, 4, 5, 0], 
     [0, 6, 7, 8, 0], 
     [0, 0, 0, 0, 0]]) 

に留意されたいです。これにはバグが含まれていて、「きれいにコード化されていない」パーツが含まれている可能性があります。私はこれをした1次元配列の場合は

4

このクラスはあなたの最初のテスト(x[1:4, 1:4])を処理することができ、必要に応じて他のテスト(つまり最初からゼロを追加)を処理するように変更できます。

a = CustomArray(np.ones((3, 3))) 

print(a[:2, :2]) 
[[ 1. 1.] 
[ 1. 1.]] 

print(a[:4, 1:6]) 
[[ 1. 1. 0. 0. 0.] 
[ 1. 1. 0. 0. 0.] 
[ 1. 1. 0. 0. 0.] 
[ 0. 0. 0. 0. 0.]] 

# The actual numpy array is stored in the _array attribute 
actual_numpy_array = a._array 
0

、誰かがここに落ちた場合に役立つことができます...

def getPaddedSlice(npArray, pos, lenSegment, center = False): 
    lenNpArray = len(npArray) 
    if center: 
     if lenSegment % 2 == 0: 
      startIndex = int(pos - math.floor(lenSegment/2.0)) + 1 
      lastIndex = int(pos + math.ceil(lenSegment/2.0)) + 1 

     else : 
      startIndex = int(pos - math.floor(lenSegment/2.0)) 
      lastIndex = int(pos + math.ceil(lenSegment/2.0)) + 1 
    else: 
     startIndex = pos 
     lastIndex = startIndex + lenSegment 

    if startIndex < 0: 
     padded_slice = npArray[0: lastIndex] 
     padded_slice = np.concatenate((np.zeros(abs(startIndex)), padded_slice)) 
    else: 
     if center : 
      padded_slice = npArray[startIndex: lastIndex] 
     else: 
      padded_slice = npArray[pos: lastIndex] 

    if lastIndex > len(npArray): 
     if center : 
      padded_slice = npArray[startIndex: pos + lenSegment] 
      padded_slice = np.concatenate((padded_slice, np.zeros(lastIndex - len(a)))) 
     else : 
      padded_slice = npArray[pos: pos + lenSegment] 
      padded_slice = np.concatenate((padded_slice, np.zeros(lastIndex - len(a)))) 

    return padded_slice 

使用

a = np.asarray([2,2,3,1,7,6,5,4]) 

for i in range(len(a)): 
    b = getPaddedSlice(a, i, lenSegment, True) 
    print b 

表示

[0 2 2 3] 
[2 2 3 1] 
[2 3 1 7] 
[3 1 7 6] 
[1 7 6 5] 
[7 6 5 4] 
[6 5 4 0] 
[5 4 0 0] 
関連する問題