2013-08-25 2 views
6

슬라이딩 윈도우 작업을 벡터화하려고합니다.파이썬 - 슬라이딩 윈도우를 벡터화하기

x[1,:]=np.where((x[0,:]<2)&(x[0,:]>0),x[1,x[0,:]+1],x[1,:]) 
IndexError: index (10) out of range (0<=index<9) in dimension 1 

:

x= vstack((np.array([range(10)]),np.array([range(10)]))) 

x[1,:]=np.where((x[0,:]<5)&(x[0,:]>0),x[1,x[0,:]+1],x[1,:]) 

지수 < 5. 각 전류 값의 N + 1 개 값하지만이 오류를 얻을 : 1-D의 경우를 위해 도움이되는 예는의 라인을 따라 갈 수

x[1,:]=np.where((x[0,:]<5)&(x[0,:]>0),x[1,x[0,:]-1],x[1,:]) 

print(x) 

[[0 1 2 3 4 5 6 7 8 9] 
[0 0 1 2 3 5 6 7 8 9]] 

이 주위 어쨌든 거기 : 이상하게도 나는 그것은 생각하지 않는 것 0보다 작은 인덱스를 의미은 n-1 값이 오류를 얻을 수 없겠죠? 내 접근 방식이 완전히 틀렸어? 모든 의견을 부탁드립니다.

EDIT :

matriz = np.array([[1,2,3,4,5], 
    [6,5,4,3,2], 
    [1,1,2,2,3], 
    [3,3,2,2,1], 
    [3,2,1,3,2], 
    [1,2,3,1,2]]) 

# matrix to vector 
vector2 = ndarray.flatten(matriz) 

ncols = int(shape(matriz)[1]) 
nrows = int(shape(matriz)[0]) 

vector = np.zeros(nrows*ncols,dtype='float64') 


# Interior pixels 
if ((i % ncols) != 0 and (i+1) % ncols != 0 and i>ncols and i<ncols*(nrows-1)): 

    vector[i] = np.mean(np.array([vector2[i-ncols-1],vector2[i-ncols],vector2[i-ncols+1],vector2[i-1],vector2[i+1],vector2[i+ncols-1],vector2[i+ncols],vector2[i+ncols+1]])) 
:

이 I는 I는 I 각 셀의 좁은 이웃의 평균을 산출 할상의 NumPy와 배열 행렬을 평탄화 달성하고자하는 무엇

+0

명확하게'vector2 [i]'를 포함시키지 않으려하거나 코드에서 실수였습니까? – Daniel

+0

나는 그렇지 않습니다. 고맙습니다. – JEquihua

+0

코드는 6x6 이웃이 아닌 각 셀의 3x3 이웃 평균을 계산합니다. 이게 의도적 인거야? – nneonneo

답변

8

문제를 올바르게 이해하면 인덱스를 무시하고 인덱스 주위에 모든 숫자의 평균을 취하고 싶습니다. np.empty_like를 사용

def mean_around(arr): 
    arr=arr.astype(np.float64) 

    out= np.copy(arr[:-2,:-2]) #Top left corner 
    out+= arr[:-2,2:]   #Top right corner 
    out+= arr[:-2,1:-1]   #Top center 
    out+= arr[2:,:-2]   #etc 
    out+= arr[2:,2:] 
    out+= arr[2:,1:-1] 
    out+= arr[1:-1,2:] 
    out+= arr[1:-1,:-2] 

    out/=8.0 #Divide by # of elements to obtain mean 

    cout=np.empty_like(arr) #Create output array 
    cout[1:-1,1:-1]=out  #Fill with out values 
    cout[0,:]=0;cout[-1,:]=0;cout[:,0]=0;cout[:,-1]=0 #Set edges equal to zero 

    return cout 

후 작성 :

def original(matriz): 

    vector2 = np.ndarray.flatten(matriz) 

    nrows, ncols= matriz.shape 
    vector = np.zeros(nrows*ncols,dtype='float64') 

    # Interior pixels 
    for i in range(vector.shape[0]): 
     if ((i % ncols) != 0 and (i+1) % ncols != 0 and i>ncols and i<ncols*(nrows-1)): 

      vector[i] = np.mean(np.array([vector2[i-ncols-1],vector2[i-ncols],\ 
         vector2[i-ncols+1],vector2[i-1],vector2[i+1],\ 
         vector2[i+ncols-1],vector2[i+ncols],vector2[i+ncols+1]])) 

내가이 슬라이스 및 뷰를 사용하여 재 작성 : 내가 작동하도록 기능을 패치 한

, 난 당신이 이런 식으로 뭔가 거라고 생각 가장자리가 약간 더 빠른 것처럼 보였습니다 np.zeros_like. 먼저 matriz 어레이를 사용하여 동일한 것을 제공하는지 다시 확인하십시오.

print np.allclose(mean_around(matriz),original(matriz)) 
True 

print mean_around(matriz) 
[[ 0.  0.  0.  0.  0. ] 
[ 0.  2.5 2.75 3.125 0. ] 
[ 0.  3.25 2.75 2.375 0. ] 
[ 0.  1.875 2.  2.  0. ] 
[ 0.  2.25 2.25 1.75 0. ] 
[ 0.  0.  0.  0.  0. ]] 

일부 타이밍 :

a=np.random.rand(500,500) 

print np.allclose(original(a),mean_around(a)) 
True 

%timeit mean_around(a) 
100 loops, best of 3: 4.4 ms per loop 

%timeit original(a) 
1 loops, best of 3: 6.6 s per loop 

대략 ~ 1500 배의 속도 향상.

def mean_numba(arr): 
    out=np.zeros_like(arr) 
    col,rows=arr.shape 

    for x in xrange(1,col-1): 
     for y in xrange(1,rows-1): 
      out[x,y]=(arr[x-1,y+1]+arr[x-1,y]+arr[x-1,y-1]+arr[x,y+1]+\ 
         arr[x,y-1]+arr[x+1,y+1]+arr[x+1,y]+arr[x+1,y-1])/8. 
    return out 

nmean= autojit(mean_numba) 

지금 모든 제시된 방법에 대해 비교할 수 있습니다 : 좋은 장소가 numba를 사용하려면

보인다. numba 위로

a=np.random.rand(5000,5000) 

%timeit mean_around(a) 
1 loops, best of 3: 729 ms per loop 

%timeit nmean(a) 
10 loops, best of 3: 169 ms per loop 

#CT Zhu's answer 
%timeit it_mean(a) 
1 loops, best of 3: 36.7 s per loop 

#Ali_m's answer 
%timeit fast_local_mean(a,(3,3)) 
1 loops, best of 3: 4.7 s per loop 

#lmjohns3's answer 
%timeit scipy_conv(a) 
1 loops, best of 3: 3.72 s per loop 

4 배의 속도는 얻을 것 같은 NumPy와 코드에 대한 좋은 것을 나타내는 매우 명목이다. 다른 배열 크기를 포함하도록 @ CTZhu의 대답을 변경해야했지만 제시된 다른 코드를 가져 왔습니다.

+1

니스. 그것은'n = 3'에 대한 나의 버전보다 2 배 더 빠르지 만, 특정 경우에는 상당히 높습니다.). – nneonneo

+0

나는 이것을 많이 좋아한다. 나는 지금 휴가 중이지만 내 특별한 문제에 대해이 문제를 시도하고 다시 생각해 보겠습니다. 나는 이것을 5000 * 5000 매트릭스에 사용하고 그것을 어떻게보고 싶다. – JEquihua

+1

@nneonneo'uniform_filter'는 실제로이 글의 첫 번째 반복에서 사용한 답변이었습니다. 여러분이 몇 가지 질문을 던졌기 때문에 대단히 강력하고 놀라 울 정도로 빠릅니다. – Daniel

2

문제는 두 번째 축의 인덱스 인 x[1,x[0,:]+1]에 있습니다. x[0,:]+1은 이 x의 차원보다 큰 [1 2 3 4 5 6 7 8 9 10]입니다. 9 마지막 요소이며 -1의 인덱스가 같은 x[1,x[0,:]-1]의 경우

는 2 축의 지수는 당신이 [9 0 1 2 3 4 5 6 7 8]을 받고 결국, [-1 0 1 2 3 4 5 6 7 8 9]입니다. 끝에있는 두 번째 요소의 인덱스는 -2입니다. 본질적으로 무슨 일이 일어나고 있는지 np.where((x[0,:]<5)&(x[0,:]>0),x[1,x[0,:]-1],x[1,:])x[0,:]=[0 1 2 3 4 5 6 7 8 9]

x[0,0]가 0이고 x[0,:]<5)&(x[0,:]>0False 때문에 첫 번째 셀 양식 x[1,:]을 촬영한다는 것입니다. 다음 네 요소는 x[1,x[0,:]-1]에서 가져옵니다. 나머지는 x[1,:]입니다. 마지막으로 결과는 [0 0 1 2 3 4 5 6 7 8]

그냥 1 셀의 슬라이딩 창의 OK 표시 될 수 있지만, 함께 거 놀라운 당신의

:

>>> np.where((x[0,:]<5)&(x[0,:]>0),x[1,x[0,:]-2],x[1,:]) 
array([0, 9, 0, 1, 2, 5, 6, 7, 8, 9]) 

하는 두 세포의 창으로 이동하려고 할 때 . 우리가 한 줄에 모든 것을 유지하려는 경우

이 특정 문제에 대한

, 이것은 수행합니다

>>> for i in [1, 2, 3, 4, 5, 6]: 
    print hstack((np.where(x[1,x[0,:]-i]<x[0, -i], x[1,x[0,:]-i], 0)[:5], x[0,5:])) 

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

편집 : 가 지금은 기본적으로 당신은 2D를 먹고 싶어, 더 나은 원래의 질문을 이해 배열을 계산하고 각 셀 주변의 N * N 셀 평균을 계산합니다. 그것은 아주 흔합니다. 우선 N을 홀수로 제한하고 싶지 않을 것입니다. 그렇지 않으면 셀 주변의 2 * 2 평균과 같은 것을 정의하기가 어렵습니다. 나는 당신이 당신에게 혼란을 야기 2D 배열을, 평평 할 필요가 없습니다 생각

#In this example, the shape is (10,10) 
>>> a1=\ 
array([[3, 7, 0, 9, 0, 8, 1, 4, 3, 3], 
    [5, 6, 5, 2, 9, 2, 3, 5, 2, 9], 
    [0, 9, 8, 5, 3, 1, 8, 1, 9, 4], 
    [7, 4, 0, 0, 9, 3, 3, 3, 5, 4], 
    [3, 1, 2, 4, 8, 8, 2, 1, 9, 6], 
    [0, 0, 3, 9, 3, 0, 9, 1, 3, 3], 
    [1, 2, 7, 4, 6, 6, 2, 6, 2, 1], 
    [3, 9, 8, 5, 0, 3, 1, 4, 0, 5], 
    [0, 3, 1, 4, 9, 9, 7, 5, 4, 5], 
    [4, 3, 8, 7, 8, 6, 8, 1, 1, 8]]) 
#move your original array 'a1' around, use range(-2,2) for 5*5 average and so on 
>>> movea1=[a1[np.clip(np.arange(10)+i, 0, 9)][:,np.clip(np.arange(10)+j, 0, 9)] for i, j in itertools.product(*[range(-1,2),]*2)] 
#then just take the average 
>>> averagea1=np.mean(np.array(movea1), axis=0) 
#trim the result array, because the cells among the edges do not have 3*3 average 
>>> averagea1[1:10-1, 1:10-1] 
array([[ 4.77777778, 5.66666667, 4.55555556, 4.33333333, 3.88888889, 
    3.66666667, 4.  , 4.44444444], 
    [ 4.88888889, 4.33333333, 4.55555556, 3.77777778, 4.55555556, 
    3.22222222, 4.33333333, 4.66666667], 
    [ 3.77777778, 3.66666667, 4.33333333, 4.55555556, 5.  , 
    3.33333333, 4.55555556, 4.66666667], 
    [ 2.22222222, 2.55555556, 4.22222222, 4.88888889, 5.  , 
    3.33333333, 4.  , 3.88888889], 
    [ 2.11111111, 3.55555556, 5.11111111, 5.33333333, 4.88888889, 
    3.88888889, 3.88888889, 3.55555556], 
    [ 3.66666667, 5.22222222, 5.  , 4.  , 3.33333333, 
    3.55555556, 3.11111111, 2.77777778], 
    [ 3.77777778, 4.77777778, 4.88888889, 5.11111111, 4.77777778, 
    4.77777778, 3.44444444, 3.55555556], 
    [ 4.33333333, 5.33333333, 5.55555556, 5.66666667, 5.66666667, 
    4.88888889, 3.44444444, 3.66666667]]) 

: 우리는 3 * 3 평균을한다고 가정. 또한 모서리 요소를 다듬는 것 외에 다르게 처리하려면 '원래 배열을 주변으로 이동'단계에서 np.ma을 사용하여 마스크 된 배열을 만드는 것을 고려하십시오.

+0

다른 방법으로 작동하지 않는 이유는 무엇입니까? 10이 다시 첫 번째 요소입니까? 또는 내가 원하는 것을 어떻게 할 수 있습니까? – JEquihua

+0

아, matlab과 달리 Python의 인덱스는 0부터 시작합니다. 따라서 양수'int'를 사용하면 길이가 10 인 벡터의 최대 인덱스는 9이고 x [10]을 시도하면'indexError'가됩니다. 'x = [0 1 2 3 4 5 6 7 8 9]'에 대해서, 9를 얻으려면'x [-1]'또는'x [9]'가되지만'x [10]'는 아니. –

+0

나는 정말로 원하는 것을 보여주기 위해 나의 질문을 편집하려고합니다. 나는 단지 긴 질문을 원하지 않았지만 여기에 간다. 내 생각에 너는 나를 오해하고있다. – JEquihua

4

2D 컨볼 루션을 계산하려는 것 같습니다. 당신이 scipy을 사용할 수있는 경우에, 나는 scipy.signal.convolve2d를 시도 제안 : 당신이 그 구성 루프에 convolve2d "을 풀다"경우

matriz = np.random.randn(10, 10) 

# to average a 3x3 neighborhood 
kernel = np.ones((3, 3), float) 

# to compute the mean, divide by size of neighborhood 
kernel /= kernel.sum() 

average = scipy.signal.convolve2d(matriz, kernel) 

이 모든 3 × 3 지역의 평균을 계산 이유는 알 수있다. 효과적으로 (소스 및 커널 배열의 가장자리에서 발생하는 무시), 그것은이다 컴퓨팅 :

커널의 모든 값이 그렇다면
X, Y = kernel.shape 
for i in range(matriz.shape[0]): 
    for j in range(matriz.shape[1]): 
     for ii in range(X): 
      for jj in range(Y): 
       average[i, j] += kernel[ii, jj] * matriz[i+ii, j+jj] 

1/(1 + 1 + 1 + 1 + 1 + 1

for i in range(matriz.shape[0]): 
    for j in range(matriz.shape[1]): 
     average[i, j] = 1./9 * matriz[i:i+X, j:j+Y].sum() 

정확히에서 시작하여 3 × 3 영역에 걸쳐, matriz의 값의 평균을 계산 같은 어느 :로 + 1 + 1 + 1) == 1/9, 당신은 위의 코드를 다시 작성할 수 있습니다 i, j.

이런 식으로 일하는 한 가지 장점은 커널의 값을 적절하게 설정하여 주변과 관련된 가중치를 쉽게 변경할 수 있다는 것입니다. 그래서 당신은 다른 사람으로 많은 무게를 두 배 각 지역의 중심 값을주고 싶어하는 경우, 예를 들어, 다음과 같이 커널을 만들 수 :

kernel = np.ones((3, 3), float) 
kernel[1, 1] = 2. 
kernel /= kernel.sum() 

및 회선 코드는 동일하게 유지하지만 것 계산은 다른 유형의 평균을 산출합니다 ("중앙 가중"평균). 여기에는 많은 가능성이 있습니다. 잘하면이 작업에 대한 좋은 추상화를 제공합니다.

3

매우 빠르게 슬라이딩 창을 통해 평균을 계산하는 Scipy 표준 라이브러리의 함수가 있습니다. uniform_filter이라고합니다. 당신은 다음과 같이 평균의-이웃 기능을 구현하는 데 사용할 수 있습니다 :

from scipy.ndimage.filters import uniform_filter 
def neighbourhood_average(arr, win=3): 
    sums = uniform_filter(arr, win, mode='constant') * (win*win) 
    return ((sums - arr)/(win*win - 1)) 

X[i,j]i,j 자체를 제외 arri,j의 모든 이웃의 평균은 배열 X을 반환합니다. 첫 번째와 마지막 열과 첫 번째와 마지막 행은 경계 조건의 영향을 받기 때문에 응용 프로그램에 대해 유효하지 않을 수 있습니다 (필요하다면 mode=을 사용하여 경계 규칙을 제어 할 수 있음). uniform_filter는 (전용 arr의 크기에 선형) 직선 C로 구현 고효율 선형 시간 알고리즘을 사용하기 때문에

가 용이 win가 클 때, 특히 다른 솔루션을 능가한다.

+0

매우 흥미 롭습니다.경계 조건은 어떤 조건을 따르고 있습니까? 나는 보통의 조건을 원한다고 생각하지만 나는 내 질문에 그것을 게시하지 않았다. 이것은 (i, j) 자체를 어떻게 제외합니까? 코드를 조금 설명해 주시겠습니까? – JEquihua

+0

'uniform_filter'는 기본적으로 각'(i, j)'에 윈도우를 중점에 두어 평균화합니다. '(i-1 : i + 2, j-1 : j + 2) '와 같은 3x3 윈도우. 원래 배열 외부에있는 값의 경우, uniform_filter는'mode'에 의해 결정된 채우기 값을 사용합니다. 불완전한 창을 신경 쓰지 않는다면 첫 번째와 마지막 행과 첫 번째와 마지막 열을 삭제하거나 0으로 만들 수 있습니다. – nneonneo

+1

'(i, j)'는'- arr' 비트로 인해 제외됩니다.이 비트는 창 합계에서 원래 값을 제거합니다. – nneonneo

관련 문제