вторник, 22 октября 2013 г.

Модель для расчета интересности, популярности или сходных величин.

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

Итак, есть задача подсчитать популярность или важность чего либо. Например фильма, события, персоны. Для чего? Отвечу кратко. Варианты могут быть такие:
  • Показать правильное количество звездочек 
  • Сделать сортировку по принципу интересности и популярности
  • Добавить данные в индекс поисковой системы, для того чтобы повысить релевантность (например Elastic Search)
  • и тп.



Какие у нас могут быть входные данные? Напишу на вскидку. Например для событий или фильмов:
  • Как много людей упоминает
  • Лайки
  • Репосты
  • Общая цитируемость 
  • Пойду / Не пойду
  • Сентимент анализ отзывов/обсуждений
  • Популярность/посещаемость места
  • Популярность людей (артиста, группы, политика)
  • и т.п.
Природа этих чисел (которые я дальше буду называть "метриками" или "данными"), может быть сложной, может быть очень простой. Они собираются либо с помощью пауков (crawlers) или их можно запросить у какого-то глобального сервиса, так же некоторые из них так же являются расчетными.  В основном имеем целые числа, хотя, местами и с плавающей точкой (как в случае с сентимент анализом). Как бы то ни было, эти данные должны быть доступны для получения для любого из оцениваемых объектов (события или фильма согласно нашему набору примеров).

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

FB likesFB citeAlready seenwant to watchsentiment....
object1-2341-23450.67....
object234-35--....
object3-456-234-0.2....
............................

Естественно, object - это или событие или фильм, ну в общем та сущность, которую мы оцениваем.

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

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

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

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

Итак, может быть разработано множество способов решения этой задачи, приведу один из самых простых и эффективных сценариев.

Итак, первый, наиболее простой, несовершенный, но иногда практически очень полезный для простых случаев подход:

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

Нормализуем данные самым примитивным образом.

  • Ищем standard deviation (sd) и mean (mu) (среднеквадратичное отклонение и матожидание)
    • mu = sum(x_i) / n 
    • sd = sqrt(Sum((x_i - mu)^2) / (n-1)) //Не забываем, что расчет std_dev включен например в numpy и т.п
  • Собственно, сдвигаем и нормализуем:  value = (value-mu)/sd (читать о z-value)
  • Как только мы получили нормализованные данные, принимаем еще одно допущение, что наша конечная величина может быть выраженной формулой некоторого фиксированного вида. В простейшем случае это выражение может быть таким:
    • pop = a1*f1 + a2*f2 .... + an*fn
    • Следует отметить, что эта формула является существенным допущением, потому в последствии желательно как то верифицировать степень, с которой мы моем доверять такому расчету. Об этом позже.
    • Вид зависимости и коэффициетны может "захардкодить" эксперт, однако можно попробовать приментить машинное обучение с учителем (supervised learning) для их поиска. 
  • Как применить машинное обучение в данном случае
    • Самое простое:
      • определиться с видом зависимости вручную
      • так как понятие "популярности" интуитивно знают живые люди, то очевидно, можно попробовать именно у людей и спросить, что они думают о популярности чего-либо. В терминологии машинного обучения это ознаяает что мы можем получить тренировочные данные от пользователей (user labeled training set)
      • И применяем линейную регрессию для определения коэффициентов
      • Проблемка: в результате всех этих умных манипуляций может получиться, что даже на тренировочных примерах эта формул дает такое среднеквадратичное отклонение от изначальных значений (0.5 например), что доверять этой формуле нельзя. В случае, если это случилось, переходим к более сложным вариантам.
    • В более сложном случае, мы можем (ой как не хочу этого писать, ибо очень уж часто злоупотребляют люди этим разделом машинного обучения и вообще, мистификации тут обычны) натренировать нейросеть. 
      • Плюсы: Это позволяет отработать весьма серьезную нелинейность и не придется считать коэффициенты и вид формулы в отдельности - нейросеть может быть обучена нелинейным зависимостям любого вида, о котором мы и знать то не будем. 
      • Минусы: Это медленно. Это трудно сделать грамотно. И может не дать результата. Если для наших данных не выполняется ряд условий, но тут уж ничего ничего не поделаешь. Так же с неправильным набором фич, или с плохим treining set мы рискуем остаться без хорошего результата даже в этом случае. Однако, это дело техники и правильного подбора фич, и т.п.
  • И... всё это не работает на наших данных. 
    • Потому что данные не являются полными. То есть мы имеем пропуски. Однако и для этой проблемы решения возможны. Наиболее привлекательный для программиста способ - задаться значениями по умолчанию. И это еще хуже, чем данных не иметь. Ибо теперь мы не будем знать, что это значение ошибочно, мы внесли огромный дополнительный шум в исходные данные. 
    • В нашем конкретном случае мы исопльзуя мат. аппарат из теории вероятности можем предпололжить наиболее вероятные значения для тех мест, где у нас есть пропуски. Это, конечно, не более чем "угаданные" значения, однако, по крайней мере не сломают нашей зависимости и не внесут лишний шум, мешающий обучению. Тут могут придти на выручку корелляционный анализ, скрытые модели Маркова и т.п. Скажем так, у меня некоторая, работоспособная мат. модель получилась. Но нет предела красоте узора.

Это незавершенная версия, материал находится в работе, скорее всего будет обновление...

Комментариев нет:

Отправить комментарий