Разделить таблицу в (postgreSQL) случайным образом 50/50 - PullRequest
0 голосов
/ 05 сентября 2018

У меня есть таблица с двумя столбцами в postgresql: исходный идентификатор и дублированный идентификатор.

Пример данных:

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 голосов
/ 05 сентября 2018

Вы можете заставить 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 будет генерировать числа между upper_limit и lower_limit (включительно). Если верхний предел равен 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;
0 голосов
/ 05 сентября 2018

Вы можете использовать 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_id и duplicate_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;

дб <> скрипка (Кстати, результат SELECT на Fiddle дает хороший пример того, что порядок возвращаемых строк может полностью отличаться от физического, если оптимизатору это нравится больше.)

0 голосов
/ 05 сентября 2018

Я бы использовал оконные функции:

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;
0 голосов
/ 05 сентября 2018

Вы можете выбрать половину строк в случайном порядке с помощью этого запроса:

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;

Рабочий пример в rextester.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...