Numpy:将数组中的每个值替换为其相邻元素的平均值

时间:2016-07-06 19:44:04

标签: python arrays numpy numpy-broadcasting

我有一个ndarray,我想用它的相邻元素的平均值替换数组中的每个值。下面的代码可以完成这项工作,但是当我有700个阵列都具有形状(7000,7000)时它是超级慢的,所以我想知道是否有更好的方法来做到这一点。谢谢!

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

3 个答案:

答案 0 :(得分:9)

嗯,那是smoothing operation in image processing,可以通过2D卷积来实现。你对近边界元素的工作方式有所不同。因此,如果为了精确而释放边界元素,您可以使用scipy's convolve2d,如此 -

from scipy.signal import convolve2d as conv2

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

此特定操作是OpenCV模块中内置的cv2.blur,并且非常高效。该名称基本上描述了模糊表示图像的输入数组的操作。我相信效率来自于内部完全在C中实现的性能,使用精简的Python包装来处理NumPy数组。

因此,输出可以用它来计算,就像这样 -

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

答案 1 :(得分: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是与傅里叶域(在其他两种方法中)相同的边界条件强制执行。对于不同的用例,您可以更改边界条件。

现在有些测试矩阵:

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似乎更快,因为两个1D卷积中的convolution is separable(类似于gaussian_filter也是可分离的)。

使用signal模块(@Divakar的解决方案)解决方案,使用不同内核的其他不可分离过滤器更有可能更快。

fftconvolveuniform_filter的速度对于不同的内核大小仍为常量,而convolve2d稍慢。

答案 2 :(得分: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)