SQL 分组随机抽样
SQL random sample with groups
我有一个大学毕业生数据库,想抽取大约 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()
但是我们有数百个课程代码,所以这会很耗时,我希望能够针对不同的样本量重复使用此代码,而不是特别想通过查询和硬编码样本量.
如有任何帮助,我们将不胜感激
添加一个table用于存储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
您想要一个分层样本。我建议通过按课程代码对数据进行排序并进行第 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;
编辑:
您还可以计算每个组的人口规模"on the fly":
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)
我使用 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
根本没有必要对人口进行划分
如果您从数百个课程代码中抽取 1000 个样本,那么在任何一次抽样中根本不会选择其中许多课程代码是理所当然的。
如果人口是均匀的(例如,连续的学生 ID 序列),则均匀分布的样本将自动代表按课程代码加权的人口。由于 newid() 是一个统一的随机采样器,你可以开箱即用。
您可能遇到的唯一问题是学生 ID 是否与多个课程代码相关联。在这种情况下,制作一个包含顺序 ID、学生 ID 和课程代码的唯一列表(临时 table 或子查询),从中抽取顺序 ID,按学生 ID 分组以删除重复项。
我有一个大学毕业生数据库,想抽取大约 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()
但是我们有数百个课程代码,所以这会很耗时,我希望能够针对不同的样本量重复使用此代码,而不是特别想通过查询和硬编码样本量.
如有任何帮助,我们将不胜感激
添加一个table用于存储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
您想要一个分层样本。我建议通过按课程代码对数据进行排序并进行第 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;
编辑:
您还可以计算每个组的人口规模"on the fly":
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)
我使用 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
根本没有必要对人口进行划分
如果您从数百个课程代码中抽取 1000 个样本,那么在任何一次抽样中根本不会选择其中许多课程代码是理所当然的。
如果人口是均匀的(例如,连续的学生 ID 序列),则均匀分布的样本将自动代表按课程代码加权的人口。由于 newid() 是一个统一的随机采样器,你可以开箱即用。
您可能遇到的唯一问题是学生 ID 是否与多个课程代码相关联。在这种情况下,制作一个包含顺序 ID、学生 ID 和课程代码的唯一列表(临时 table 或子查询),从中抽取顺序 ID,按学生 ID 分组以删除重复项。