2016-12-14 13 views
5

Czy w numpy istnieje sposób na zerowanie wpisów padu, jeśli przecinam koniec tablicy, tak, że otrzymuję coś, co jest wielkością żądanego plasterka?Zerowa kreska za końcem tablicy w numpy

Na przykład

>>> 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.]]) 

Wizualnie, chciałbym z out-of-granic obszarów być zerami:

enter image description here

mam do czynienia z obrazami i chciałby zerować podkładkę, aby zaznaczyć odsunięcie obrazu dla mojej aplikacji.

Mój obecny plan polega na użyciu np.pad, aby cała tablica była większa przed cięciem, ale indeksowanie wydaje się być nieco trudne. Czy istnieje potencjalnie łatwiejszy sposób?

+1

Obawiam się ręcznie padding jest Twoją jedyną opcją, ponieważ modyfikowanie zachowania '[]' na tablicach NumPy nie jest możliwe (ponieważ 'numpy.ndarray' jest zaimplementowany w C, który zabrania dynamicznego y zastępuje 'numpy.ndarray .__ getitem__'). –

Odpowiedz

4

O ile wiem, nie ma rozwiązania numpy (ani w żadnym pakiecie wiem) dla takiego problemu. Możesz to zrobić samemu, ale będzie to naprawdę, bardzo skomplikowany, nawet jeśli chcesz tylko podstawowe cięcie. Sugerowałbym ręczną np.pad twoją tablicę i po prostu przesunięcie twojego startu/stopu/kroku zanim zaczniesz go ciąć.

Jednak jeśli wszystko czego potrzebujesz, aby wesprzeć są liczbami całkowitymi i plastry bez kroku mam pewne „kod roboczy” to:

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 

może to zostać wykorzystane w następujący sposób:

>>> 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]]) 

Należy pamiętać, że może to być Bugs i "niezupełnie zakodowane" części, nigdy tego nie używałem, z wyjątkiem drobnych przypadków.

4

Ta klasa może obsłużyć Twój pierwszy test (x[1:4, 1:4]) i można go zmodyfikować, aby obsłużyć inny test (tj. Dołączanie zer do początku), jeśli chcesz.

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 

Oto przykładem jest użycie:

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

W przypadku 1D tablicy Zrobiłem to może być przydatne, jeśli ktoś spadnie tu ...

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 

Wykorzystanie

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 

Wyświetlacz

[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]