Подтвердить что ты не робот

Пользовательская фильтрация: система рекомендаций

Я знаю, что это не специфическая проблема с кодированием, но это наиболее подходящее место для запроса таких вопросов. Поэтому, пожалуйста, несите меня.

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

likes={
    "rajat":{"music","x-men","programming","hindi","english","himesh","lil wayne","rap","travelling","coding"},
    "steve":{"travelling","pop","hanging out","friends","facebook","tv","skating","religion","english","chocolate"},
    "toby":{"programming","pop","rap","gardens","flowers","birthday","tv","summer","youtube","eminem"},
    "ravi":{"skating","opera","sony","apple","iphone","music","winter","mango shake","heart","microsoft"},
    "katy":{"music","pics","guitar","glamour","paris","fun","lip sticks","cute guys","rap","winter"},
    "paul":{"office","women","dress","casuals","action movies","fun","public speaking","microsoft","developer"},
    "sheila":{"heart","beach","summer","laptops","youtube","movies","hindi","english","cute guys","love"},
    "saif":{"women","beach","laptops","movies","himesh","world","earth","rap","fun","eminem"}
    "mark":{"pilgrimage","programming","house","world","books","country music","bob","tom hanks","beauty","tigers"},
    "stuart":{"rap","smart girls","music","wrestling","brock lesnar","country music","public speaking","women","coding","iphone"},
    "grover":{"skating","mountaineering","racing","athletics","sports","adidas","nike","women","apple","pop"},
    "anita":{"heart","sunidhi","hindi","love","love songs","cooking","adidas","beach","travelling","flowers"},
    "kelly":{"travelling","comedy","tv","facebook","youtube","cooking","horror","movies","dublin","animals"},
    "dino":{"women","games","xbox","x-men","assassin creed","pop","rap","opera","need for speed","jeans"},
    "priya":{"heart","mountaineering","sky diving","sony","apple","pop","perfumes","luxury","eminem","lil wayne"},
    "brenda":{"cute guys","xbox","shower","beach","summer","english","french","country music","office","birds"}
}

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

4b9b3361

Ответ 1

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

Основы этого подробно описаны в в главе 2 книги "Программирование коллективного интеллекта" . Пример кода находится в Python, что является еще одним плюсом.

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

Короче говоря, можно использовать такие методы, как вычисление Коэффициент корреляции Пирсона, Косинус сходство, k-ближайшие соседи и т.д., чтобы определить сходство между пользователями на основе элементов, которые они хотели/купили/проголосовали.

Обратите внимание, что существуют различные библиотеки python, которые были написаны для этой цели, например. pysuggest, Crab, python-recsys и SciPy.stats.stats.pearsonr.

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

Ответ 2

Решение с использованием библиотеки python recsys [http://ocelma.net/software/python-recsys/build/html/quickstart.html]

from recsys.algorithm.factorize import SVD
from recsys.datamodel.data import Data

likes={
    "rajat":{"music","x-men","programming","hindi","english","himesh","lil wayne","rap","travelling","coding"},
    "steve":{"travelling","pop","hanging out","friends","facebook","tv","skating","religion","english","chocolate"},
    "toby":{"programming","pop","rap","gardens","flowers","birthday","tv","summer","youtube","eminem"},
    "ravi":{"skating","opera","sony","apple","iphone","music","winter","mango shake","heart","microsoft"},
    "katy":{"music","pics","guitar","glamour","paris","fun","lip sticks","cute guys","rap","winter"},
    "paul":{"office","women","dress","casuals","action movies","fun","public speaking","microsoft","developer"},
    "sheila":{"heart","beach","summer","laptops","youtube","movies","hindi","english","cute guys","love"},
    "saif":{"women","beach","laptops","movies","himesh","world","earth","rap","fun","eminem"},
    "mark":{"pilgrimage","programming","house","world","books","country music","bob","tom hanks","beauty","tigers"},
    "stuart":{"rap","smart girls","music","wrestling","brock lesnar","country music","public speaking","women","coding","iphone"},
    "grover":{"skating","mountaineering","racing","athletics","sports","adidas","nike","women","apple","pop"},
    "anita":{"heart","sunidhi","hindi","love","love songs","cooking","adidas","beach","travelling","flowers"},
    "kelly":{"travelling","comedy","tv","facebook","youtube","cooking","horror","movies","dublin","animals"},
    "dino":{"women","games","xbox","x-men","assassin creed","pop","rap","opera","need for speed","jeans"},
    "priya":{"heart","mountaineering","sky diving","sony","apple","pop","perfumes","luxury","eminem","lil wayne"},
    "brenda":{"cute guys","xbox","shower","beach","summer","english","french","country music","office","birds"}
}

data = Data()
VALUE = 1.0
for username in likes:
    for user_likes in likes[username]:
        data.add_tuple((VALUE, username, user_likes)) # Tuple format is: <value, row, column>

svd = SVD()
svd.set_data(data)
k = 5 # Usually, in a real dataset, you should set a higher number, e.g. 100
svd.compute(k=k, min_values=3, pre_normalize=None, mean_center=False, post_normalize=True)

svd.similar('sheila')
svd.similar('rajat')

Результаты:

In [11]: svd.similar('sheila')
Out[11]: 
[('sheila', 0.99999999999999978),
 ('brenda', 0.94929845546505753),
 ('anita', 0.85943494201162518),
 ('kelly', 0.53385495931440263),
 ('saif', 0.39985366653259058),
 ('rajat', 0.30757664244952165),
 ('toby', 0.28541364367155014),
 ('priya', 0.26184289111194581),
 ('steve', 0.25043700194182622),
 ('katy', 0.21812807229358305)]

In [12]: svd.similar('rajat')
Out[12]: 
[('rajat', 1.0000000000000004),
 ('mark', 0.89164019482177692),
 ('katy', 0.65207273451425907),
 ('stuart', 0.61675507205285718),
 ('steve', 0.55730648750670264),
 ('anita', 0.49836982296014803),
 ('brenda', 0.42759524471725929),
 ('kelly', 0.40436047539358799),
 ('toby', 0.35972227835054826),
 ('ravi', 0.31113813325818901)]

Ответ 3

SequenceMatcher в difflib полезен для такого рода вещей. Если вы используете ratio(), оно возвращает значение между 0 и 1, соответствующее сходству между двумя последовательностями, из документов:

Возвращает меру сходства последовательностей как float в диапазоне [0, 1]. Где T - общее количество элементов в обеих последовательностях, а M - количество совпадений, это 2.0 * M/T. Обратите внимание, что это 1.0, если последовательности идентичны и 0.0, если они не имеют ничего общего.

Из вашего примера, сравнивая только 'rajat' со всеми остальными (исправлено в словаре путем переключения внутреннего {} для []):

import difflib
for key in likes:
    print 'rajat', key, difflib.SequenceMatcher(None,likes['rajat'],likes[key]).ratio()
#Output:
rajat sheila 0.2
rajat katy 0.2
rajat brenda 0.1
rajat saif 0.2
rajat dino 0.2
rajat toby 0.2
rajat mark 0.1
rajat steve 0.1
rajat priya 0.1
rajat grover 0.0
rajat ravi 0.1
rajat rajat 1.0
rajat stuart 0.2
rajat kelly 0.1
rajat paul 0.0
rajat anita 0.2

Ответ 4

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

Может использоваться нечто вроде list(set(list1).intersection(list2)). Это вернет список с элементами, которые определяют пересечение.

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

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

Ответ 5

for k in likes:
    if likes["rajat"] & likes[k]:
        print k, likes["rajat"] & likes[k]
    else:
        print k,  " No Like with rajat" 

Output

sheila set(['hindi', 'english'])
katy set(['music', 'rap'])
brenda set(['english'])
saif set(['himesh', 'rap'])
dino set(['x-men', 'rap'])
toby set(['programming', 'rap'])
mark set(['programming'])
steve set(['travelling', 'english'])
priya set(['lil wayne'])
grover No Likes with rajat
ravi set(['music'])
rajat set(['lil wayne', 'x-men', 'himesh', 'coding', 'programming', 'music', 'hindi',  'rap', 'english', 'travelling'])
stuart set(['music', 'coding', 'rap'])
kelly set(['travelling'])
paul No Likes with rajat
anita set(['travelling', 'hindi'])

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

Ответ 6

Можно также использовать scikit-learn для пользовательской фильтрации:

Взяв более простой пример, если у вас было:

"stuart":{"rap","rock"}

и вы хотели изучить его сходство с музыкальным вкусом:

"toby:{"hip-hop","pop","rap"}

Вы можете использовать функцию подобия косинуса sklearn,

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity

vec = CountVectorizer(analyzer='char')
vec.fit(stuart_list)

x = cosine_similarity(vec.transform(toby_list),
                 vec.transform(stuart_list))

который даст вам косинус-матрицу, например:

[[ 0.166  0.327  1]
 [ 0.123  0.267  0.230]]

где первая строка представляет rap сходство с косинусом со всеми тремя выборами. Обратите внимание на то, что 1, представляющий идеальное подобие, в правильных тригонометрических терминах, означает, что 2 варианта имели угол 0º (то есть были идентичны) и, следовательно, имели косинус от 1.

Вторая подобная строка представляет собой rock сходство косинусов со всеми тремя вариантами выбора.

Я не мог найти способ найти общее сходство между двумя списками в sklearn, однако, учитывая матрицу косинусов, вы можете подсчитать количество 1 там и иметь это число сходства. Или вы можете подсчитать количество 0.9 и выше для учета почти таких же слов, как "хип-хоп" и "хип-хоп".

(Sklearn также имеет евклидовое сходство, которое можно использовать как альтернативу сходству с косинусом.)