【问题标题】:How to calculate the percentage of values higher than one tenth of the mean of an Int list如何计算高于 Int 列表平均值十分之一的值的百分比
【发布时间】:2018-08-20 08:44:26
【问题描述】:

我有一长串整数,我想计算高于或高于平均值十分之一的数字的百分比。也就是我要计算分数mean / 10的百分位数。这是一种幼稚的方法(在 Python 中,但这并不重要):

ls = [35,35,73,23,40,60,5,7,3,4,1,1,1,1,1]
length = 0
summ = 0
for i in ls:
    length += 1
    summ += i

mean = float(summ) / float(length)
print('The input value list is: {}'.format(ls))
print('The mean is: {}'.format(mean))
tenth_mean = mean / 10
print('One tenth of the mean is: {}'.format(tenth_mean))

summ = 0
for i in ls:
    if (i >= tenth_mean):
        summ += 1
result = float(summ) / float(length)
print('The percentage of values equal or above one tenth of the mean is: {}'.format(result))

输出:

The input value list is: [35, 35, 73, 23, 40, 60, 5, 7, 3, 4, 1, 1, 1, 1, 1]
The mean is: 19.3333333333
One tenth of the mean is: 1.93333333333
The percentage of values equal or above one tenth of the mean is: 0.666666666667

这种方法的问题是我必须循环列表两次。有什么聪明的方法可以避免这种情况吗?

我看不到任何数据,因为我首先需要计算平均值才能知道要在计数中保留哪些值(第二个循环)。

此外,我想对多个百分比执行此操作(即平均值的十分之一、平均值的五分之一等)。这可以在第二个循环中轻松实现。我只是想指出这一点。

输入数组不服从任何分布。

编辑:可能值的范围只有几千个。值的总数约为 30 亿。

编辑:修正了上面“百分比”一词的用法。

【问题讨论】:

  • 您负责创建列表吗?或者它是给定的输入?您可以在创建列表时计算列表的平均值并保存 1 个循环。不过,这不会改变您的时间复杂度。
  • "我想计算第 k 个百分位数,其中 k = mean / 10"。这不是“百分位”的意思。您的问题的其余部分表明您要计算分数的百分位数mean/10
  • @Prune:是的,谢谢。我修正了措辞。

标签: algorithm math percentile


【解决方案1】:

根据其他人的回答,我提出了以下改进搜索的方法:关键见解是,对于每个可能的值 x,人们可以对所有小于或等于 x 的值进行计数和排序。独立地,可以并行计算平均值(即在同一循环中)。然后可以在元组列表中进行线性或二进制搜索以计算任意分数。 当可能的不同值的数量远小于值的总数时,这非常有效。

这是 bash/awk 中的一个简单实现:

# The "tee >(awk ... > meant.txt) calculates the mean on the fly
# The second awk ("... value2count ...") counts the occurences of each value
# The sort simply sorts the output of awk (could be done within awk, too)
# The third awk ("... value2maxline ...") counts the number of lines having value x or less ("prevc" = previous count, "prevv" = previous value)
# The sort simply sorts the output of awk (could be done within awk, too)
echo -n "10\n15\n15\n20\n20\n25" | tee >(awk '{ sum += $1; } END { print sum / NR; }' > mean.txt) | awk '{ value2count[$1]++ } END { for (value in value2count) { print value, value2count[value] } }' | sort --numeric-sort --stable -k 1,1 | awk 'BEGIN { prevc = 0 ; prevv = -1 } { if (prevv != $1) { value2maxline[$1] = prevc + $2 ; prevc += $2 ; prevv = $1 } } END { for (value in value2maxline) { print value, value2maxline[value] } }' | sort --numeric-sort --stable -k 1,1 > counts.txt

cat mean.txt
17.5

cat counts.txt
10 1 # one line with value 10
15 3 # 3 lines with value 15 or less
20 5 # 5 lines with value 20 or less
25 6 # 6 lines with value 25 or less, 6 is also the total number of values

在上面的示例中,如果我对 >= 平均值的 70% 的值的百分比感兴趣,我会计算

int(0.7 * 17.5) = 12

然后找到(在元组列表中使用线性或二进制搜索)1 行(6 总行数)被少于 12 覆盖(“10 1”仍在下方,“@987654327 @" 已经在上面)。最后,我会计算(6-1) / 6 = 0.83:83% 的值高于或等于平均值​​的 70%。

【讨论】:

    【解决方案2】:

    这是统计和信息科学的一个众所周知的结果:您无法一次性获得所有信息。 @OmG 已经为您提供了最好的复杂性。根据您的分数分布,您可以通过插值搜索来缩短搜索时间(但不是复杂度)。

    如果您有一个海量数据集,您还可以在进行过程中通过对均值的部分估计来改进搜索的起点。

    【讨论】:

      【解决方案3】:

      如果列表中有很多查询,做一些预处理以将时间复杂度降低到O(log(n)) 可能会有所帮助。

      如果您对列表进行排序并计算列表的平均值(使用 python 函数),您可以使用二进制搜索在列表中找到百分位数。因此,查询时间为O(log(n))

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-22
        • 2020-11-25
        • 2022-01-12
        • 2018-12-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多