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.
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)
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).
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.
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 ...
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.
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