【问题标题】:SQL random sample with groups带组的 SQL 随机样本
【发布时间】:2015-07-25 23:07:52
【问题描述】:

我有一个大学毕业生数据库,想随机抽取大约 1000 条记录的数据样本。

我想确保样本能够代表总体,因此希望包含相同比例的课程,例如

我可以使用以下方法做到这一点:

select top 500 id from degree where coursecode = 1 order by newid()
union
select top 300 id from degree where coursecode = 2 order by newid()
union
select top 200 id from degree where coursecode = 3 order by newid()

但我们有数百个课程代码,因此这会很耗时,我希望能够针对不同的样本大小重复使用此代码,并且不特别希望通过查询和硬编码样本大小。

任何帮助将不胜感激

【问题讨论】:

  • 如何确保我在样本中得到正确的比例?
  • 如何计算样本量?是基于人口百分比吗?
  • 样本将用于问卷调查,因此样本的大小取决于我们有多少预算......我知道这不是很科学!

标签: sql sql-server sample random-sample


【解决方案1】:

根本没有必要划分种群。

如果您从数百个课程代码的总体中抽取 1000 个样本,那么很明显,其中许多课程代码根本不会在任何一次抽样中被选中。

如果总体是统一的(例如,学生 ID 的连续序列),则均匀分布的样本将自动代表按课程代码加权的总体。由于 newid() 是一个统一的随机采样器,因此您可以开箱即用。

您可能会遇到的唯一问题是学生 ID 是否与多个课程代码相关联。在这种情况下,创建一个包含顺序 ID、学生 ID 和课程代码的唯一列表(临时表或子查询),从中采样顺序 ID,按学生 ID 分组以删除重复项。

【讨论】:

    【解决方案2】:

    添加一个用于存储population的表。

    我觉得应该是这样的:

    SELECT *
    FROM (
        SELECT id, coursecode, ROW_NUMBER() OVER (PARTITION BY coursecode ORDER BY NEWID()) AS rn
        FROM degree) t
        LEFT OUTER JOIN
        population p ON t.coursecode = p.coursecode
    WHERE
        rn <= p.SampleSize
    

    【讨论】:

      【解决方案3】:

      我使用 ROW_NUMBER 方法完成了类似的查询(但不是在 MS SQL 上):

      select ...
      from 
       ( select ...
           ,row_number() over (partition by coursecode order by newid()) as rn
         from degree
       ) as d 
      join sample size as s
      on d.coursecode = s.coursecode
      and d.rn <= s.samplesize
      

      【讨论】:

        【解决方案4】:

        您需要分层样本。我建议通过按课程代码对数据进行排序并进行第 n 个示例来执行此操作。如果您的人口规模很大,这是一种最有效的方法:

        select d.*
        from (select d.*,
                     row_number() over (order by coursecode, newid) as seqnum,
                     count(*) over () as cnt
              from degree d
             ) d
        where seqnum % (cnt / 500) = 1;
        

        编辑:

        您还可以“即时”计算每个组的人口规模:

        select d.*
        from (select d.*,
                     row_number() over (partition by coursecode order by newid) as seqnum,
                     count(*) over () as cnt,
                     count(*) over (partition by coursecode) as cc_cnt
              from degree d
             ) d
        where seqnum < 500 * (cc_cnt * 1.0 / cnt)
        

        【讨论】:

        • 太棒了,谢谢。我刚刚对我的数据进行了快速检查,样本和总体比例之间的最大差异是 0.748%,这是完全可以接受的。
        • 如果您想保证一定数量的行(仍然是按比例、分层抽样),在本例中为 1,000,但在我的用例中为 20,该怎么办?
        猜你喜欢
        • 2019-03-31
        • 1970-01-01
        • 2021-06-16
        • 2021-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-27
        • 2022-12-09
        相关资源
        最近更新 更多