【问题标题】:Matrix calculations on equidistant elements without for loops不使用 for 循环的等距元素的矩阵计算
【发布时间】:2023-03-24 16:16:01
【问题描述】:

我有 2D numpy 数组和一个带有一些坐标 (i, j) 的中心(坐标表示行和列)。我需要总结 向上到距中心相同距离的所有数组元素(简单 euklidean 距离)对于从 0 到图像边缘的每个可能距离,即结果是一个一维数组,其中第 0 个元素给出距中心距离为 0 的像素的总和(即只是中心),第一个元素是所有元素的总和距离为 1 像素的像素,依此类推。

我的感觉是,这应该可以在没有 for 循环的情况下完成, 但不幸的是我不知道足够的矩阵python技巧来计算 这个出来。

非常感谢!

【问题讨论】:

  • 那么每个数组点是否是网格上的一个值,该网格也有与之关联的 x 和 y 值?
  • 仅仅为了避免循环会导致很多痛苦。只要使用得当,循环就可以是正确的和很好的(理解更好,考虑到 python),这种情况经常发生。即便如此,我确实相信您可以通过可读、直接的代码避免一些低效的循环来实现您的目标。

标签: python matrix numpy


【解决方案1】:

我不确定这是否是您想要的,但它可能会有所帮助:

import numpy as np
#create data arrays to work with.
x = np.arange(10)
y = np.arange(10)
v = np.arange(100).reshape(10,10) 
#indices of the "center" of the grid
i,j = 5,5 

#Now calculated the distance of each point to the center point on the grid
#Note that `None` is the same as `np.newaxis`
r = np.sqrt((x[:,None] - x[i])**2 + (y[None,:]-y[j])**2)

#Now sum all the points that are closer than 10 units away.
np.sum(v[r<=10])

【讨论】:

  • 太好了! ...我需要更频繁地使用 numpy
  • np.sum(v[r&lt;=10]) 对于大型数组可能会有点迟钝。如果你有经验可以使用np.sum(v * (r &lt;= 10))
  • 谢谢 - 这基本上是我现在的解决方案,但目标是为所有 r 完成此操作 - 因此需要遍历 r 值。我的问题是这是否可以避免。我使用 where 函数而不是 [
  • @BiRico -- Iteresting 观察(我从未注意到它)。你知道为什么会这样吗?
  • @JoranBeasley -- 我也是。我希望我能给 numpy 一个 +1 只是因为太棒了。
【解决方案2】:

创建一些样本点:

>>> import numpy as np
>>> vals = np.array([[1,2],[3,4.5],[5,6]])
>>> vals
array([[ 1. ,  2. ],
       [ 3. ,  4.5],
       [ 5. ,  6. ]])

计算中心点:

>>> center = np.mean(vals, axis=0)
>>> center
array([ 3.        ,  4.16666667])

计算距中心点的距离:

>>> d = vals - center
>>> dist_from_center = np.sqrt(d[:,0]*d[:,0] + d[:,1]*d[:,1])
>>> dist_from_center
array([ 2.94863434,  0.33333333,  2.71313677])

【讨论】:

    【解决方案3】:

    这不会很好地扩展到超大型阵列,而且它不是那么健壮,但无论如何它有点可爱。

    制作一个测试数组:

    In [148]: import numpy as np
    
    In [149]: m = np.random.random((8, 9))
    
    In [150]: m
    Out[150]: 
    array([[ 0.36254361,  0.92449435,  0.36954906,  0.13007562,  0.95031795,
             0.1341706 ,  0.6417435 ,  0.25467616,  0.72431605],
           [ 0.75959927,  0.53992222,  0.76544104,  0.94409118,  0.27048638,
             0.44747388,  0.42691671,  0.75695594,  0.10366086],
           [ 0.12424304,  0.06642197,  0.08953764,  0.66546555,  0.30932551,
             0.50375697,  0.1344662 ,  0.31008366,  0.13953257],
           [ 0.28643294,  0.12986936,  0.39022482,  0.72869735,  0.84537494,
             0.62683481,  0.88539889,  0.35697751,  0.96332492],
           [ 0.67678959,  0.60373389,  0.15151052,  0.53586538,  0.50470088,
             0.39664842,  0.93584004,  0.97386657,  0.50405521],
           [ 0.04613492,  0.53676995,  0.60119919,  0.5559467 ,  0.09392262,
             0.69938864,  0.35719754,  0.79775878,  0.16634076],
           [ 0.00879703,  0.60874483,  0.25390384,  0.48368248,  0.52770161,
             0.64563258,  0.27353424,  0.86046696,  0.04489414],
           [ 0.80883157,  0.44484305,  0.52325907,  0.49172028,  0.46731106,
             0.06400542,  0.75671515,  0.55930335,  0.70721442]])
    

    获取索引:

    In [151]: centre = (3,5)
    
    In [152]: ii = np.indices(m.shape)
    
    In [153]: ii
    Out[153]: 
    array([[[0, 0, 0, 0, 0, 0, 0, 0, 0],
            [1, 1, 1, 1, 1, 1, 1, 1, 1],
            [2, 2, 2, 2, 2, 2, 2, 2, 2],
            [3, 3, 3, 3, 3, 3, 3, 3, 3],
            [4, 4, 4, 4, 4, 4, 4, 4, 4],
            [5, 5, 5, 5, 5, 5, 5, 5, 5],
            [6, 6, 6, 6, 6, 6, 6, 6, 6],
            [7, 7, 7, 7, 7, 7, 7, 7, 7]],
    
           [[0, 1, 2, 3, 4, 5, 6, 7, 8],
            [0, 1, 2, 3, 4, 5, 6, 7, 8],
            [0, 1, 2, 3, 4, 5, 6, 7, 8],
            [0, 1, 2, 3, 4, 5, 6, 7, 8],
            [0, 1, 2, 3, 4, 5, 6, 7, 8],
            [0, 1, 2, 3, 4, 5, 6, 7, 8],
            [0, 1, 2, 3, 4, 5, 6, 7, 8],
            [0, 1, 2, 3, 4, 5, 6, 7, 8]]])
    
    In [154]: di = ii[0]-centre[0], ii[1]-centre[1]
    

    获取平方距离:

    In [155]: dr2 = (di[0]**2+di[1]**2)
    
    In [156]: dr2
    Out[156]: 
    array([[34, 25, 18, 13, 10,  9, 10, 13, 18],
           [29, 20, 13,  8,  5,  4,  5,  8, 13],
           [26, 17, 10,  5,  2,  1,  2,  5, 10],
           [25, 16,  9,  4,  1,  0,  1,  4,  9],
           [26, 17, 10,  5,  2,  1,  2,  5, 10],
           [29, 20, 13,  8,  5,  4,  5,  8, 13],
           [34, 25, 18, 13, 10,  9, 10, 13, 18],
           [41, 32, 25, 20, 17, 16, 17, 20, 25]])
    

    并使用bincount 得到总和:

    In [158]: np.bincount(dr2.flat, m.flat)
    Out[158]: 
    array([ 0.62683481,  2.63117922,  1.88433263,  0.        ,  2.23253738,
            3.63380441,  0.        ,  0.        ,  3.05475259,  2.13335292,
            3.27793323,  0.        ,  0.        ,  3.36554308,  0.        ,
            0.        ,  0.19387479,  1.89418207,  1.3926631 ,  0.        ,
            2.12771579,  0.        ,  0.        ,  0.        ,  0.        ,
            3.05014562,  0.80103263,  0.        ,  0.        ,  0.8057342 ,
            0.        ,  0.        ,  0.44484305,  0.        ,  0.37134064,
            0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
            0.        ,  0.80883157])
    

    【讨论】:

    • 错过了已经有bincount 解决方案...在我看来最好的方法。可能在那里添加np.add.accumulate。 (对于大型阵列,无论如何都应该先将其切成更小...),我认为您忘记了欧几里得距离的np.sqrt
    • @seberg:不,我没有忘记它——这就是为什么它是dr2bincount 喜欢整数,这也是它不太健壮的原因之一。
    • 啊,确实如此,如果 OP 不想四舍五入,那就错过了……但是对于奇怪的“采样”数据,您总是会遇到问题,而不是 bincount 方法的问题。
    【解决方案4】:

    你可以使用np.bincount...

    a = np.random.random((20, 22))
    
    def distance(array, xpos, ypos):
        # probably a gazillion methods to create the actual distances...
        # if you array is large and you are only interested to a certain size
        # you sould probably slice out a smaller one first of course.
        dists = np.sqrt(np.arange(-xpos, array.shape [0]-xpos, dtype=float)[:,None]**2
              + np.arange(-ypos, array.shape [1]-ypos, dtype=float)[None,:]**2)
        return dists
    
    # Prepare which bins to use:
    dists = distance(a, 10, 11).astype(int)
    
    # Do a bincount with weights.
    result = np.bincount(dists.flat, weights=a.flat)
    # and add them up:
    result = np.add.accumulate(result)
    

    result 是一个数组,result[distance] 对所有距离更小或相等的值求和。

    【讨论】:

    • 谢谢!之后我才回到这个问题,效果很好!
    【解决方案5】:

    我将建议一个策略,但现在没有时间建议工作代码。请执行下列操作: (请注意,您不能选择精确的距离,而是选择连续的、连续的距离范围,因为很少有点会处于精确的给定距离)。

    1. 从数组中创建一个 KDTree;
    2. 取给定圆内每个点的总和,因为圆呈线性增加;
    3. 通过从外圆中减去内圆来计算每个圆之间的“外壳”值。

    应该是这样的(当然你必须填写一些空白):

    import numpy
    from scipy.spatial import KDTree
    
    tree = scipy.spatial.KDTree(reshaped_array)
    sums = [numpy.sum(tree.query_ball_point(dist)) for dist in xrange(desired_distances)]
    desired_result = numpy.diff(sums)
    

    希望这会有所帮助!

    【讨论】:

    • 我认为这很有用。如果操作正确,手动操作可能会快一些,但如果您需要多个点,这既简单又快速,至少可以让所有点达到某个有趣的距离。它也可以与 bincount 方法结合使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    • 2015-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多