【问题标题】:Python get get average of neighbours in matrix with na valuePython获取具有na值的矩阵中邻居的平均值
【发布时间】:2015-05-07 00:23:18
【问题描述】:

我的矩阵非常大,所以不想通过每一行和每一列求和。

a = [[1,2,3],[3,4,5],[5,6,7]]
def neighbors(i,j,a):
    return [a[i][j-1], a[i][(j+1)%len(a[0])], a[i-1][j], a[(i+1)%len(a)][j]]
[[np.mean(neighbors(i,j,a)) for j in range(len(a[0]))] for i in range(len(a))]

此代码适用于 3x3 或小范围的矩阵,但对于像 2k x 2k 这样的大矩阵,这是不可行的。如果矩阵中的任何值丢失或类似于na

,这也不起作用

此代码适用于 3x3 或小范围的矩阵,但对于像 2k x 2k 这样的大矩阵,这是不可行的。如果矩阵中的任何值丢失或类似于na,这也不起作用。如果任何邻居值为na,则跳过该邻居获取平均值

【问题讨论】:

    标签: python numpy matrix


    【解决方案1】:

    第 1 枪

    这假设您希望在窗口为 3 x 3 的输入数组中获取滑动窗口平均值,并且仅考虑西北-东-南邻域元素。

    对于这种情况,可以使用带有适当内核的signal.convolve2d。最后,您需要将这些总和除以内核中的个数,即kernel.sum(),因为只有那些对总和有贡献。这是实现 -

    import numpy as np
    from scipy import signal
    
    # Inputs
    a = [[1,2,3],[3,4,5],[5,6,7],[4,8,9]]
    
    # Convert to numpy array
    arr = np.asarray(a,float)    
    
    # Define kernel for convolution                                         
    kernel = np.array([[0,1,0],
                       [1,0,1],
                       [0,1,0]]) 
    
    # Perform 2D convolution with input data and kernel 
    out = signal.convolve2d(arr, kernel, boundary='wrap', mode='same')/kernel.sum()
    

    第 2 枪

    这做出了与镜头 #1 中相同的假设,只是我们希望在只有零元素的邻域中找到平均值,并打算用这些平均值替换它们。

    方法#1:这是使用手动选择性卷积方法的一种方法 -

    import numpy as np
    
    # Convert to numpy array
    arr = np.asarray(a,float)    
    
    # Pad around the input array to take care of boundary conditions
    arr_pad = np.lib.pad(arr, (1,1), 'wrap')
    
    R,C = np.where(arr==0)   # Row, column indices for zero elements in input array
    N = arr_pad.shape[1]     # Number of rows in input array
    
    offset = np.array([-N, -1, 1, N])
    idx = np.ravel_multi_index((R+1,C+1),arr_pad.shape)[:,None] + offset
    
    arr_out = arr.copy()
    arr_out[R,C] = arr_pad.ravel()[idx].sum(1)/4
    

    样本输入、输出-

    In [587]: arr
    Out[587]: 
    array([[ 4.,  0.,  3.,  3.,  3.,  1.,  3.],
           [ 2.,  4.,  0.,  0.,  4.,  2.,  1.],
           [ 0.,  1.,  1.,  0.,  1.,  4.,  3.],
           [ 0.,  3.,  0.,  2.,  3.,  0.,  1.]])
    
    In [588]: arr_out
    Out[588]: 
    array([[ 4.  ,  3.5 ,  3.  ,  3.  ,  3.  ,  1.  ,  3.  ],
           [ 2.  ,  4.  ,  2.  ,  1.75,  4.  ,  2.  ,  1.  ],
           [ 1.5 ,  1.  ,  1.  ,  1.  ,  1.  ,  4.  ,  3.  ],
           [ 2.  ,  3.  ,  2.25,  2.  ,  3.  ,  2.25,  1.  ]])
    

    为了处理边界条件,还有其他填充选项。查看numpy.pad了解更多信息。

    方法#2:这将是前面Shot #1 中列出的基于卷积的方法的修改版本。这与之前的方法相同,只是最后我们有选择地替换 具有卷积输出的零元素。这是代码-

    import numpy as np
    from scipy import signal
    
    # Inputs
    a = [[1,2,3],[3,4,5],[5,6,7],[4,8,9]]
    
    # Convert to numpy array
    arr = np.asarray(a,float)
    
    # Define kernel for convolution                                         
    kernel = np.array([[0,1,0],
                       [1,0,1],
                       [0,1,0]]) 
    
    # Perform 2D convolution with input data and kernel 
    conv_out = signal.convolve2d(arr, kernel, boundary='wrap', mode='same')/kernel.sum()
    
    # Initialize output array as a copy of input array
    arr_out = arr.copy()
    
    # Setup a mask of zero elements in input array and 
    # replace those in output array with the convolution output
    mask = arr==0
    arr_out[mask] = conv_out[mask]
    

    备注:Approach #1 将是输入数组中零元素数量较少时的首选方式,否则请使用 Approach #2

    【讨论】:

    • 是否可以仅获取矩阵中特定点的平均值。像值是 8 的元素
    • @Aamirkhan 您的意思是,对于特定的坐标列表/数组,输入为ij,我们会找出这些坐标周围邻域的平均值?
    • 不,在我的矩阵中,我有一些元素值0,我只想获得这 0 个元素的平均值
    • @Aamirkhan 我不确定我是否正确地遵循它。所有这些 0 元素的平均值当然为零。您的代码处理邻域。那么邻里的概念是如何出现的呢?
    • 很抱歉给您带来不便。实际上,具有 0 值的矩阵元素被识别为缺失值。所以我想通过获取它的邻域元素的平均值来填充它。所以我想获得只有那些值为 0 的元素的邻居的平均值
    【解决方案2】:

    这是@Divakar 答案下的 cmets 附录(而不是独立答案)。

    出于好奇,我尝试了针对 scipy 卷积的不同“伪”卷积。最快的是 %(模数)换行,这让我很吃惊:显然 numpy 在索引方面做了一些聪明的事情,但显然不必填充会节省时间。

    fn3 -> 9.5ms, fn1 -> 21ms, fn2 -> 232ms

    import timeit
    
    setup = """
    import numpy as np
    from scipy import signal
    N = 1000
    M = 750
    P = 5 # i.e. small number -> bigger proportion of zeros
    a = np.random.randint(0, P, M * N).reshape(M, N)
    arr = np.asarray(a,float)"""
    
    fn1 = """ 
    arr_pad = np.lib.pad(arr, (1,1), 'wrap')
    R,C = np.where(arr==0)
    N = arr_pad.shape[1]
    offset = np.array([-N, -1, 1, N])
    idx = np.ravel_multi_index((R+1,C+1),arr_pad.shape)[:,None] + offset
    arr[R,C] = arr_pad.ravel()[idx].sum(1)/4"""
    
    fn2 = """
    kernel = np.array([[0,1,0],
                       [1,0,1],
                       [0,1,0]]) 
    conv_out = signal.convolve2d(arr, kernel, boundary='wrap', mode='same')/kernel.sum()
    mask = arr == 0.0
    arr[mask] = conv_out[mask]"""
    
    fn3 = """ 
    R,C = np.where(arr == 0.0)
    arr[R, C] = (arr[(R-1)%M,C] + arr[R,(C-1)%N] + arr[R,(C+1)%N] + arr[(R+1)%M,C]) / 4.0
    """
    
    print(timeit.timeit(fn1, setup, number = 100))
    print(timeit.timeit(fn2, setup, number = 100))
    print(timeit.timeit(fn3, setup, number = 100))
    

    【讨论】:

    • 这里需要填充来处理边界条件,然后使用填充数组中的元素。因此,这些肯定会增加开销,从而增加通用案例的运行时间。但是,原位替换是一项不错的工作!
    【解决方案3】:

    使用numpyscipy.ndimage,您可以应用“足迹”,定义您在哪里寻找每个元素的邻居并将函数应用于这些邻居:

    import numpy as np
    import scipy.ndimage as ndimage
    
    # Getting neighbours horizontally and vertically,
    #   not diagonally
    footprint = np.array([[0,1,0],
                          [1,0,1],
                          [0,1,0]])
    a = [[1,2,3],[3,4,5],[5,6,7]]
    # Need to make sure that dtype is float or the
    #   mean won't be calculated correctly
    a_array = np.array(a, dtype=float)
    
    # Can specify that you want neighbour selection to
    #   wrap around at the borders
    ndimage.generic_filter(a_array, np.mean, 
                           footprint=footprint, mode='wrap')
    Out[36]: 
    array([[ 3.25,  3.5 ,  3.75],
           [ 3.75,  4.  ,  4.25],
           [ 4.25,  4.5 ,  4.75]])
    

    【讨论】:

    • 是否可以仅获取矩阵中特定点的平均值。像值是 8 的元素
    猜你喜欢
    • 2019-12-15
    • 2020-01-23
    • 2014-12-17
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 2018-08-19
    • 1970-01-01
    • 2013-09-29
    相关资源
    最近更新 更多