import math as mt
import numpy as np
import collections as cl
Допустим, у нас есть список клиентов, интересы которых нам известны.
user_items = [
    ["Hadoop", "Big Data", "HBase", "Java", "Spark", "Storm", "Cassandra"],
    ["NoSQL", "MongoDB", "Cassandra", "HBase", "Postgres"],
    ["Python", "scikit-learn", "scipy", "numpy", "statsmodels", "pandas"],
    ["R", "Python", "statistics", "regression", "probability"],
    ["machine learning", "regression", "decision trees", "libsvm"],
    ["Python", "R", "Java", "C++", "Haskell", "programming languages"],
    ["statistics", "probability", "mathematics", "theory"],
    ["machine learning", "scikit-learn", "Mahout", "neural networks"],
    ["neural networks", "deep learning", "Big Data", "artificial intelligence"],
    ["Hadoop", "Java", "MapReduce", "Big Data"],
    ["statistics", "R", "statsmodels"],
    ["C++", "deep learning", "artificial intelligence", "probability"],
    ["pandas", "R", "Python"],
    ["databases", "HBase", "Postgres", "MySQL", "MongoDB"],
    ["libsvm", "regression", "support vector machines"]
]
Задача выдачи рекомендации этим клиентам, интересы которых нам известны, может быть решена разными способами:

  1. Рекомендация наиболее популярного выбора.
  2. Рекомендация по преференциям схожих клиентов (user-user)
  3. Рекомендации по схожести категорий (item-item)

1. Рекомендация наиболее популярного выбора.

Данный способ не учитывает особенностей выбора данного клиента в прошлом. По всем выборам, которые были сделаны в прошлом, выбираются наиболее популярные (наиболее частые) выборы, и предлагаются те, которых клиент еще не делал

most_popular = cl.Counter([j for i in user_items for j in i]).most_common()

def popular_recommendation_user(user_id, mx=5):
    return [(k,v) for (k,v) in most_popular if k not in user_items[user_id]][:mx]


user_id = 0 # id клиента

print('Интересы клиента id{}: {}'.format(user_id, user_items[user_id]))
print('Рекомендации для клиента id{}: {}'.format(user_id, popular_recommendation_user(user_id)))
Интересы клиента id0: ['Hadoop', 'Big Data', 'HBase', 'Java', 'Spark', 'Storm', 'Cassandra']
Рекомендации для клиента id0: [('Python', 4), ('R', 4), ('statistics', 3), ('regression', 3), ('probability', 3)]
Следует заметить, что на данную рекомендацию не влияет выбор, сделанный клиентом в прошлом. Рекомендация будет одинакова для всех клиентов (за исключением категорий, которые уже выбирались в прошлом).
user_id = 1 # id клиента

print('Интересы клиента id{}: {}'.format(user_id, user_items[user_id]))
print('Рекомендации для клиента id{}: {}'.format(user_id, popular_recommendation_user(user_id)))
Интересы клиента id1: ['NoSQL', 'MongoDB', 'Cassandra', 'HBase', 'Postgres']
Рекомендации для клиента id1: [('Python', 4), ('R', 4), ('Java', 3), ('statistics', 3), ('Big Data', 3)]
user_id = 2 # id клиента

print('Интересы клиента id{}: {}'.format(user_id, user_items[user_id]))
print('Рекомендации для клиента id{}: {}'.format(user_id, popular_recommendation_user(user_id)))
Интересы клиента id2: ['Python', 'scikit-learn', 'scipy', 'numpy', 'statsmodels', 'pandas']
Рекомендации для клиента id2: [('R', 4), ('Java', 3), ('statistics', 3), ('Big Data', 3), ('regression', 3)]

2. Рекомендации по преференциям похожих клиентов (user-user)

Клиент «А» в прошлом сделал определенный набор выборов. Например, клиент мог выбрать ‘Big Data’, ‘Spark’, и ‘Python’. Основываясь на преференциях других клиентов, которые сделали похожие выборы, что еще мы можем порекомендовать данному клиенту? Данный способ рекомендаций основывается на предположении, что если клиенты «А» и «В» имеют схожие интересы, то что нравится «В» — скорее всего понравится и «А». На практике, этот способ рекомендаций реализуется, когда мы звоним друзьям и спрашиваем совета, какой фильм посмотреть? Математически задача решается следующим образом:

  1. Определяется размерность пространства, в котором будет решаться задача. Размерность равняется количеству уникальных выборов.
  2. Каждый клиент отображается в полученном n-мерном пространстве в виде вектора c координатами (0,1):
    • 1, если клиент делал выбор по данной оси координат
    • 0, если клиент не делал данный выбор
  3. В n-мерном пространстве выбираются вектора клиентов, наиболее «близкие» вектору клиента, для которого дается рекомендация. «Близость» определяется по cosine_similarity
  4. Предпочтения выбранных, наиболее «близких» клиентов суммируется и топовые преференции выдаются в виде рекомендации.

Для начала, давайте определим функцию cosine similarity(v1,v2), с помощью который мы будем измерять «близость» двух клиентов в n-мерном пространстве, или, выражаясь простым языком, «схожесть» клиентов v1 и v2.

def cosim(v1,v2):
    return np.dot(v1,v2)/ mt.sqrt(np.dot(v1,v1)*np.dot(v2,v2))
Затем, мы определим n-мерное пространство, в котором мы и будем искать похожих клиентов. Каждая ось в n-мерном пространстве — это уникальный выбор, который был сделан в прошлом.
unique_items = sorted({j for i in user_items for j in i})
unique_items[:5]
['Big Data', 'C++', 'Cassandra', 'HBase', 'Hadoop']
Выборы, которые были сделаны в прошлом, необходимо перевести в n-мерное пространство. В n-мерном пространстве по каждой оси будет:

  • 1, если такой выбор делался данным клиентом в прошлом
  • 0, если клиент не делал такой выбор в прошлом
def make_vector_items(items):
    return [1 if i in items else 0 for i in unique_items]

user_items_matrix = [make_vector_items(items) for items in user_items]
Таким образом, мы получили m x n user_items_matrix, где строки представляют клиентов (m), а столбцы представляют сделанные ими выборы (n).


 user\_items\_matrix_{ij}=\begin{cases} 1, & \text{if client i made choice j}\\ 0, & \text{if client i did NOT make choice j} \end{cases}

Используя полученную матрицу интересов клиентов user_items_matrix на основе cosim() мы можем определить список наиболее схожих клиентов:
def similar_users(user_ID):
    pairs = [(user_id, cosim(user_items_matrix[user_ID], user_interest)) 
             for user_id, user_interest in enumerate(user_items_matrix) 
             if user_id != user_ID
             and cosim(user_items_matrix[user_ID], user_interest) > 0]   
    return sorted(pairs, key = lambda x: x[1], reverse =1)

similar_users(0)
[(9, 0.56694670951384085),
 (1, 0.33806170189140661),
 (8, 0.1889822365046136),
 (13, 0.1690308509457033),
 (5, 0.15430334996209191)]
И, наконец, функция выдачи рекомендаций, которая суммирует преференции по схожим клиентам:
def user_user_recommendation(user_ID, mx = 5):
    recommendation = cl.defaultdict(float)
# calculate recommendations over similar users
    for user_id, cosim_similarity in similar_users(user_ID):
        for interest in user_items[user_id]:
            recommendation[interest] += cosim_similarity
# sort them out 
    recommendation = sorted(recommendation.items(), key = lambda x: x[1], reverse=1)
# exclude already existing items
    recommendation = [i for i in recommendation if i[0] not in user_items[user_ID]]  
    return recommendation[:mx]
Теперь мы можем сравнить преференции, которые имеет пользователь, с наиболее популярными интересами по всей выборке (не принимая во внимание специфику данного клиента) и рекомендации для данного клиента, принимающие во внимание историю сделанных выборов.
user_id = 0

print('Интересы клиента id_{0}: \n{1}\n\n\
Рекомендации для клиента id_{0} по наиболее популярным запросам: \n{2}\n\n\
Рекомендации для клиента id_{0} по схожим клиентам: \n{3}'\
      .format(user_id,user_items[user_id],popular_recommendation_user(user_id),user_user_recommendation(user_id)))
Интересы клиента id_0: 
['Hadoop', 'Big Data', 'HBase', 'Java', 'Spark', 'Storm', 'Cassandra']

Рекомендации для клиента id_0 по наиболее популярным запросам: 
[('Python', 4), ('R', 4), ('statistics', 3), ('regression', 3), ('probability', 3)]

Рекомендации для клиента id_0 по схожим клиентам: 
[('MapReduce', 0.56694670951384085), ('Postgres', 0.50709255283710997), ('MongoDB', 0.50709255283710997), ('NoSQL', 0.33806170189140661), ('artificial intelligence', 0.1889822365046136)]

3. Рекомендации по схожести категорий (item-item)

Клиент уже выбрал несколько категорий, например ‘Big Data’, ‘Spark’ и ‘Python’. Каждая выбранная категория, в свою очередь, также имеет наиболее близкие категории. Основываясь на схожести категорий, что еще мы можем посоветовать ему? Данный способ основывается на рекомендации категорий, которые наиболее «близки» уже сделанным выборам:

  • «Близость» определяется на основе cosine similarity
  • На основе cosine similarity выбираются категории, которые наиболее близки уже сделанным выборам
  • Cosine similarity суммируется по всем выбранным (наиболее близким) категориям и выбираются топовые рекомендации, которых нет среди уже сделанных выборов.

Вспомним, что в основе рекомендаций лежал лист выборов, где каждый элемент листа ассоциировался с клиентом, а для каждого клиента был вектор выборов.

user_items
[['Hadoop', 'Big Data', 'HBase', 'Java', 'Spark', 'Storm', 'Cassandra'],
 ['NoSQL', 'MongoDB', 'Cassandra', 'HBase', 'Postgres'],
 ['Python', 'scikit-learn', 'scipy', 'numpy', 'statsmodels', 'pandas'],
 ['R', 'Python', 'statistics', 'regression', 'probability'],
 ['machine learning', 'regression', 'decision trees', 'libsvm'],
 ['Python', 'R', 'Java', 'C++', 'Haskell', 'programming languages'],
 ['statistics', 'probability', 'mathematics', 'theory'],
 ['machine learning', 'scikit-learn', 'Mahout', 'neural networks'],
 ['neural networks', 'deep learning', 'Big Data', 'artificial intelligence'],
 ['Hadoop', 'Java', 'MapReduce', 'Big Data'],
 ['statistics', 'R', 'statsmodels'],
 ['C++', 'deep learning', 'artificial intelligence', 'probability'],
 ['pandas', 'R', 'Python'],
 ['databases', 'HBase', 'Postgres', 'MySQL', 'MongoDB'],
 ['libsvm', 'regression', 'support vector machines']]
Для рекомендаций типа item-item нам необходимо привести эту матрицу к виду:


 item\_users\_matrix_{ij}=\begin{cases} 1, & \text{if choice i was made by client j}\\ 0, & \text{if choice i was NOT made by client j} \end{cases}

item_users_matrix = [[1 if i in j else 0 for j in user_items] for i in unique_items]
item_users_matrix[:5]
[[1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
 [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
 [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]
Точно также, как и для рекомендаций типа user-user, мы можем найти схожие категории:
def similar_items(interest_id):
    pairs = [(unique_items[i], cosim(item_users_matrix[interest_id], item))
             for i, item in enumerate(item_users_matrix)
             if i != interest_id and cosim(item_users_matrix[interest_id], item) > 0
            ]
    pairs = sorted(pairs, key = lambda x: x[1], reverse =1)
    return pairs

similar_items(0)[:5]
[('Hadoop', 0.81649658092772615),
 ('Java', 0.66666666666666663),
 ('MapReduce', 0.57735026918962584),
 ('Spark', 0.57735026918962584),
 ('Storm', 0.57735026918962584)]
Для функции, которая непосредственно будет давать рекомендации, нам понадобится вспомогательный словарь, который будет сопоставлять название категории и её позицию в листе уникальных категорий:
unique_items_position = {k:v for v,k in enumerate(unique_items)}
print(unique_items[:3])
print(unique_items_position['Big Data'])
['Big Data', 'C++', 'Cassandra']
0
Наконец, мы можем написать функцию, которая:

  • найдет схожие категории для всех сделанных выборов
  • просуммирует cosine simialrity для всех схожих категорий
  • выберет топовые 5 рекомендаций
def item_item_recommendation(user_id, mx=5):
    rec = cl.defaultdict(float)
    for item in user_items[user_id]:
        sim_items = similar_items(unique_items_position[item])
        for it, similarity in sim_items:
            rec[it] += similarity
    rec = sorted(rec.items(), key=lambda x: x[1], reverse = 1)
    rec = [i for i in rec if i[0] not in user_items[user_id]]
    return rec[:mx]
user_id = 0

print('Интересы клиента id_{0}: \n{1}\n\n\
Рекомендации для клиента id_{0} по наиболее популярным запросам: \n{2}\n\n\
Рекомендации для клиента id_{0} user-user: \n{3}\n\n\
Рекомендации для клиента id_{0} item-item: \n{4}'\
      .format(user_id,
              user_items[user_id],
              popular_recommendation_user(user_id),
              user_user_recommendation(user_id),
              item_item_recommendation(user_id)))
Интересы клиента id_0: 
['Hadoop', 'Big Data', 'HBase', 'Java', 'Spark', 'Storm', 'Cassandra']

Рекомендации для клиента id_0 по наиболее популярным запросам: 
[('Python', 4), ('R', 4), ('statistics', 3), ('regression', 3), ('probability', 3)]

Рекомендации для клиента id_0 user-user: 
[('MapReduce', 0.56694670951384085), ('Postgres', 0.50709255283710997), ('MongoDB', 0.50709255283710997), ('NoSQL', 0.33806170189140661), ('artificial intelligence', 0.1889822365046136)]

Рекомендации для клиента id_0 item-item: 
[('MapReduce', 1.8618073195657989), ('Postgres', 1.3164965809277263), ('MongoDB', 1.3164965809277263), ('NoSQL', 1.2844570503761732), ('databases', 0.57735026918962584)]
Как мы видим, и user-user и item-item рекомендации довольны похожи.
Write a comment:

*

Your email address will not be published.

© 2014 In R we trust.
Top
Follow us: