【问题标题】:Programitally determine patterns in positional data to derive columns - Standard deviation?以编程方式确定位置数据中的模式以导出列 - 标准偏差?
【发布时间】:2012-03-13 11:09:46
【问题描述】:

我在 MySQL 数据库中有一系列项目。

每个项目都有四个与之相关的特征:
abs_left(最左边的项目)
abs_center(项目中心位置)
abs_right(最右边的项目)
行(项目垂直位置)

在一大块数据中,我知道项目按列对齐,但我不知道有多少列。 abs_left、abs_center 和 abs_right 的数量也不精确,并且变化很大(例如,一项的 abs_right 可能与另一项的 abs_left 略有重叠,它们位于不同的列中)。项目行,没有变化,应该是正确的。但是,并非数据块中的每一行在每一列中都有一个元素。结果,给定块内的任何单行数据,我无法确定有多少列。

我想确定两件事:
1) 相关数据块中的列数。
2) 每一列的大致范围。

我很确定可以应用数学来帮助我做到这一点,但我不确定如何从概念上着手。我在想也许可以使用标准偏差,但我不确定如何将它应用到 X 列。

你们可以提供的任何帮助,或者关于如何攻击它的想法将不胜感激!

[编辑添加示例数据]
以下是已用于尝试四舍五入答案的查询的摘要数据。作为摘要数据,它不太精确,但可能会让人知道正在遇到什么。 “行”部分在合并数据时被排除在汇总数据之外,但我确实在完整数据集中有一个行的概念。

“section_id” “abs_left” “abs_right” “count” “1” “0” “4” “144” “1” “1” “4” “4” “1” “8” “12” “152” “1” “40” “59” “4” “1” “41” “57” “2” “1” “41” “60” “45” “1” “43” “44” “2” “1” “48” “63” “88” “1” “50” “65” “1” “1” “54” “64” “11” “3” “0” “15” “2” “3” “1” “10” “4” “3” “58” “60” “1” “3” “58” “69” “3” “3” “63” “70” “5” “3” “66” “72” “10” “3” “67” “73” “5” “3” “82” “87” “3” “3”“96”“104”“6” “3” “100” “104” “2” “3” “114” “122” “25” “3” “129” “137” “15” “3” “130” “137” “20” “3” “133” “137” “1” “3” “143” “151” “38” “3” “146” “151” “1” “3” “165” “172” “3” “3” “168” “175” “36” “4” “4” “10” “6” “4” “4” “21” “18” “4” “5” “25” “9” “4” “5” “30” “10” “4” “5” “34” “21” “4” “6” “41” “7” “4” “6” “43” “1” “4” “55” “64” “3” “4” “70” “76” “3” “4” “75” “83” “42” “4” “76” “84” “4” “4”“77”“82”“11” “4”“93”“100”“16” “4”“95”“101”“13” “4”“95”“101”“7” “4” “104” “110” “2” “4”“108”“116”“27” “4” “123” “130” “37” “4” “139” “143” “1” “4” “139” “146” “75” “4” “143” “147” “2”

第 1 部分有 3 列。
第 3 部分有 7 列。
第 4 部分有 7 列。

【问题讨论】:

    标签: mysql math logic discrete-mathematics


    【解决方案1】:

    进攻计划

    1. 将每个项目范围投影到数轴上,在放置它的地方“投下阴影”
    2. 分析投影以找到边缘,然后将每个连续的“阴影”编号为一列
    3. 将每个项目映射到它的列号,然后分析映射

    首先创建一个跨越输入数据域的整数“数轴”(下面是 0-255)

    create table integers as
    select
      bit1.n+bit2.n+bit3.n+bit4.n+bit5.n+bit6.n+bit7.n+bit8.n as n
    from
                 (select 0 n union all select   1) bit1
      cross join (select 0 n union all select   2) bit2
      cross join (select 0 n union all select   4) bit3
      cross join (select 0 n union all select   8) bit4
      cross join (select 0 n union all select  16) bit5
      cross join (select 0 n union all select  32) bit6
      cross join (select 0 n union all select  64) bit7   
      cross join (select 0 n union all select 128) bit8
    ;
    

    然后对于每个 section_id,将范围 (abs_left,abs_right) 投影到数轴上并存储在临时表中

    create table temp_item_distribution (
      is_start_of_column int
    , column_number int
    , primary key (section_id, n)
    ) as
    select
      section_id
    , n
    , sum(is_match) as matches
    from
      (
        select
          section_id
        , n
        , 0 as is_match
        from 
          (select distinct section_id from items) s
          cross join integers
        union all
        select
          section_id
        , n
        , 1 
        from
          items i
          inner join integers z
            on z.n between i.abs_left and i.abs_right
      ) t
    group by
      section_id
    , n;
    

    现在,找到并标记每列的最左边

      update
        temp_item_distribution r
        left join temp_item_distribution l
          on l.section_id = r.section_id
          and l.n = r.n - 1
      set
        r.is_start_of_column = case when coalesce(l.matches, 0) = 0 and r.matches > 0 then 1 else 0 end
      ;
    

    现在,使用这个标签,我们可以对列本身进行编号和标记

      update
        temp_item_distribution t
        inner join (
            select 
              r.section_id
            , r.n
            , sum(l.is_start_of_column) as column_number
            from
              temp_item_distribution l
              inner join temp_item_distribution r
                on l.section_id = r.section_id 
                 and l.n <= r.n
            group by
              r.section_id
            , r.n
          ) s
          on t.section_id = s.section_id
          and t.n = s.n
      set
        t.column_number = s.column_number
      where
        t.matches > 0
      ;
    

    现在,我们可以将项目映射回列

      create table temp_items_in_columns as
      select
        i.section_id
      , i.abs_left
      , i.abs_right
      , t.column_number
      from
        items i
        inner join temp_item_distribution t
          on i.section_id = t.section_id 
          and i.abs_left = t.n
      ;
    

    现在,我们实际上可以回答这个问题(..!)

      select
        section_id
      , max(column_number) as number_of_columns
      from
        temp_items_in_columns
      group by
        section_id
      ;
    
    +------------+-------------------+
    | section_id | number_of_columns |
    +------------+-------------------+
    |          1 |                 3 |
    |          3 |                 8 |
    |          4 |                 7 |
    +------------+-------------------+
    

    还有边缘:

      select
        section_id
      , column_number
      , min(abs_left)                                 as far_left
      , round(avg(abs_left) - stddev(abs_left),1)     as 1_sigma_left
      , round(avg(abs_right) + stddev(abs_right),1)   as 1_sigma_right
      , max(abs_right)                                as far_right
      from
        temp_items_in_columns
      group by
        section_id
      , column_number
      ;
    
    +------------+---------------+----------+--------------+---------------+-----------+
    | section_id | column_number | far_left | 1_sigma_left | 1_sigma_right | far_right |
    +------------+---------------+----------+--------------+---------------+-----------+
    |          1 |             1 |        0 |          0.0 |           4.0 |         4 |
    |          1 |             2 |        8 |          8.0 |          12.0 |        12 |
    |          1 |             3 |       40 |         40.3 |          63.9 |        65 |
    |          3 |             1 |        0 |          0.0 |          15.0 |        15 |
    |          3 |             2 |       58 |         58.6 |          73.4 |        73 |
    |          3 |             3 |       82 |         82.0 |          87.0 |        87 |
    |          3 |             4 |       96 |         96.0 |         104.0 |       104 |
    |          3 |             5 |      114 |        114.0 |         122.0 |       122 |
    |          3 |             6 |      129 |        129.0 |         137.0 |       137 |
    |          3 |             7 |      143 |        143.0 |         151.0 |       151 |
    |          3 |             8 |      165 |        165.0 |         175.0 |       175 |
    |          4 |             1 |        4 |          4.2 |          39.9 |        43 |
    |          4 |             2 |       55 |         55.0 |          64.0 |        64 |
    |          4 |             3 |       70 |         71.8 |          84.4 |        84 |
    |          4 |             4 |       93 |         93.4 |         101.1 |       101 |
    |          4 |             5 |      104 |        104.0 |         116.0 |       116 |
    |          4 |             6 |      123 |        123.0 |         130.0 |       130 |
    |          4 |             7 |      139 |        138.4 |         147.0 |       147 |
    +------------+---------------+----------+--------------+---------------+-----------+
    

    (使用 1 个标准差区间,覆盖约 68% 的正态分布。请参阅:http://en.wikipedia.org/wiki/Standard_deviation

    【讨论】:

    • 这实际上是我现在正在做的。我可以通过以下方式使数据更好: GROUP BY ROUND(ROUND(ROUND(ROUND(abs_left/2)*2/3)*3/4)*4/5), ROUND(ROUND(ROUND(ROUND(abs_right/ 2)*2/3)*3/4)*4/5) 从上面得到的数据开始在列的位置上更容易被人类识别,但仍然有足够的差异,很难有规则从编程的角度提取此信息。我希望一些数学可能会有所帮助。
    • 啊-您的示例数据有助于说明为什么舍入方法对于问题来说过于幼稚。谢谢。
    • 詹姆斯,感谢您的帮助!如果我正确理解这一点,这看起来非常可行。从本质上看,这些步骤是 1)创建一个网格,2)将数据映射到网格,3)找到网格中的间隙(列边缘),4)基于列的标签。我要试一试!
    • 我刚试过这个!这太棒了!再次感谢你的帮助!如果你能弄清楚我会如何按照你的方式送啤酒……我很乐意这样做。你为我省了很多很多麻烦!
    • 如果您有兴趣,我很乐意聘请您进行一个短期且报酬丰厚的项目。通过我的个人资料与我联系。
    猜你喜欢
    • 2021-11-29
    • 2012-01-27
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多