Случайный выбор с разбивкой по процентам по нескольким группам - PullRequest
1 голос
/ 13 января 2010

Я пытаюсь собрать простую систему для пользователя, чтобы создать список пользователей, которым будут отправляться опросы. Формирование списка может зависеть от различных ограничений. Например, «нам нужны только люди из США и Канады» или «нам нужны только люди, которые имеют членство уровня 2 или уровня 3».

Эта часть довольно проста, и я настроил таблицы для сбора критериев выбора. Один из дополнительных критериев заключается в том, что они могут захотеть получить определенный процент от каждого предмета. Например, «дайте мне 70% пользователей в США и 30% пользователей в Канаде». Опять же, я думаю, что могу сделать это без особых проблем. Они дадут желаемое количество пользователей, поэтому я могу просто умножить их на проценты, а затем убедиться, что после округления числа все еще складываются, и мне пора.

Впрочем, думая о будущем, что, если они хотят определенных процентных разбивок по двум наборам критериев? Например, «Дайте мне 70% США, 30% Канады и в то же время 50% пользователей уровня 2 и 50% пользователей уровня 3». Поскольку это не является текущим требованием, я не собираюсь испытывать головную боль из-за этого, но если у кого-то есть достаточно простой алгоритм (или код SQL) для выполнения чего-то подобного, то я буду рад это увидеть.

Хотя я бы предпочел решение, не зависящее от БД, я использую MS SQL 2005, поэтому решения, специфичные для этой СУБД, тоже подойдут.

Структура таблицы, которую я сейчас использую, похожа на эту:

CREATE TABLE Selection_Templates
(
     template_code     VARCHAR(20)     NOT NULL,
     template_name     VARCHAR(100)    NOT NULL,
     CONSTRAINT PK_Selection_Templates PRIMARY KEY CLUSTERED (template_code),
     CONSTRAINT UI_Selection_Templates UNIQUE (template_name)
)
GO
CREATE TABLE Selection_Template_Countries
(
     template_code            VARCHAR(20)       NOT NULL,
     country_code             CHAR(3)           NOT NULL,
     selection_percentage     DECIMAL(2, 2)     NULL,
     CONSTRAINT PK_Selection_Template_Countries PRIMARY KEY CLUSTERED (template_code, country_code),
     CONSTRAINT CK_Selection_Template_Countries_selection_percentage CHECK (selection_percentage > 0),
     CONSTRAINT FK_Selection_Template_Countries_Selection_Template FOREIGN KEY (template_code) REFERENCES Selection_Templates (template_code)
)
GO
CREATE TABLE Selection_Template_User_Levels
(
     template_code            VARCHAR(20)       NOT NULL,
     user_level               SMALLINT          NOT NULL,
     selection_percentage     DECIMAL(2, 2)     NULL,
     CONSTRAINT PK_Selection_Template_User_Levels PRIMARY KEY CLUSTERED (template_code, user_level),
     CONSTRAINT CK_Selection_Template_User_Levels_selection_percentage CHECK (selection_percentage > 0),
     CONSTRAINT FK_Selection_Template_User_Levels_Selection_Template FOREIGN KEY (template_code) REFERENCES Selection_Templates (template_code)
)

1 Ответ

2 голосов
/ 13 января 2010

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

  • пользователи из США, уровень 2, выберите 35% от общей желаемой выборки
  • Канадские пользователи, уровень 2, выберите 15% от общей желаемой выборки
  • Пользователи из США, уровень 3, выберите 35% от общего желаемого образца
  • Канадские пользователи, уровень 3, выберите 15% от общей желаемой выборки

Если есть третий критерий, разбейте задачу на восемь подходов. И так далее.

Может показаться искусственным получение точно 50% уровня 2 и 50% уровня 3 в обоих наборах пользователей из США и Канады. Поскольку он должен быть случайным, вы можете ожидать, что он будет меняться немного больше. Кроме того, что если не так много пользователей уровня 3 из Канады, которые составляют 15% от общего числа?

Поскольку критерии становятся все более и более избирательными, вы естественным образом отбираете случайность всей выборки. В конце концов у вас мог бы быть длинный список критериев, так что только одно подмножество ваших пользователей могло бы удовлетворить его, и тогда не было бы никакой случайности вообще.


Ваш комментарий: Да, SQL не лучшее решение для всех типов проблем. Возможно, лучше решить проблему с помощью итерационного алгоритма вместо одного SQL-запроса на основе набора. Например:

  1. Выберите одну случайную строку.
  2. Если строка была выбрана уже на предыдущей итерации, отбросить ее.
  3. Если ряд помогает сохранить темп выбора общей выборки, которая составляет 70% США, 30% Канады, 50% уровня 2, 50% уровня 3, сохраните его. В противном случае откажитесь от него.
  4. Если вы наберете нужное количество образцов, остановитесь.
  5. Вернитесь к шагу 1.

Конечно, будет сложно, если вы выберете строку, которая помогает сбалансировать соотношение наций 70/30%, но нарушает соотношение уровней 50/50%. Вы отказываетесь от этого или нет? А также вы можете игнорировать отношения, когда вы выбрали только первые несколько строк.

Как заметил @Hogan, это может быть неразрешимой проблемой NP-Complete. Но у многих таких проблем есть решение, которое дает вам «достаточно хороший» результат, хотя и не является доказуемо оптимальным результатом.

...