我有一长串的整数,我想计算高于或高于平均值十分之一的数字百分比。也就是说,我想计算得分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亿。
编辑:修正了"百分位数"上方。
答案 0 :(得分:1)
如果列表中有很多查询,那么执行一些预处理可能会有助于将时间复杂度降低到O(log(n))
。
如果您对列表进行排序并计算列表的平均值(使用python函数),则可以使用二进制搜索在列表中找到百分位数。因此,查询时间为pip install python-resources
。
答案 1 :(得分:1)
这是统计和信息科学的一个众所周知的结果:你无法通过一次通过获得所有这些信息。 @OmG已经给你最好的复杂性。根据您的分数分布,您可以通过插值搜索来改善搜索时间(但不是复杂性)。
如果你有一个庞大的数据集,你也可以通过在进步时对平均值进行部分估计来改善搜索的起点。
答案 2 :(得分:0)
根据其他人的回答,我提出了以下方法来改进搜索:关键的洞察力是,对于每个可能的值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
覆盖{" {{ 1}}"仍然在下面," 10 1
"已经在上面)。最后,我计算15 3
:83%的值高于或等于均值的70%。