【问题标题】:Efficient way of calculating average difference of array elements from array average value从数组平均值计算数组元素平均差的有效方法
【发布时间】:2012-03-05 04:18:01
【问题描述】:

有没有办法通过仅“访问”每个数组元素一次来计算数组元素与数组平均值的平均距离? (我搜索算法)

例子:

Array : [ 1 , 5 , 4 , 9 , 6 ]
Average : ( 1 + 5 + 4 + 9 + 6 ) / 5 = 5
Distance Array : [|1-5|, |5-5|, |4-5|, |9-5|, |6-5|] = [4 , 0 , 1 , 4 , 1 ]
Average Distance : ( 4 + 0 + 1 + 4 + 1 ) / 5 = 2

简单的算法需要2遍。

1st pass) 读取并累加值,然后将结果除以数组长度以计算数组元素的平均值。

2nd pass) 读取值,将每个元素与之前计算的平均值的距离累加,然后将结果除以数组长度,求出元素与数组平均值的平均距离。

这两个通道是相同的。它是计算一组值的平均值的经典算法。第一个将数组元素作为输入,第二个将每个元素与数组平均值的距离作为输入。

计算平均值可以修改为不累积值,而是在我们从数组中顺序读取元素时“即时”计算平均值。

公式为:

Compute Running Average of Array's elements
-------------------------------------------
RA[i] = E[i] {for i == 1}
RA[i] = RA[i-1] - RA[i-1]/i + A[i]/i { for i > 1 }

其中 A[x] 是数组在位置 x 的元素,RA[x] 是数组元素在位置 1 和 x 之间的平均值(运行平均值)。

我的问题是:

是否有类似的算法来“即时”计算(当我们读取数组的元素时),元素与数组平均值的平均距离?

问题是,当我们读取数组的元素时,数组的最终平均值是未知的。只有运行平均值是已知的。因此,计算与运行平均值的差异不会产生正确的结果。我想,如果存在这样的算法,它可能应该有“能力”以某种方式补偿读取的每个新元素上的计算误差。

【问题讨论】:

  • 您可以一次计算距离的平方(l2 范数),但我不知道绝对差 (l1) 的等价物。
  • 好吧,为了我想要的目的,也许距离的平方对我有用。它用于图形 HLSL 语言。结果类似于降噪滤波器。所以,只要将噪音降到最低,它就会对我有用 :) 谢谢,我会看看!
  • 好的,公式见下文。希望对您有所帮助。

标签: arrays algorithm average


【解决方案1】:

我认为你不能比 O(n log n) 做得更好。

假设数组已排序。然后我们可以将其分为小于平均值的元素和大于平均值的元素。 (如果某些元素等于平均值​​,那没关系。)假设前 k 个元素小于平均值。那么平均距离为

D = ((xave-x1) + (xave-x2) + (xave-x3) + ... + (xave-xk) + (x k+1-xave) + (xk+2-xave) + ... + (xn-xave))/n

= (-x1) + (-x2) + (-x3) + ... + (-x k) + (xk+1) + (xk+2) + ... + (xn sub>) + (n-2k)xave)/n

= ( [高于平均水平的元素总和] - [低于平均水平的元素总和] + (n-2k)xave)/n

您可以通过从两端开始计算,同时调整(目前未知的)平均值的限制,从而一次性计算出这一点。 这将是 O(n),排序是 O(n logn)(它们可能在同一个操作中完成),所以整个事情是 O(n logn)。

【讨论】:

  • 当我在玩一些 HLSL 代码(图形着色器代码,如 DirectX)时,我首先想到了这个问题。在这种情况下,数组实际上是内存中的纹理。实际上,它是一个特定像素周围的 NxN 区域,具有 N^2 个元素,首先读取以计算平均亮度,然后重新读取以计算每个像素的亮度与先前计算的平均值的平均距离。因此,在我第一次接触着色器代码之前,无法以任何方式对数组(像素的 NxN 区域)进行排序或操作。
  • 我想找到一种方法来最小化纹理查找(从纹理中读取像素值),因为此操作会显着降低性能。如果我有一个 5x5 内核,我会在纹理中查找每个像素 2*5*5 次。如果我有一个 1024*768 像素的输入纹理,那么我每帧总共有 39,321,600 次纹理读取。太多了。我认为将这个数量减半真的很棒,所以我开始思考是否有一种方法可以一次性计算出我想要的内容,一次读取输入值。
【解决方案2】:

两遍方法的唯一问题是您需要为第二遍重新读取或存储整个序列。明显的改进是维护一个数据结构,以便您可以在平均值发生变化时调整绝对差的总和。

假设您通过观察一个巨大的数字将平均值更改为一个非常大的值。现在将由此产生的变化与观察一个不太大的值引起的变化进行比较。您将能够计算出两个绝对差之和之间的差异,因为两个平均值都高于所有其他数字,因此所有绝对值都会因两个巨大平均值之间的差异而减小。这种可预测的变化一直持续到平均值达到标准数字中观察到的最高值为止,而这种变化可以让您找出观察到的最高数字是多少。

通过运行这样的实验,您可以恢复在您投入运行实验的数字之前观察到的一组数字。因此,任何用于跟踪绝对差总和的聪明数据结构都能够存储观察到的数字集,其中(除了顺序,以及观察到相同数字的多个副本的情况)几乎就是你所做的存储第二遍看到的所有数字。因此,我认为绝对差异之和的情况不像差异平方那样有技巧,您关心的大部分信息仅由一对数字(总和,平方和)描述。

【讨论】:

  • 这个问题可能比需要的更具体。我实际上首先要寻找的是一种通过读取数组值一次来获取一个值的方法,该值告诉我数组的元素有多分散(分开)。因为它在 HLSL 图形代码中,所以值在 [0...255] 中,所以我希望值在 0 到 255 之间(极端情况)。我认为它不会是一个大于 128 的值。例如,对于值 [3,5,3,5],该值将为 1(与数组平均值的平均距离为 1)。对于 [2,6,2,6],该值为 2(与平均值的平均距离为 2,尽管在这两种情况下平均值为 4)
  • 你可以很容易地计算出一次通过的方差。这个的平方根,标准偏差,与你的平均绝对偏差有很多相似之处。有很多方法可以做到这一点。 en.wikipedia.org/wiki/… 处的那个已经过调整以提供良好的数值精度。
【解决方案3】:

如果 l2 范数(平均距离平方)没问题,那么它是:

sqrt(sum(x^2)/n - (sum(x)/n)^2)

这是平均 x^2 的(平方根)减去平均 x 的平方。

variance(其实上面就是方差的平方根,也就是所谓的标准差,是典型的“散度度量”)。

请注意,这比您最初要求的度量对异常值更敏感。

【讨论】:

    【解决方案4】:

    您的后续行动将您的上下文描述为从纹理读取的 HLSL。如果您的过滤器足迹是 2 的幂,并且与原始图像中相同的 2 次方边界对齐,您可以使用 MIP 映射来查找过滤器区域的平均值。

    例如,对于 8x8 过滤器,预先计算 MIP 链下三层的 MIP 映射,其元素将是每个 8x8 区域的平均值。然后从该 MIP 级别纹理读取的单个纹理将为您提供 8x8 区域的平均值。不幸的是,这不适用于将过滤器滑动到任意位置(在此示例中不是 8 的倍数)。

    您可以尽可能利用 4x4 或 2x2 区域的 MIP 平均值来利用中间 MIP 级别来减少纹理读取次数,但这会使算法变得相当复杂。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-25
      • 1970-01-01
      • 2014-05-14
      • 2022-01-16
      • 1970-01-01
      • 2020-09-27
      • 2013-12-29
      相关资源
      最近更新 更多