Алгоритм выбора подмножества, удовлетворяющего условиям - PullRequest
0 голосов
/ 07 сентября 2018

У меня есть несколько отзывов клиентов, и каждая ссылка имеет некоторые свойства:

  1. Когда это было добавлено.
  2. Решение (например, HR, здравоохранение, контроль и т. Д.).
  3. Промышленность (например, транспорт, энергетика, электроника и т. Д.).
  4. Происходит ли это от сильного бренда.
  5. Регион (например, страна / континент).

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

  1. Недавно добавленные ссылки имеют более высокую вероятность выбора.
  2. Решений должно быть множество.
  3. В отраслях должно быть разнообразие.
  4. Должно быть разнообразие в ссылках от сильных брендов.
  5. В регионе должно быть разнообразие.

Как мне создать такой алгоритм выбора?

Редактировать 2018-09-08

Структура базы данных

| Column           | Type   | Key type    |
|------------------|--------|-------------|
| ReferenceId      | int    | Primary key |
| AuthorName       | string |             |
| OrganisationName | string |             |
| Content          | string |             |
| AddedDate        | date   |             |
| SolutionId       | int    | Foreign key |
| IndustryId       | int    | Foreign key |
| BrandIsStrong    | bool   |             |
| RegionId         | int    | Foreign key |

Идеи решения

1. Назначение весов

Общая идея: присвойте веса ссылкам и выберите ссылки на основе их совокупного веса. Например, вот так:

  1. Назначьте вес DateWeight для каждой ссылки. Чем старше ссылка, тем меньше вес.
  2. Для каждого решения просмотрите каждую ссылку, принадлежащую этому решению, в случайном порядке, присваивая каждой ссылке вес SolutionWeight. Для каждой итерации уменьшайте назначенный вес. В конце в каждом решении будет одна ссылка с высоким значением SolutionWeight, одна ссылка с немного меньшим значением SolutionWeight и т. Д. Если вы сейчас просмотрите все ссылки, упорядоченные по убыванию SolutionWeight, изменение в решении будет большой.
  3. Сделайте как в шаге 2, но для промышленности вместо решения, и давайте назовем вес IndustryWeight вместо SolutionWeight.
  4. Сделайте, как на шаге 2, но для сильного бренда вместо слабого бренда вместо решения, и давайте назовем вес BrandWeight вместо SolutionWeight.
  5. Сделайте как в шаге 2, но для региона вместо решения, и давайте назовем вес RegionWeight вместо SolutionWeight.
  6. У каждой ссылки теперь есть 5 весов. Они должны быть объединены в одну (например, путем сложения или умножения), а затем выбираются ссылки n для показа на главной странице. Это может быть сделано, например:
    1. Выбор ссылок с наибольшим общим весом.
    2. Итерационный процесс, в котором одна ссылка выбирается в каждой итерации, и вероятность выбора каждой ссылки относительно ее объединенного веса.

2. Итерационный выбор

Общая идея: перебирайте каждое ограничение, выбирая одну ссылку за раз.

  1. Пусть Unselected будет набором ссылок, которые не были выбраны.
  2. Выберите самую последнюю ссылку в Unselected.
  3. Для каждого решения выберите случайную ссылку в Unselected, принадлежащую этому решению.
  4. Для каждой отрасли выберите случайную ссылку в Unselected, относящуюся к этой отрасли.
  5. Выберите одну ссылку от сильного бренда и одну ссылку не от сильного бренда.
  6. Для каждого региона выберите случайную ссылку в Unselected, принадлежащую этому региону.
  7. Повторяйте шаги с 2 по 6, пока не будут выбраны ссылки n.

Недостаток этого решения заключается в том, что одно из ограничений содержит много опций (например, если число различных параметров больше n). Затем процесс остановится, прежде чем будет завершена хотя бы одна итерация.

3. Регулировка веса

Общая идея: Для каждой выбранной ссылки уменьшите вес, назначенный ссылкам с такими же свойствами, как у выбранной ссылки.

  1. Назначьте одинаковый вес для каждой ссылки.
  2. Выберите ссылку, используя взвешенный случайный выбор.
  3. Уменьшите вес всех ссылок с тем же решением, что и выбранная ссылка.
  4. Уменьшите вес всех ссылок в той же отрасли, что и выбранная ссылка.
  5. Если выбранная ссылка принадлежит сильному бренду, уменьшите вес всех ссылок сильных брендов. Если выбранная ссылка не от сильного бренда, уменьшите вес всех ссылок, которые не от сильных брендов.
  6. Уменьшите вес всех ссылок в той же области, что и выбранная ссылка.
  7. Повторяйте шаги 2-7, пока не будут выбраны ссылки n.

1 Ответ

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

Я думаю, что это в основном заключается в том, как вы определяете количественно приемлемое решение, и как вы определяете ограничения, такие как There should be a variety in [...]. Вы также должны решить, что делать, когда ваши данные сильно коррелируют: например, если большинство ссылок на «сильные бренды» происходят из одной «отрасли», то, поскольку вы хотите, чтобы многие отрасли были представлены, у вас будет небольшая доля » Сильные фирменные »элементы в вашем наборе. В этом случае вы не сможете иметь оба.

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

Перейдите к разделу tl; dr внизу, чтобы пропустить детали.

Решение 1: дешево и (в общем) эффективно: 100% случайно

Вы можете просто выбрать n ссылки наугад и позволить вселенной решить, какие элементы попадут на вашу страницу. Если ваши данные более или менее равномерно распределены по различным столбцам, и если n «достаточно велик», большую часть времени вы будете получать достаточно хорошие данные. Это также делает ваш код очень легко обслуживаемым / обновляемым в случае, если вам нужна быстрая реализация, так что вы можете вернуться к нему позже, когда у вас есть лучший алгоритм.

Теперь это не относится к

Недавно добавленные ссылки имеют более высокую вероятность выбора

часть, так что мы можем сделать немного лучше

Решение 2: не 100% случайное

Это слегка измененная версия первого решения. В этом примере вы выполняете итерацию по своему набору данных, начиная с самого последнего «ReferenceId» и следуя в порядке убывания «ReferenceId». Каждый элемент имеет вероятность выбора p, выбранную таким образом, что элементы n обычно находятся в пределах N самых последних элементов вашего набора данных. Если вы достигли дна до того, как выбрали n элементов, просто начните сверху (или увеличьте p).

В Java это будет выглядеть так:

for (Object item : items) {
    if (random.nextDouble() < p) {
        result.add(item);
    }
    if (result.size() == n) {
        break;
    }
}

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

Решение 3: сформулируйте ограничения и попытайтесь их удовлетворить, жадный метод

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

Вы должны знать, что, поскольку вы настраиваете шансы каждого конкретного предмета быть выбранным в финальном наборе, вы, возможно, не сможете по-настоящему иметь

они отличаются каждый раз, когда кто-то посещает мою домашнюю страницу

Чтобы быть действительно уверенным в этом, представьте пример, в котором одна из «областей» представлена ​​только одним элементом во всем наборе данных: скорее всего, он всегда будет в конечном выбранном подмножестве, поскольку вы хотите принудительно разнести. Существует также тот факт, что, поскольку вы предоставляете привилегии недавно добавленным ссылкам, ваше распределение данных будет более точно отражать распределение самых последних записей.

Так что теперь вы в мире с не всегда обязательным истинным случайным и равномерным представлением, давайте сформулируем ограничения. Ограничение для столбца может быть в форме «Я хотел бы иметь по крайней мере n/10 отдельных элементов из этого столбца в конечном подмножестве». Вы оцениваете состояние ограничения как «удовлетворенное» или «неудовлетворенное» с помощью функции (S, n, k) -> {true, false} где:

  • S - текущий набор выбранных элементов
  • n - желаемый размер для выбранных элементов
  • k - мощность столбца

говоря "учитывая текущее подмножество элементов, это ограничение уже выполнено?" Вы также можете оценить, способствует ли элемент удовлетворению ограничения, говоря: «учитывая текущее подмножество элементов, мы ближе к выполнению этого ограничения, если добавим этот элемент?».

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

Без подробностей реализации вы получите что-то вроде:

for (Object item : items) {
    // every item still has some probability of being chosen or not
    if (random.nextDouble() < p && helpsSatsfyAtLeastOne(remainingConstraints, item, result, n)) {
        result.add(item);                       
    }
    for (/* Appropriate data structure */ constraint : remainingConstraints) {
        if (constraint.isSatisfied(result, n)) {
            constraints.remove(constraint);
        }
    }
    if (result.size() == n) {
        break;
    }
}
System.out.println("Unsatisfied constraints: " + remainingConstraints);

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

Это жадный подход, и у вас нет гарантии, что конечный результат будет на 100% идеальным. Если в конце некоторые ограничения остаются неудовлетворенными, попробуйте установить приоритет в этих ограничениях.

ТЛ; др

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

  1. Определите, что это значит, чтобы удовлетворить ваши ограничения (с точки зрения количество элементов, относительное / абсолютное количество элементов, представляющих колонка и т. д.)
  2. Итерация по ссылкам в порядке убывания даты (последние первый)
  3. Каждый предмет имеет p вероятность быть выбранным
    1. Если выбран элемент (с вероятностным процессом), проверьте, добавляете ли вы это к результату вносит вклад как минимум в одно ограничение (т.е. это увеличит количество someColumn?). Если так, добавьте это к результат.
    2. Затем проверьте, удовлетворяются ли некоторые ограничения теперь, когда этот элемент добавлено (т. е. у меня есть достаточно из someColumn в моем результате установить? "). Снять эти ограничения.
  4. Если все ограничения выполнены, но вы все равно можете добавлять элементы в свой набор, добавьте их случайным образом любым удобным вам способом.
...