2016-07-06 38 views
5

私はndarrayを持っています。配列のすべての値を隣接する要素の平均で置き換えたいと思います。下のコードは仕事をすることができますが、私は700の配列をすべて形(7000,7000)で持っていると非常に遅いので、もっと良い方法があるのだろうかと思います。ありがとう!Numpy:配列内のすべての値を隣接する要素の平均で置き換えます。

a = np.array(([1,2,3,4,5,6,7,8,9],[4,5,6,7,8,9,10,11,12],[3,4,5,6,7,8,9,10,11])) 
row,col = a.shape 
new_arr = np.ndarray(a.shape) 
for x in xrange(row): 
    for y in xrange(col): 
     min_x = max(0, x-1) 
     min_y = max(0, y-1) 
     new_arr[x][y] = a[min_x:(x+2),min_y:(y+2)].mean() 
print new_arr 
+0

私はゆっくりと動作しているわけではなく、ゆっくりと動作するようにも見えません。 –

+0

@EliSadoffもし私が形状(7000,7000)のすべての700の配列を持っていれば... – Chiefscreation

+0

私はPythonでそれを行う方法はわかりませんが、マルチスレッドや並列処理を考慮していますか?私はCで大規模なデータ処理を高速化するためにこれを行うことができます知っています。 – Michael

答えて

9

まあ、それは2Dコンボリューションを用いて達成することができるsmoothing operation in image processing、です。あなたは境界近くの要素で少し違った働きをしています。境界要素は精度のためにオフにさせているのであれば、あなたはそのようscipy's convolve2dを使用することができます -

from scipy.signal import convolve2d as conv2 

out = (conv2(a,np.ones((3,3)),'same')/9.0 

この具体的な動作であるcv2.blurとしてOpenCVのモジュールに内蔵し、それで非常に効率的です。名前は基本的に、イメージを表す入力配列をぼかす操作を表します。効率は、NumPy配列を扱うための薄いPythonラッパーを使って、内部的にはCで完全に実装されているという事実から来ていると思います。

そうのようなので、出力を代わりに、それを計算することができた -

import cv2 # Import OpenCV module 

out = cv2.blur(a.astype(float),(3,3)) 

はここでちゃんと大きな画像/アレイ上のタイミングのクイックショーダウンだ -

In [93]: a = np.random.randint(0,255,(5000,5000)) # Input array 

In [94]: %timeit conv2(a,np.ones((3,3)),'same')/9.0 
1 loops, best of 3: 2.74 s per loop 

In [95]: %timeit cv2.blur(a.astype(float),(3,3)) 
1 loops, best of 3: 627 ms per loop 
+0

うまくやっています。私はこのようなことを書こうとしていました。 +1。 – rayryeng

+0

@rayryeng NumPyタグでお会いできて良かったです! ;) – Divakar

+0

@Divakarそれは私の餌にあります:)私は最近、質問に答えていません...私の最後にはたくさんのことが起こっています。 – rayryeng

4

後@Divakarとのディスカッションでは、scipyに存在するさまざまな畳み込み方法の比較を以下に示します。

import numpy as np 
from scipy import signal, ndimage 

def conv2(A, size): 
    return signal.convolve2d(A, np.ones((size, size)), mode='same')/float(size**2) 

def fftconv(A, size): 
    return signal.fftconvolve(A, np.ones((size, size)), mode='same')/float(size**2) 

def uniform(A, size): 
    return ndimage.uniform_filter(A, size, mode='constant') 

すべての3つのメソッドは、まったく同じ値を返します。しかしながら、uniform_filterは、フィルタの境界条件を示すパラメータmode='constant'を有し、constant == 0は、フーリエ領域(他の2つの方法において)が実施されるのと同じ境界条件であることに留意されたい。異なるユースケースについては、境界条件を変更することができます。

現在、いくつかのテスト行列:

A = np.random.randn(1000, 1000) 

そして、いくつかのタイミング:

%timeit conv2(A, 3)  # 33.8 ms per loop 
%timeit fftconv(A, 3) # 84.1 ms per loop 
%timeit uniform(A, 3) # 17.1 ms per loop 

%timeit conv2(A, 5)  # 68.7 ms per loop 
%timeit fftconv(A, 5) # 92.8 ms per loop 
%timeit uniform(A, 5) # 17.1 ms per loop 

%timeit conv2(A, 10)  # 210 ms per loop 
%timeit fftconv(A, 10) # 86 ms per loop 
%timeit uniform(A, 10) # 16.4 ms per loop 

%timeit conv2(A, 30)  # 1.75 s per loop 
%timeit fftconv(A, 30) # 102 ms per loop 
%timeit uniform(A, 30) # 16.5 ms per loop 

だから、要するに、uniform_filterは速いようで、それであるgaussian_filterに似convolution is separable 2における1D convolutons(理由また分離可能)。

異なるカーネルを持つ他の分離不可能なフィルタは、signalモジュール(@ Divakarのもの)を使用すると、より高速になる可能性が高くなります。

convolve2dが若干遅くなるながらfftconvolveuniform_filter両方の速度は、異なるカーネルサイズの定数のままです。

+0

良い発見!今、すべてのものを消化しなければならない。 – Divakar

+0

@Divakarはちょっと面白いものを見つけました。*小さな*カーネルサイズでは、最後の2つのメソッドは* constant *実行時間を維持します。 –

+0

私はuniform_filterの実装を2つの処理で理解していると思います。その 'fftconvolve'の内部実装は面倒です。これらの有用な発見を思い付いてくれてありがとう! – Divakar

0

私は最近同様の問題があり、私はscipyを使用できないので、別の解決策を見つけなければなりませんでした。

import numpy as np 

a = np.random.randint(100, size=(7000,7000)) #Array of 7000 x 7000 
row,col = a.shape 

column_totals = a.sum(axis=0) #Dump the sum of all columns into a single array 

new_array = np.zeros([row,col]) #Create an receiving array 

for i in range(row): 
    #Resulting row = the value of all rows minus the orignal row, divided by the row number minus one. 
    new_array[i] = (column_totals - a[i])/(row - 1) 

print(new_array) 
関連する問題