Случайный выбор с разбивкой по процентам по нескольким группам

StackOverflow https://stackoverflow.com/questions/2060008

Вопрос

Я пытаюсь создать простую систему, позволяющую пользователю генерировать список пользователей, которым будут отправляться опросы.Генерация списка может зависеть от различных ограничений.Например, "нам нужны только люди из США.и Канада" или "нам нужны только те, у кого есть членство на уровне 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)
)
Это было полезно?

Решение

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

  • Пользователи из США, уровень 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-полная проблема.Но у многих таких проблем есть решение, которое дает вам "достаточно хороший" результат, хотя и не является доказуемо оптимальным.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top