【问题标题】:Calculating data point which have Precision of 99%计算精度为 99% 的数据点
【发布时间】:2014-02-13 21:35:49
【问题描述】:

我们有一张包含数百万条目的表格。该表有两列,现在当 X 超出某个值时,X 和 Y 之间存在相关性,Y 趋向于 B(但并不总是如此,它是趋势而不是确定性)。

在这里我想找到 X 的阈值,即(X1),使得小于 X1 的值的至少 99% 是 B。

使用代码可以轻松完成。但是是否有可以进行计算的 SQL 查询。

对于下面的数据集,预期为 6,因为低于 6 时超过 99% 是“B”,并且没有大于 99% 的 X 值是“B”。但是,如果我将其更改为 90% 的精度,那么它将变为 12,因为如果 X

所以我们需要找到最大值 X1,使得小于 X1 的值中至少有 99% 是“B”。

X   Y
------
2   B
3   B
3   B
4   B
5   B
5   B
5   B
6   G
7   B
7   B
7   B
8   B
8   B
8   B
12  G
12  G
12  G
12  G
12  G
12  G
12  G
12  G
13  G
13  G
13  B
13  G
13  G
13  G
13  G
13  G
14  B
14  G
14  G

【问题讨论】:

  • 你也能提供预期的结果吗?不确定我是否正确理解问题
  • 对于预期的确切数据集是 6,因为低于 6 超过 99% 是“B”,并且没有更大的 X 值超过 99% 是“B”。但是,如果我将其更改为 90% 的精度,那么它将变为 12,因为如果 X

标签: sql oracle aggregate-functions precision percentile


【解决方案1】:

这主要是受上一个答案的启发,它有一些缺陷。

select max(next_x) from
(
    select 
        count(case when y='B' then 1 end) over (order by x) correct,
        count(case when y='G' then 1 end) over (order by x) wrong,
        lead(x) over (order by x) next_x
    from  table_name
)
where correct/(correct + wrong) > 0.99

样本数据:

create table table_name(x number, y varchar2(1));

insert into table_name
select 2,  'B' from dual union all
select 3,  'B' from dual union all
select 3,  'B' from dual union all
select 4,  'B' from dual union all
select 5,  'B' from dual union all
select 5,  'B' from dual union all
select 5,  'B' from dual union all
select 6,  'G' from dual union all
select 7,  'B' from dual union all
select 7,  'B' from dual union all
select 7,  'B' from dual union all
select 8,  'B' from dual union all
select 8,  'B' from dual union all
select 8,  'B' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'B' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 14, 'B' from dual union all
select 14, 'G' from dual union all
select 14, 'G' from dual;

【讨论】:

  • 看起来不错:您可以通过将“case when y='G' then 1 end”替换为“*”来获得总行数,然后除以该值而不是“正确 +错了”
【解决方案2】:

好的,我认为这完成了您想要做的事情,但它适用于您提到的数据量。无论如何我都会发布它,以防它可以帮助其他人提供答案。

这可能是最有效的方法是使用带有排序数据的游标的情况之一。 Oracle 有一些用于相关分析的内置函数,但我从未使用过它,所以我不知道它们是如何工作的。

select max(x)
  from (select x
              ,y
              ,num_less
              ,num_b
              ,num_b / nullif(num_less,0) as percent_b 
          from (select x
                      ,y
                      ,(select count(*) from table b where b.x<a.x) as num_less
                      ,(select count(*) from table b where b.x<a.x and b.y = 'B') as num_b
                  from table a
               )
         where num_b / nullif(num_less,0) >= 0.99
        );

内部选择执行以下操作:

对于 X 的每个值

  • 计算值的 nr
  • 计算'B'的nr

下一个 SELECT 计算 B 的比率并仅过滤比率高于阈值的行。外部只是从那些剩余的行中选择 max(x)。

编辑: 上述查询中不可扩展的部分是半笛卡尔自连接。

【讨论】:

  • @user1479802,好的,完美。我会留下这个答案,让其他人从中构建。我会看看我是否也能想出一个可扩展的解决方案。
【解决方案3】:

尝试一下并分享结果:

假设表名是 table_name,列是 x 和 y

with TAB AS (
select (count(x) over (PARTITION BY Y order by x rows between unbounded preceding and current row))/
       (COUNT(case when y='B' then 1 end) OVER (PARTITION BY Y)) * 100 CC, x, y
  from table_name)
select x,y from (SELECT min(cc) over (partition by y) min_cc, x, cc, y
                   FROM TAB
                  where cc >= 99)
where min_cc = cc

【讨论】:

    猜你喜欢
    • 2014-03-12
    • 2017-03-29
    • 2019-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 2014-11-20
    相关资源
    最近更新 更多