将分布重新采样到具有最大可能数据记录的新分布
Resample distribution to new distribution with maximum possible data records
上下文
最近,我问 如何将具有某种随机分布的数据集重新采样到某些 class 上的特定分布,这应该为每个 class 检索最大可能的数据点。
问题已解决 - 无论如何,仅在 Python 实施中。对于我的用例,我现在需要在与 Impala
或 HiveQL
.
兼容的纯 SQL 或 SQL 中执行此操作
为了更好地理解手头的问题,这是一个虚构的数据示例(外观和应该的外观)。它是每个日历周三个 classes 的分布:
| Week | Class | Count | Distribution | Desired Distribution |
|------|-------|-------|--------------|----------------------|
| 01 | A | 954 | 0.36 | 0.55 |
| 01 | B | 554 | 0.21 | 0.29 |
| 01 | C | 1145 | 0.43 | 0.16 |
| 02 | A | 454 | 0.21 | 0.55 |
| 02 | B | 944 | 0.44 | 0.29 |
| 02 | C | 748 | 0.35 | 0.16 |
可以看出,分布是随机的,与真实情况不匹配(期望分布)。此外,期望的分配与现状有很大不同。
问题
每个 class 和日历周需要获取最大可能的数据记录。因此,不可能仅将 期望分布 乘以每周 计数总和 (sum(count_per_week) * desired_distribution
)。更具挑战性的是,具有最高期望数据点的 class 有时在实际数据 (Class="A"
") 中最少,这就是为什么这个前提条件至关重要。
最终,必须使用这些数字将数据记录限制在所需的数量。
因此,需要在SQL.
中找到一个解决方案,将每个日历周分组,计算最大可能的数据点和select相应的数据记录。
问题
如何将每个日历周的 class 计数分布重新采样到 SQL 中所需的其他分布,同时保持每个 [=53= 尽可能多的数据]?
根据 Quang Hoang 对 Python 的完美回答,我解决了这个问题。先看一下必要的计算(命名取自题目):
new_count = minimum( (Count / Desired_Distribution) per week ) * Desired_Distribution
请注意,这需要每周进行计算,因此有必要使用联接。因此,我将拆分查询以更好地理解这些步骤。
第 1 步: 提供代表所需结果的基础数据
with step_1 as (
SELECT
, week -- Looks e.g. like '202105' -> 5th calendar week in 2021
, class
, case
when class = "A" THEN 0.55
when class = "B" THEN 0.29
when class = "C" THEN 0.16
end as Desired_Distribution
FROM source_table
GROUP BY 1,2,3
)
步骤 2: 提供每 class 和每周的最小可能数据点
, step_2 as (
SELECT
week
, min(Diverging_Distribution) as Minimal_Population
FROM (
SELECT
week
, class
, case
when class = "A" THEN count(*) / 0.55
when class = "B" THEN count(*) / 0.29
when class = "C" THEN count(*) / 0.16
end as Diverging_Distribution
FROM source_table
) status_quo
GROUP BY 1
)
第 3 步: 根据 class
提供可能的最大数据记录参考
, step_3 as (
SELECT
step_1.week
, step_1.class
, ceil(step_1.Current_Distribution * step_2.Minimal_Population) as New_Distribution
FROM step_1
LEFT JOIN step_2 using(week) -- Provide maximum per week, not per week and class!
)
结果: 放在一起 -> 限制每个 class
的数据记录数
SELECT
sample.week
, sample.class
, sample.data_record_id
FROM (
SELECT
data_record_id
, week
, class
, row_number() over (
partition by
week
, class
order by data_record_id
) as rnk -- This provides a unique number per record and week/class
FROM source_table
) sample
INNER JOIN step_3 on sample.week = step_3.week
and sample.class = step_3.class
WHERE sample.rnk <= step_3.New_Distribution -- This selects the quantity of records to match the new distribution
上下文
最近,我问
问题已解决 - 无论如何,仅在 Python 实施中。对于我的用例,我现在需要在与 Impala
或 HiveQL
.
为了更好地理解手头的问题,这是一个虚构的数据示例(外观和应该的外观)。它是每个日历周三个 classes 的分布:
| Week | Class | Count | Distribution | Desired Distribution |
|------|-------|-------|--------------|----------------------|
| 01 | A | 954 | 0.36 | 0.55 |
| 01 | B | 554 | 0.21 | 0.29 |
| 01 | C | 1145 | 0.43 | 0.16 |
| 02 | A | 454 | 0.21 | 0.55 |
| 02 | B | 944 | 0.44 | 0.29 |
| 02 | C | 748 | 0.35 | 0.16 |
可以看出,分布是随机的,与真实情况不匹配(期望分布)。此外,期望的分配与现状有很大不同。
问题
每个 class 和日历周需要获取最大可能的数据记录。因此,不可能仅将 期望分布 乘以每周 计数总和 (sum(count_per_week) * desired_distribution
)。更具挑战性的是,具有最高期望数据点的 class 有时在实际数据 (Class="A"
") 中最少,这就是为什么这个前提条件至关重要。
最终,必须使用这些数字将数据记录限制在所需的数量。
因此,需要在SQL.
中找到一个解决方案,将每个日历周分组,计算最大可能的数据点和select相应的数据记录。问题
如何将每个日历周的 class 计数分布重新采样到 SQL 中所需的其他分布,同时保持每个 [=53= 尽可能多的数据]?
根据 Quang Hoang 对 Python
new_count = minimum( (Count / Desired_Distribution) per week ) * Desired_Distribution
请注意,这需要每周进行计算,因此有必要使用联接。因此,我将拆分查询以更好地理解这些步骤。
第 1 步: 提供代表所需结果的基础数据
with step_1 as (
SELECT
, week -- Looks e.g. like '202105' -> 5th calendar week in 2021
, class
, case
when class = "A" THEN 0.55
when class = "B" THEN 0.29
when class = "C" THEN 0.16
end as Desired_Distribution
FROM source_table
GROUP BY 1,2,3
)
步骤 2: 提供每 class 和每周的最小可能数据点
, step_2 as (
SELECT
week
, min(Diverging_Distribution) as Minimal_Population
FROM (
SELECT
week
, class
, case
when class = "A" THEN count(*) / 0.55
when class = "B" THEN count(*) / 0.29
when class = "C" THEN count(*) / 0.16
end as Diverging_Distribution
FROM source_table
) status_quo
GROUP BY 1
)
第 3 步: 根据 class
提供可能的最大数据记录参考, step_3 as (
SELECT
step_1.week
, step_1.class
, ceil(step_1.Current_Distribution * step_2.Minimal_Population) as New_Distribution
FROM step_1
LEFT JOIN step_2 using(week) -- Provide maximum per week, not per week and class!
)
结果: 放在一起 -> 限制每个 class
的数据记录数SELECT
sample.week
, sample.class
, sample.data_record_id
FROM (
SELECT
data_record_id
, week
, class
, row_number() over (
partition by
week
, class
order by data_record_id
) as rnk -- This provides a unique number per record and week/class
FROM source_table
) sample
INNER JOIN step_3 on sample.week = step_3.week
and sample.class = step_3.class
WHERE sample.rnk <= step_3.New_Distribution -- This selects the quantity of records to match the new distribution