[PYTHON] Ich habe LightFM auf Movielens angewendet

Bei der Recherche nach Bibliotheken im Zusammenhang mit Factoriazation Machines bin ich auf eine Bibliothek namens LightFM gestoßen, also habe ich versucht, sie zu verwenden.

Irgendwann möchte ich es auf meinen eigenen Datensatz anwenden, aber dieses Mal werde ich es auf Movielens (Filmempfehlungsdatensatz) anwenden, um mich an die Verwendung von LightFM zu gewöhnen.

LightFM-Repository GitHub - lyst/lightfm: A Python implementation of LightFM, a hybrid recommendation algorithm.

Unterschied zwischen Light FM und FM

LightFM ist an FM angeschlossen, aber keine Bibliothek von Faktorisierungsmaschinen.

Beim Lesen von LightFMs Paper geben die Autoren an, dass "LightFM ein Sonderfall von FM ist".

Ich suchte nach einer Python-Implementierung von FM, war also etwas enttäuscht, aber als ich es las, hatte ich immer noch ein Modell, das die Aufgabe zu lösen schien, die ich versuchen wollte, also entschied ich mich, dies zu versuchen. (Und viele Tutorials und Dokumentationen)

Bei normalem FM können zusätzlich zur Benutzer- und Artikel-ID verschiedene Funktionen zur Eingabe als Kontextfunktionen verwendet werden. Jede Einbettung wird vorgenommen, und alle inneren Produkte werden zur Ausgabe der Summe verwendet.

f(x)=w_0 + \sum_{i=1}^d w_ix_i + \sum_{i,j}\langle \boldsymbol v_i, \boldsymbol 
 v_j \rangle x_ix_j

Nehmen Sie das innere Produkt der Benutzer- und Elementeinbettung, das innere Produkt der Kontextmerkmale usw.

LightFM kann teilweise Kontextfunktionen wie FM enthalten, aber nicht alles kann enthalten sein.

Die hinzuzufügende Funktion ist zwangsläufig entweder eine Benutzerfunktion oder eine Elementfunktion.

Was das innere Produkt betrifft, so nimmt die Funktion des Benutzers nur das innere Produkt mit der Funktion des Artikels. Es wird nicht das innere Produkt der Benutzerfunktionen verwendet.

f(i, u)=  \langle \boldsymbol p_i,  \boldsymbol q_u \rangle + b_i +b_u 

jedoch

 \boldsymbol p_i = \sum_{j \in f_i}\boldsymbol e_{j}^I
  \boldsymbol q_u = \sum_{j \in f_u}\boldsymbol e_{j}^U
  b_i = \sum_{j \in f_i}b_{j}^U
  b_u = \sum_{j \in f_u} b_{j}^U

ist.

Wenn keine Benutzer- oder Artikelmerkmale angegeben sind, entspricht dies der Form der Matrixfaktorisierung.

Die von LightFM unterstützten Verluste sind BPR, WARP, Warp-Kos und logistische Verluste. Die ersten drei sind Verluste für Rankings und eignen sich für das Ranking des Lernens mit implizitem Feedback.

Ich habe hier einen Artikel über BPR geschrieben, also zögern Sie bitte nicht, mich zu kontaktieren!

[Einführung] BPR: Bayesian Personalized Ranking aus implizitem Feedback (UAI 2009)

Lass uns gehen

Movielens-Datensatz abrufen

Movielens ist ein Datensatz mit Filmempfehlungen und wird häufig in Experimenten auf diesem Gebiet verwendet. Dieses Mal konzentriere ich mich auf eine relativ kleine Größe.

LightFM bietet freundlicherweise eine Klasse zum Laden von Movielens an. Verwenden wir sie also.

(Die LightFM-Installation kann entweder mit pip oder conda eingegeben werden. Weggelassen)

from lightfm.datasets import fetch_movielens
data = fetch_movielens()

data.keys()

Dann

dict_keys(["train", "test",  "item_features", "item_feature_labels", "item_labels"])

Ist zurückgekommen.

Zug und Test werden in der Matrix (n_user, n_item) bewertet. Wenn es keine Bewertung gibt, ist 0 enthalten.

Ich dachte, dass item_features eine Matrix aus (n_item, n_features) ist, die darstellt, welche Funktion jedes Element bis 01 hat ... aber wenn ich mir den Inhalt anschaue, sieht es aus wie eine quadratische Matrix und eine Einheitsmatrix. ist.

Das Dokument besagt außerdem, dass item_feature_label den Namen jedes Features und item_labels den Namen des Elements enthält und dass es sich um Arrays von (n_feature,) bzw. (n_item) handelt, aber sehen Sie sich den Inhalt an. Beide

array(['Toy Story (1995)', 'GoldenEye (1995)', 'Four Rooms (1995)', ...,
       'Sliding Doors (1998)', 'You So Crazy (1994)',
       'Scream of Stone (Schrei aus Stein) (1991)'], dtype=object)

war. Alle sind Artikelnamen.

Möglicherweise funktioniert dieses Tutorial ohne die Elementfunktion (dh mit Matrix Factorization).

Lernteil

Klicken Sie hier für den Teil, der das Modell tatsächlich trainiert.

train = data["train"]
test = data["test"]

model = LightFM(no_components=10,learning_rate=0.05, loss='bpr')
model.fit(train, epochs=10)

train_precision = precision_at_k(model, train, k=10).mean()
test_precision = precision_at_k(model, test, k=10).mean()

train_auc = auc_score(model, train).mean()
test_auc = auc_score(model, test).mean()

print('Precision: train %.2f, test %.2f.' % (train_precision, test_precision))
print('AUC: train %.2f, test %.2f.' % (train_auc, test_auc))

Sie können die Einbettungsdimension mit "no_components" angeben. Diesmal 10.

Bei Modell fit und auc

model.fit(train, item_features=data["item_features"], epochs=10)
auc_score(model, train, item_features=data["item_features"]).mean()

Sie können item_features wie folgt einfügen.

Dieses Mal enthält item_features jedoch nur die Element-ID, sodass sich das Ergebnis nicht ändern sollte.

item_Keine Funktion
Precision: train 0.59, test 0.10.
AUC: train 0.90, test 0.86.

item_mit Funktion
Precision: train 0.59, test 0.10.
AUC: train 0.89, test 0.86.

Ich dachte, aber es ist etwas anders ... Ist es ein Fehler?

Wenn in der LightFM-Quelle keine item_features angegeben sind, werden Item-Features mit der Einheitenmatrix von (n_item, n_item) erstellt, sodass sich beide oben genannten Elemente gleich verhalten sollten.

Holen Sie sich Einbettung

Sie können die Einbettung nach dem Lernen wie folgt erhalten.

user_embedding=model.user_embeddings
item_embedding=model.item_embeddings

user_embedding ist (n_user_features, no_components) item_embedding ist (n_item_features, no_components)

Array.

Wie ich durch einen früheren Besuch der Quelle herausgefunden habe, wurde die Einbettung für die Benutzer- / Element-ID erhalten, wenn keine Funktionen angegeben wurden.

predict

Schließlich gab es einen kleinen Stolperstein bei der Vorhersage, also notieren Sie es sich.

Wenn user_id und item_id angegeben werden, wird die Punktzahl für dieses Paar berechnet. Um eine ID anzugeben, können Sie zunächst mehrere Element-IDs für jeden Benutzer angeben.

model.predict(user_ids=0,item_ids=[1,3,4])

Dann wird die Punktzahl für Punkt 1,3,4 von Benutzer 0 berechnet. Ich denke, dass es viele Situationen gibt, in denen für jeden Benutzer ein Ranking erstellt wird, daher ist diese Schreibmethode praktisch.

Es gibt einige Punkte, die bei mehreren Benutzer-ID- und mehreren Element-ID-Paaren zu beachten sind.

model.predict(user_ids=[4,3,1],item_ids=[1,3,4])

In diesem Fall wird ein Bestätigungsfehler angezeigt.

Korrekt

import numpy as np
model.predict(user_ids=np.array([4,3,1]),item_ids=[1,3,4])

Wenn beim Lesen der Quelle die Benutzer-ID kein Numpy-Array ist, wird der Vorgang des Wiederholens der Anzahl der Element-IDs eingeschlossen, um die Anzahl mit den Element-IDs abzugleichen. Wenn die Benutzer-ID int ist (bei der Berechnung der Punktzahl für mehrere Elemente pro zuvor erwähntem Benutzer), sind die Längen gleich, aber wenn user_ids als Liste angegeben wird, wird sie wiederholt und die Länge ist gleich. Wird nicht ausgerichtet. Das ist eine Falle ...

Ich sollte entscheiden, ob ich mit "Kann user_ids len berechnen?" Wiederhole. Jemand wird Ihnen eine Liste geben ...

Über Verlust

BPR und WARP wurden so implementiert, dass diejenigen mit einer positiven Bewertung als positives Feedback angesehen werden. Es scheint, dass Sie es hier nicht auf 1 korrigieren und geben müssen.

Es wurde geschrieben, dass logistische Verluste verwendet werden können, wenn +1 und -1 Rückmeldungen vorliegen. Es hat funktioniert, auch wenn ich die Bewertungsmatrix so gegeben habe, wie sie war. (Ich konnte nicht ganz verstehen, was ich drinnen tat, indem ich nur auf die Quelle schaute)

logistic


Precision: train 0.43, test 0.08.
AUC: train 0.87, test 0.84.

bpr(Erneut veröffentlichen)


Precision: train 0.59, test 0.10.
AUC: train 0.90, test 0.86.

Sie sehen jedoch, dass es nicht als Ranking-Index geeignet ist.

abschließend

Wie oben erwähnt, denke ich, dass die grundlegende Verarbeitung jetzt durchgeführt werden kann.

Ich bin froh, dass die Tutorials und die Dokumentation leicht zu verstehen sind und dass mehrere Verluste unterstützt werden.

Ich habe es kurz geschrieben, aber es ist auch praktisch, dass auch Bewertungsindikatoren wie AUC und Precision @ k bereitgestellt werden.

Als nächstes werde ich LightFM endlich auf meinen eigenen Datensatz anwenden!

Vielen Dank für das Lesen bis zum Ende.

Recommended Posts

Ich habe LightFM auf Movielens angewendet
Ich fing an zu analysieren
Ich habe versucht zu debuggen.
Ich habe versucht, PredNet zu lernen
Ich habe versucht, SVM zu organisieren.
Ich habe mit Raspberry Pi gesprochen
Ich habe versucht, PCANet zu implementieren
Einführung in die nichtlineare Optimierung (I)
Ich möchte SUDOKU lösen
Ich habe versucht, Linux wieder einzuführen
Ich habe versucht, Pylint vorzustellen
Ich habe versucht, SparseMatrix zusammenzufassen
jupyter ich habe es berührt
Ich habe versucht, StarGAN (1) zu implementieren.
Ich habe versucht, Deep VQE zu implementieren
Ich habe versucht, eine Quip-API zu erstellen
Ich habe versucht, Python zu berühren (Installation)
Ich möchte systemd grob verstehen
Ich habe versucht, Pytorchs Datensatz zu erklären
Ich habe Watson Voice Authentication (Speech to Text) ausprobiert.
Ich habe versucht, das Wahrscheinlichkeitsintegral (I zu Integral) zu berechnen.
Ich habe Teslas API berührt
Ich wollte cGAN zu ACGAN weiterentwickeln
Ich möchte Bilder kratzen und trainieren
Ich habe versucht, mich über MCMC zu organisieren.
Ich möchte ○○ mit Pandas machen
Ich habe versucht, Realness GAN zu implementieren
Ich möchte Yolos Anmerkung kopieren
Ich möchte mit Python debuggen
Hash-Kette wollte ich vermeiden (1)
Ich habe versucht, den Ball zu bewegen
Ich war süchtig nach Multiprocessing + Psycopg2
Ich habe versucht, den Abschnitt zu schätzen.
Eine Geschichte, die mich süchtig nach dem Versuch machte, LightFM unter Amazon Linux zu installieren