„Клиентите, които са купили това, също са купили...“ Често срещаме персонализирани препоръки, докато пазаруваме в Amazon, слушаме музика в Spotify и гледаме предавания в Netflix, за да цитирам няколко. Те са толкова широко разпространени, че много от нас взаимодействат с тях, без дори да го осъзнават. Всички тези уебсайтове се опитват да преценят нашите вкусове, за да могат да стимулират непрекъсната ангажираност. Тези компании използват нашите модели на пазаруване/слушане/гледане, за да предвидят какво може да ни хареса в бъдеще. В известен смисъл препоръчителните системи са печеливши както за потребителите, така и за бизнеса. За потребителите те предлагат по-добро изживяване и ангажираност, докато за бизнеса помагат за увеличаване на приходите.

Съвместно филтриране

Има няколко подхода за изграждане на двигател за препоръки. Тази статия обаче ще се фокусира върху подхода за съвместно филтриране. Отправната точка за съвместното филтриране е миналите взаимодействия между потребители и елементи да се съхраняват в разредена матрица, наречена „матрица на взаимодействие потребител-елемент“. Предположението е, че тези минали взаимодействия между потребител и артикул са достатъчни за откриване на подобни потребители и/или подобни артикули и за отправяне на препоръки въз основа на тези изчислени близости.

За разлика от някои други техники, основното предимство на съвместното филтриране е, че не е необходимо да знаем съдържанието в детайли. Например, ако гледате филми за Хари Потър на Prime Video, той ви препоръчва други филми, гледани от хора, които също са гледали Хари Потър. При този подход системата за препоръчване може дори да не се интересува от жанра, актьорския състав или режисьора на предложения филм. Просто ще го препоръча, защото други хора с подобни вкусове са го гледали.

Съвместното филтриране може допълнително да се категоризира на:

  • Въз основа на потребителите:В зависимост от оценките, които потребителите са дали на едни и същи артикули, ние се опитваме да разберем потребителите, които имат подобни вкусове/предпочитания като потребител A, като използваме косинусово сходство. Освен това използваме претеглена сума от оценките, предоставени от най-близките съседи (т.е. потребители с подобно мислене като A) за артикул X и изчисляваме предварителната оценка, която потребител A може да предостави на този артикул.
  • Базиран на артикул:За разлика от измерването на приликите между потребителите, подходът, базиран на артикул, има за цел намирането на подобни артикули/продукти. След това оценката на потребител за елемент X се прогнозира чрез вземане на претеглената сума от оценките, предоставени от потребителя за най-близките съседи (в този случай - други елементи, подобни на елемент X ). Подходът, базиран на артикули, е успешна техника, която различни компании използват широко.

Набор от данни за филмов обектив

В тази статия ще преминем през двата подхода на съвместно филтриране и ще използваме набора от данни за филмови обективи, за да изградим основна система за препоръки в Python. Този набор от данни описва оценки, направени по 5-звездна скала със стъпки от половин звезда. Той съдържа 100 836 оценки в 9 742 филма, създадени от 610 потребители. Потребителите бяха избрани на случаен принцип за включване. Всички избрани потребители са оценили най-малко 20 филма. Не е включена демографска информация. Всеки потребител се представя с идентификатор и не се предоставя друга информация.

Косинусово сходство

Преди да преминем към алгоритъма, нека първо разберем косинусното подобие.

Косинусното сходство определя количествено сходството между два ненулеви вектора и варира между 0 и 1. Това е косинусът на ъгъла между векторите. Математически се дефинира, както следва:

Изграждане на модела в Python

За да направим нещата по-ясни, нека започнем с алгоритъма. Тези стъпки са общи както за базиран на потребител, така и за базиран на артикул подход.

  • Импортиране на подходящи библиотеки на Python:В първата стъпка импортираме библиотеки pandas, numpy за обработка на данни. Също така импортираме os за извличане/промяна на работната директория. train_test_split, StratifiedKFold и cosine_similariltyсе импортират за разделяне на набора от данни, извършване на кръстосано валидиране и съответно изчисляване на резултатите за сходство. И накрая, за оценка на нашия модел ние също импортираме mean_absolute_error.
  • Изтегляне и четене на данните:Следващата стъпка е да изтеглите набора от данни за филмов обектив и да прочетете данните за оценките. Освен това можем да извършим някои EDA и предварителна обработка на тези данни.
# reading the ratings data
ratings=pd.read_csv('ratings.csv')

# unique ratings
print('Unique ratings: ', ratings['rating'].unique(), '\n')

# number of ratings
print('Number of ratings: ', len(ratings), '\n')

# number of unique users
print('Number of unique users: ', len(ratings['userId'].unique()), '\n')

# number of unique movies
print('Number of unique movies: ', len(ratings['movieId'].unique()), '\n')

# removing the redundant column timestamp
df=ratings.iloc[:,:-1]
df

Output

Unique ratings:  [4.  5.  3.  2.  1.  4.5 3.5 2.5 0.5 1.5] 

Number of ratings:  100836 

Number of unique users:  610 

Number of unique movies:  9724 

  • Внедряване на стратифицирана извадка при кръстосано валидиране: Сега идеята е да разделим нашия набор от данни на подгрупи за обучение и тестване. Ще оставим модела да се учи от набора за обучение и след това ще измерим ефективността му на набора за тестване. За да оценим как резултатите се обобщават към независим набор от данни и за да предотвратим пренастройване, извършваме кръстосано валидиране. При кръстосано валидиране наборът от данни се разделя на k разделяния. Ние използваме k-1 сплитове за обучение, а останалият сплит се използва за тестване. Моделът преминава през целия набор от данни k пъти и всеки път се използва различно разделение за тестване. По този начин ние използваме всички точки от данни както за обучение, така и за тестване. Stratified k foldsизвежда кръстосаното валидиране една стъпка напред. Той гарантира, че разпределението на класовете в набора от данни се запазва в комплектите за обучение и тестване.
Output

StratifiedKFold(n_splits=5, random_state=None, shuffle=False)

Fold:  1
TRAIN: [    47     48     49 ... 100833 100834 100835]  having:  80668
TEST: [    0     1     2 ... 99792 99793 99794]  having:  20168
------------------------------------

Fold:  2
TRAIN: [     0      1      2 ... 100833 100834 100835]  having:  80669
TEST: [    47     48     49 ... 100052 100053 100054]  having:  20167
------------------------------------

Fold:  3
TRAIN: [     0      1      2 ... 100833 100834 100835]  having:  80669
TEST: [    94     95     96 ... 100312 100313 100314]  having:  20167
------------------------------------

Fold:  4
TRAIN: [     0      1      2 ... 100833 100834 100835]  having:  80669
TEST: [   140    141    142 ... 100572 100573 100574]  having:  20167
------------------------------------

Fold:  5
TRAIN: [     0      1      2 ... 100572 100573 100574]  having:  80669
TEST: [   186    187    188 ... 100833 100834 100835]  having:  20167
  • Оценки и матрица на приликата: Изчертаваме опорна точка от набора от данни за обучение, като вземаме userId в редове и movieId в колони и рейтинг като стойности. Резултатът е рядка Оценъчна матрица, където NaN може допълнително да бъде заменен с нули.

  1. Матрица за прилика потребител-потребител —След това измерваме приликата между потребителите. Корелацията на Пиърсън и косинусното подобие са два широко използвани метода. В нашия случай ще използваме косинусово сходство, за да изчислим резултатите за сходство потребител-потребител. Тъй като косинусното подобие не приема липсващи стойности, трябва да им приписваме нули, преди да изчислим подобието.

2. Матрица за сходство артикул по артикул —По подобен начин можем да изчислим оценките за сходство между артикулите. Взимаме транспониране на нашата матрица за оценки и след това измерваме сходството по косинус на артикул.

Съвместно филтриране, базирано на потребителя

  • Функция за предвиждане на оценките:След това създаваме функция, която предвижда оценките на потребител A за артикул X, използвайки претеглени сумата от оценките на най-близките съседина този потребител. С други думи, ние използваме оценките на други потребители с подобно мислене, за да предложим нови елементи за потребител А. За да намерим най-близките съседи, можем да използваме различни методи. Първо, можем да зададем прагова оценка за сходство, да речем similarity_thresholdи да филтрираме всички потребители с оценка за сходство, по-висока от тази similarity_threshold. Друг метод за намиране на най-близки съседи е просто избиране на първите n потребители с най-голямо сходство по косинус. Нека използваме първия подход при базирано на потребители и втория при съвместно филтриране въз основа на елементи.
  1. Горната функция calculate_ratings приема три параметъра id_movie, id_user, similarity_threshold.
  2. Въз основа на прага, прекаран във функцията, тя намира най-близките съседи на id_user
  3. След това отпада потребителите, които не са оценили id_movie
  4. С останалите най-близки съседи, той изчислява сумата от оценките, претеглени от техните резултати за сходство
  5. Ако id_movieне присъства в матрицата за оценки, тогава той просто връща неутрална оценка от 2,5
  • Функция за оценка на данните от теста и връщане на MAE:eval_test_data сравнява прогнозираните оценки с действителните оценки на данните от теста и връща средната абсолютна грешка.

Резултат:Накрая прилагаме всички стъпки, обсъдени досега за базирано на потребителите съвместно филтриранеи извличаме средната абсолютна грешка в данните от теста за всяко сгъване. Докато извикваме функцията eval_test_data, задаваме 0,4 като праг. Това означава, че алгоритъмът ще филтрира само тези потребители като най-близки съседи, където приликата между потребителите е по-голяма или равна на този праг. Освен това изчисляваме средната стойност на MAE за всичките пет гънки и виждаме колко добре се представя нашият алгоритъм.

Съвместно филтриране на базата на елементи

  • Функция за прогнозиране на оценките:Подобно на подхода, базиран на потребителите, можем да изградим функция calculate_ratings, която предвижда оценката на елемент X от потребител A използвайки претеглената сума от оценките на най-близките съседи на този елемент. С други думи, ние използваме оценките на други подобни артикули, за да предложим нови артикули за потребител А.В този случай методологията за избиране на най-близки съседи филтрира първите n елемента с най-висок резултат за сходство.
  1. Горната функция calculate_ratings отново приема три параметъра id_movie, id_user, top_k_similar.
  2. Въз основа на прага, прекаран във функцията, той намира top_k_similarнай-близките съседи на id_movie
  3. След това премахва филмите/елементите, които не са оценени от id_user
  4. С останалите най-близки съседи, той изчислява сумата от оценките, претеглени от техните резултати за сходство
  5. Ако id_userне присъства в матрицата за оценки, тогава той просто връща неутрална оценка от 2,5

Резултат:Подобно на съвместното филтриране на базата на потребители,ние прилагаме всички стъпки, обсъдени досега за базирано на елементи съвместно филтриране и извличаме средната абсолютна стойност грешка в тестовите данни за всяко сгъване. Докато извикваме функцията eval_test_data, задаваме 40 като праг. Това означава, че алгоритъмът ще филтрира само първите 40 елемента като най-близки съседи, които имат най-голямо сходство по косинус. Отново изчисляваме средната стойност на MAE за всичките пет пъти и виждаме колко добре се представя нашият алгоритъм.

Това беше урок стъпка по стъпка за изграждане на основен алгоритъм за съвместно филтриране в Python. Представянето на кода по-горе може да не е много лесно за следване, така че можете да се обърнете към моето хранилище Github за достъп до кода.