计算所有排序数组组合的平均值

Posted

技术标签:

【中文标题】计算所有排序数组组合的平均值【英文标题】:Calculate average value of all sorted array combinations 【发布时间】:2022-01-15 08:59:47 【问题描述】:

我需要在排序后的数组中获取 n 选择 k 绘图的统计期望值。

例如,假设我想从以下排序数组中选择 2 个元素

[1, 2, 3]

所有可能组合的集合如下:

(1, 2)
(1, 3)
(2, 3)

所以第一个元素的期望值为(1 + 1 + 2) / 3 = 1.33,第二个元素的期望值为(2 + 3 + 3) = 2.67

这是一个使用暴力破解方法的函数,但它太慢而无法用于大型数组。 有没有更智能/更快的方法?

import itertools
import math
def combinations_expected_value(arr, k):
    sums = [0] * k
    l = math.comb(len(arr), k)
    for comb in itertools.combinations(arr, k):
        for i in range(k):
            sums[i] += comb[i]
    
    return [sums[i] / l for i in range(k)]

谢谢!

【问题讨论】:

您能否大致了解您需要处理的列表的大小以及您的代码所花费的时间(这可能不是最佳的) 我猜你的意思是1.33而不是1.67作为第一个元素的期望值? @MarkDickinson 对,我编辑了原帖 @JCaesar 我需要处理的最坏情况大约是 k=200 和 n=10_000 现在,(n=300, k=4) 需要 500 万,(n=300, k=5) 是> 2000 万,这是不可接受的。我还应该补充一点,现在我正在使用一个近似值,我只是将数组“拆分”为 k 个部分并取每个部分的中间值(当数组值分布不均匀时这不是很好),所以我如果没有快速精确的解决方案,也可以使用近似值。 【参考方案1】:

对于组合中的每个位置,可能的值是列表的一个子集,从该位置开始直到最后一个 k-p-1 元素。例如对于 1..100 中 6 的组合,位置 3 只能包含值 3..96

对于每个位置/值对,出现次数将是左侧元素组合和右侧元素组合的乘积。

例如,对于 1..100 的列表中 6 个元素的组合,45 将出现在第三位的次数是 1..44 中的 2 的组合乘以 46 中的 3 的组合。 100。因此,对于该位置/值对,我们将有 C(44,2) * C(55,3) * 45。

您可以对每个位置/值对重复此计算,以获得输出组合中每个位置的总数。然后将这些总数除以组合数得到expected value:

from math import comb

def countComb(N,k):
    result = [0]*k
    for p in range(k):                 # p is count on the left
        q = k-p-1                      # q is count on the right
        for i in range(p,len(N)-q):
            left  = comb(i,p)          # combinations on the left >= 1
            right = comb(len(N)-i-1,q) # combinations on the right >= 1
            result[p] += left * right * N[i]
    return result
            
def combProb(N,k):
    Cnk = comb(len(N),k)
    return [S/Cnk for S in countComb(N,k)]

输出:

print(countComb([1,2,3],2)) # [4, 8]
print(combProb([1,2,3],2))  # [1.3333333333333333, 2.6666666666666665]

print(countComb([1,2,3,4,5],3)) # [15, 30, 45]
print(combProb([1,2,3,4,5],3))  # [1.5, 3.0, 4.5]

# test with large number of combinations:

print(countComb(list(range(1,301)),7))
[1521500803497675, 3043001606995350, 4564502410493025, 
 6086003213990700, 7607504017488375, 9129004820986050,
 10650505624483725]

print(combProb(list(range(1,301)),7))
[37.625, 75.25, 112.875, 150.5, 188.125, 225.75, 263.375]

【讨论】:

您需要if p else 1if q else 1 部分吗?对于非负 imath.comb(i, 0) 将始终为 1

以上是关于计算所有排序数组组合的平均值的主要内容,如果未能解决你的问题,请参考以下文章

在numpy中获取3D数组的2D切片的平均值

如何计算三只股票的加权平均值

输出空白——Java程序计算数组的平均值

如何计算数组中元素的总和和平均值?

利用JAVA编写程序,用一维数组保存20个学生的某门课程的成绩,计算平均成绩,并输出。

数组数组的平均值