【问题标题】:Numpy: Replace every value in the array with the mean of its adjacent elementsNumpy:将数组中的每个值替换为其相邻元素的平均值
【发布时间】:2016-11-09 00:09:03
【问题描述】:

我有一个 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

【问题讨论】:

  • 它对我来说一点也不慢,看起来也不应该慢。
  • @EliSadoff 如果我有 700 个数组,所有形状都为 (7000,7000) ...
  • 我不确定如何在 python 中做到这一点,但您是否考虑过多线程或并行处理?我知道在 C 语言中你可以这样做来加速大数据处理。
  • 你没有正确设置max_xmax_y...

标签: python arrays numpy array-broadcasting


【解决方案1】:

嗯,这是一个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。
  • @rayryeng 很高兴见到您使用 NumPy 标签! ;)
  • @Divakar 它在我的订阅源上 :) 不过我最近没有回答问题……我的任务很多。
  • uniform_filter 是一个捷径...但是由于signal 模块在傅里叶域中运行,我想这会更快吗?
  • @Chiefscreation scipy 中也有最大过滤器:docs.scipy.org/doc/scipy-0.16.0/reference/generated/…
【解决方案2】:

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

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

fftconvolveuniform_filter 的速度对于不同的内核大小保持恒定,而convolve2d 会稍微慢一些。

【讨论】:

  • 很好的发现!现在必须消化所有这些东西。
  • @Divakar 刚刚发现了一些非常有趣的东西,对于不同的 small 内核大小,最后 2 个方法保持 constant 执行时间。
  • 我想我理解了 uniform_filter 的实现,通过两次处理来处理它。 fftconvolve 的内部实现看起来很乱。再次感谢您提出这些有用的发现!
  • @Divakar wikipedia 实际上很好地解释了uniform_filter 在做什么(基本上是相同的例子)!
【解决方案3】:

我最近遇到了类似的问题,因为我不能使用 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)

【讨论】:

    猜你喜欢
    • 2019-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-27
    • 2013-09-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多