在(postgreSQL)中随机拆分表50/50

时间:2018-09-04 23:42:15

标签: sql postgresql

我在postgresql中有一个带有两列的表:原始ID和重复ID。

样本数据:

original_id   duplicate_id  
     1             1
     2             2
     3             3
     4             4
     5             5
     6             6

我想将此表格随机分成50/50,因此我可以在每个表格中放置一个特定的标签

样本数据:

original_id   duplicate_id     tag
     1             1         control
     2             2         treatment
     3             3         treatment
     4             4         control
     5             5         treatment
     6             6         control

重要的是: 1.选择必须是随机的 2.拆分必须为50/50(如果行数为奇数,则为最接近的拆分)

4 个答案:

答案 0 :(得分:0)

您可以使用此查询以随机顺序选择一半的行:

select *
from my_table
order by random()
limit (select count(*)/ 2 from my_table)

使用它来标记行:

with control as (
    select *
    from my_table
    order by random()
    limit (select count(*)/ 2 from my_table)
)
select 
    *, 
    case when t in (select t from control t) then 'control' else 'treatment' end
from my_table t;

Working example in rextester.

答案 1 :(得分:0)

您可以使用rownumber() OVER (ORDER BY random())为每个记录分配一个随机数。然后在CASE中使用它来分配标签'control''treatment',具体取决于数字是否小于(或等于)表中行数的一半

对于看起来像这样的SELECT

SELECT original_id,
       duplicate_id,
       CASE
         WHEN rn <= (SELECT count(*) / 2
                            FROM elbat) THEN
           'control'
         ELSE
           'treatment'
       END tag
       FROM (SELECT original_id,
                    duplicate_id,
                    row_number() OVER (ORDER BY random()) rn
                    FROM elbat) x;

如果您想要一个UPDATE(我不确定),假设original_idduplicate_id对是唯一的,则可能看起来像这样:

UPDATE elbat t
       SET tag = CASE
                   WHEN rn <= (SELECT count(*) / 2
                                      FROM elbat) THEN
                     'control'
                   ELSE
                     'treatment'
                 END
       FROM (SELECT original_id,
                    duplicate_id,
                    row_number() OVER (ORDER BY random()) rn
                    FROM elbat) x
       WHERE x.original_id = t.original_id
             AND x.duplicate_id = t.duplicate_id;

db<>fiddle (顺便说一句,小提琴上的SELECT结果提供了一个很好的例子,如果优化程序更喜欢这样做,则返回的行的顺序可以与物理行的顺序完全不同。)

答案 2 :(得分:0)

我将使用窗口功能:

select t.*,
       (case when seqnum <= cnt / 2
             then 'treatment' else 'control
        end) as tag
from (select t.*,
             count(*) over () as cnt,
             row_number() over (order by random() as seqnum
      from t
     ) t;

实际上,随机是随机的。因此,您不需要计数。您可以改用模运算:

select t.*,
       (case when row_number() over (order by random()) % 2 = 1
             then 'treatment' else 'control'
        end) as tag
from t;

答案 3 :(得分:0)

您可以使random()使用以下公式生成值1或2:(random() + 1)::int

select t.*,
       case (random() + 1)::int
         when 1 then 'treatment' 
         else 'control'
       end as tag
from t;

通常,(random() * (upper_limit - 1) + lower_limit)::int会生成介于上限和下限(包括下限)之间的数字。如果上限为2,则可以删除乘法(因为它将是* 1,它不会改变任何内容),但是如果您想例如生成四个随机值,您也可以使用它:

select t.*,
       case (random() * 3 + 1)::int
         when 1 then 'treatment' 
         when 2 then 'control'
         when 3 then 'something'
         else 'some other thing'
       end as tag
from t;