На пути к Data Science. Рекомендательные системы.

Рекомендательные системы, наверное обычному разработчику эта фраза вселяет ужас :), либо иллюзию простоты. Например как найти похожих людей? Представьте что у нас есть набор тегов, нам нужно найти похожих пользователей. Можно было бы конечно и в лоб это все решить, типа взять пользователя нужного, взять остальных, пройти по всем тегом нашего пользователя и по всем тегам других пользователей, но это мега медленный алгоритм, да и не круто совсем :) Круче мы решим эту задачу с помощью оценки Евклидова расстояния, это математическая формула, но она простая, дальше Вы это поймете. Также есть и другие метрики, например индекс корреляции Пирсона, но в этой статье мы его рассматривать не будем.

Суть оценки Евклидова расстояния в том, что нужно сложить квадраты разницы интересов, звучит страшно, но далее мы рассмотрим это подробнее.

Кейс у нас будет следующий, есть пользователи которые оценивают автомобили, нам нужно будет найти пользователей со схожими интересами и вывести их. Писать мы будем все на питоне :)

Первым делом нам нужно задать data set (это данные с которыми нам будет удобно работать и обрабатывать их)

Я придумал такие данные, Вы можете придумать что-то другое.

cars_rating = {
  "Вячеслав": {
      "BMW": 5,
      "Audi": 4.3,
      "Volvo": 5,
      "ВАЗ": 2,
      "Toyota": 5,
      "Ford": 4
  },
  "Сергей": {
      "BMW": 3,
      "Audi": 2,
      "Volvo": 4.5,
      "ВАЗ": 5,
      "Toyota": 5,
      "Ford": 2
  },
  "Петр": {
      "BMW": 0,
      "Audi": 5,
      "Volvo": 0,
      "ВАЗ": 0,
      "Toyota": 0,
      "Ford": 0
  },
  "Евгений": {
      "BMW": 4.5,
      "Audi": 3.5,
      "Volvo": 4,
      "ВАЗ": 3,
      "Toyota": 5,
      "Ford": 4
  }
}

У нас есть 5 человек и они оценили некоторые марки автомобилей, Вячеслав у нас любитель немцев, Сергей тазовод, Петр обожает ауди, а Евгений реалист. Давайте теперь попробуем оценить расстояние между Вячеславом и Евгением при помощи Евклидова расстояния, простым языком формула будет выглядеть так.

1 / (1 + ((5 - 4.5)^2 + (4.3 - 3.5)^2 + (5 - 4)^2 + (2 - 3)^2 + (5 - 5)^2 + (4 - 4)^2))

Здесь мы просто считаем разницу оценок автомобилей и возводим ее в квадрат и потом суммируем это число по каждой оценке. Давайте же напишем это в коде, напишем функцию euclid_destination.

def euclid_destination(data_set, person1, person2):
  general_interest = [interest for interest in data_set[person1] if interest in data_set[person2]]

  if len(general_interest) == 0:
      return 0

  return 1 / (1 + sum([(data_set[person1][item] - data_set[person2][item]) ** 2 for item in general_interest]))

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

$ python3 recommendations.py
0.25706940874035994

Это значит что Вячеслав и Евгений похожи, но не очень :))))) Раз у нас теперь есть функция для оценки похожести двух людей, то мы можем теперь оценить конкретного человека с другими людьми, давайте же это сделаем.

def search_similar_peoples(data_set, person):
  persons = [(euclid_destination(data_set, person, person2), person2) for person2 in data_set if person2 != person]
  persons.sort(reverse=True)

  return persons

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

Давайте же теперь запустим функцию

print(search_similar_peoples(cars_rating, "Вячеслав"))

В результате получим что-то типа этого

$ python3 recommendations.py
[(0.25706940874035994, 'Евгений'), (0.04248088360237893, 'Сергей'), (0.010363768266141568, 'Петр')]

Из результатов этого вычисления можно смело сказать что Евгений больше всех похож на Вячеслава, дальше идет Сергей и Петр. Давайте теперь в наш data set добавим Андрея у которого оценки будут максимально схожими с Вячеславом.

"Андрей": {
  "BMW": 5,
  "Audi": 4.8,
  "Volvo": 5,
  "ВАЗ": 2,
  "Toyota": 5,
  "Ford": 4
}

Пускай Андрей у нас немножко больше любит ауди, чем Вячеслав ;). Новым результатом вычислений будет уже следующий список

$ python3 recommendations.py
[(0.8, 'Андрей'), (0.25706940874035994, 'Евгений'), (0.04248088360237893, 'Сергей'), (0.010363768266141568, 'Петр')]

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

Всем спасибо и пока :) До следующей статьи.

Python
08.05.2017
1 ответ
авторизуйтесь чтобы ответить