На пути к 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, 'Петр')]
Здесь мы видим, что Андрей больше всех стал похож на Вячеслава, вот так работает поиск похожих людей с помощью оценки Евклидова расстояния, в следующей статье мы порекомендуем Вячеславу возможно интересные ему автомобили.
Всем спасибо и пока :) До следующей статьи.