Стратифицированная случайная выборка с BigQuery? - PullRequest
0 голосов
/ 20 октября 2018

Как я могу сделать стратифицированную выборку на BigQuery?

Например, мы хотим, чтобы 10% -ная пропорциональная стратифицированная выборка использовала category_id в качестве страты.В наших таблицах содержится до 11000 category_ids.

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

Я думаю, что самый простой способ получить пропорциональную стратифицированную выборку - это упорядочить данные по категориям и сделать «n-ю» выборку данных.Для 10% выборки вы хотите каждые 10 строк.

Это выглядит следующим образом:

select t.*
from (select t.*,
             row_number() over (order by category order by rand()) as seqnum
      from t
     ) t
where seqnum % 10 = 1;

Примечание. Это не гарантирует, что все категории будут в окончательной выборке.Категория с менее чем 10 строками может не отображаться.

Если вы хотите сэмплы одинакового размера, закажите в каждой категории и просто возьмите фиксированное число:

select t.*
from (select t.*,
             row_number() over (partition by category order by rand()) as seqnum
      from t
     ) t
where seqnum <= 100;

Примечание: это не гарантирует, что в каждой категории существует 100 строк.Требуются все строки для небольших категорий и случайная выборка для более крупных.

Оба эти метода довольно удобны.Они могут работать с несколькими измерениями одновременно.Первый имеет особенно приятную особенность - он также может работать с числовыми размерами.

0 голосов
/ 20 октября 2018

С #standardSQL давайте определим нашу таблицу и некоторые статистические данные по ней:

WITH table AS (
  SELECT *, subreddit category
  FROM `fh-bigquery.reddit_comments.2018_09` a
), table_stats AS (
  SELECT *, SUM(c) OVER() total 
  FROM (
    SELECT category, COUNT(*) c 
    FROM table
    GROUP BY 1 
    HAVING c>1000000)
)

В этой настройке:

  • subreddit будет нашей категорией
  • нам нужны только субредакты с более чем 1000000 комментариями

Итак, если мы хотим, чтобы 1% каждой категории в нашей выборке:

SELECT COUNT(*) samples, category, ROUND(100*COUNT(*)/MAX(c),2) percentage
FROM (
  SELECT id, category, c  
  FROM table a
  JOIN table_stats b
  USING(category)
  WHERE RAND()< 1/100 
)
GROUP BY 2

enter image description here

Или, скажем, мы хотим ~ 80 000 образцов - но выбираем пропорционально по всем категориям:

SELECT COUNT(*) samples, category, ROUND(100*COUNT(*)/MAX(c),2) percentage
FROM (
  SELECT id, category, c  
  FROM table a
  JOIN table_stats b
  USING(category)
  WHERE RAND()< 80000/total
)
GROUP BY 2

enter image description here

Сейчас, если вы хотите получить примерно одинаковое количество образцов из каждой группы (скажем, 20 000):

SELECT COUNT(*) samples, category, ROUND(100*COUNT(*)/MAX(c),2) percentage
FROM (
  SELECT id, category, c  
  FROM table a
  JOIN table_stats b
  USING(category)
  WHERE RAND()< 20000/c
)
GROUP BY 2

enter image description here

Если вы хотите точно20 000 элементов из каждой категории:

SELECT ARRAY_LENGTH(cat_samples) samples, category, ROUND(100*ARRAY_LENGTH(cat_samples)/c,2) percentage
FROM (
  SELECT ARRAY_AGG(a ORDER BY RAND() LIMIT 20000) cat_samples, category, ANY_VALUE(c) c
  FROM table a
  JOIN table_stats b
  USING(category)
  GROUP BY category
)

enter image description here

Если вы хотите ровно 2% от каждой группы:

SELECT COUNT(*) samples, sample.category, ROUND(100*COUNT(*)/ANY_VALUE(c),2) percentage
FROM (
  SELECT ARRAY_AGG(a ORDER BY RAND()) cat_samples, category, ANY_VALUE(c) c
  FROM table a
  JOIN table_stats b
  USING(category)
  GROUP BY category
), UNNEST(cat_samples) sample WITH OFFSET off
WHERE off<0.02*c
GROUP BY 2

enter image description here


Если вам нужен последний подход, вы можете заметить, что он потерпел неудачу, когда вы действительно хотите получить данные.Раннее значение LIMIT, аналогичное наибольшему размеру группы, позволит нам не сортировать больше данных, чем необходимо:

SELECT sample.*
FROM (
  SELECT ARRAY_AGG(a ORDER BY RAND() LIMIT 105000) cat_samples, category, ANY_VALUE(c) c
  FROM table a
  JOIN table_stats b
  USING(category)
  GROUP BY category
), UNNEST(cat_samples) sample WITH OFFSET off
WHERE off<0.02*c
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...