
Vor nicht allzu langer Zeit fand auf der
Boosters- Plattform ein Wettbewerb mit Empfehlungssystemen aus dem Okko-
Onlinekino -
Rekko Challenge 2019 statt. Für mich war es die erste Erfahrung, an einem Wettbewerb mit einer Rangliste teilzunehmen (vorher habe ich nur bei einem Hackathon Kraft versucht). Die Aufgabe ist interessant und mir aus der Praxis vertraut, es gibt einen Preisfonds, was bedeutet, dass es Sinn macht, daran teilzunehmen. Infolgedessen belegte ich den 14. Platz, für den die Organisatoren ein T-Shirt zum Gedenken herausgaben. Schön Vielen Dank.
In diesem Artikel werde ich Sie kurz in die Aufgabe eintauchen lassen, über die von mir vorgebrachten Hypothesen sprechen und darüber, wie Sie den Wettbewerb in Empfehlungssystemen schleppen und ohne Stapelerfahrung in die Top 15 gelangen können. Dies ist besonders nützlich für diejenigen, die nur an Wettbewerben teilnehmen werden.
Empfehlungssysteme
Das Hauptziel von Empfehlungssystemen ist es, dem Benutzer das zu geben, was er kaufen
möchte (leider wird uns eine solche hypertrophierte Sichtweise durch kommerzielle Anwendung auferlegt).
Es gibt verschiedene Aussagen zu Aufgaben (Rangfolge, Suche nach ähnlichen Aufgaben, Vorhersage eines bestimmten Elements) und dementsprechend Möglichkeiten, diese zu lösen. Nun, wir alle lieben die Variabilität bei der Auswahl, die sich aus einer Reihe von möglichen Lösungen für jedes Problem ergibt. Verschiedene Ansätze sind im Artikel
Anatomie von Empfehlungssystemen gut beschrieben. Natürlich hat niemand das
NFL-Theorem aufgehoben, was bedeutet, dass wir im Wettbewerbsproblem verschiedene Algorithmen ausprobieren können.
Erklärung des Problems
Lesen Sie mehr über die Aufgabe und die Daten im
Artikel der Organisatoren. TL; DR hier werde ich das notwendige Minimum zum Verständnis des Kontextes beschreiben.
Der Datensatz enthält etwas mehr als zehntausend Filme mit anonymisierten Attributen. Die folgenden Optionen stehen als Benutzerelement-Interaktionsmatrizen zur Verfügung:
- Transaktionen - enthält Fakten von Benutzern, die Inhalte kaufen / mieten / im Abonnement anzeigen;
- Bewertungen - Bewertungen von Filmen durch Benutzer;
- Lesezeichen - das Ereignis des Hinzufügens eines Films zu Lesezeichen.
Alle Informationen werden über einen bestimmten Zeitraum hinweg aufgenommen und in willkürlichen Einheiten dargestellt, die mit real verknüpft sind.
Der Inhalt hatte die folgenden Attribute:

Sie können im Artikel der Organisatoren ausführlich darüber lesen, aber ich möchte sofort darauf achten, was mir aufgefallen ist: den Parameter „Attribute“. Es enthielt eine Tüte kategorialer Attribute mit einer Kardinalität von ~ 36.000. Es gab durchschnittlich 15 Werte pro Film. Auf den ersten Blick werden nur die grundlegendsten Attribute, die den Inhalt beschreiben, in diesen Werten verschlüsselt: Schauspieler, Regisseure, Land, Abonnements oder Sammlungen, zu denen der Film gehört.
Es ist notwendig, 20 Filme vorherzusagen, die Testbenutzer in den nächsten zwei Monaten sehen werden. Testbenutzer sind 50.000 von allen 500.000 Benutzern. In der Rangliste sind sie in zwei Hälften geteilt: jeweils 25.000 öffentlich / privat.
Metrisch
Die Organisatoren haben als Metrik die mittlere durchschnittliche Genauigkeit für 20 Elemente (MNAP @ 20) als Metrik ausgewählt. Der Hauptunterschied zum üblichen MAP besteht darin, dass für Benutzer, die im Testzeitraum keine 20 Filme gesehen haben, die Rationierung nicht für k erfolgt, sondern für den tatsächlichen Wert der angesehenen Filme.

Lesen Sie mehr und sehen Sie den Code in Cython
hier.Validierung
Zur Lösung des Problems gelangen. Zunächst musste entschieden werden, was validiert wurde. Da wir in Zukunft Filme vorhersagen müssen, können wir keine einfache Aufschlüsselung nach Benutzern vornehmen. Aufgrund der Tatsache, dass die Zeit anonymisiert ist, musste ich zumindest ungefähr anfangen, sie zu entschlüsseln. Dazu habe ich mehrere Benutzer genommen, einen Zeitplan für Transaktionen erstellt und eine bestimmte Saisonalität festgestellt. Es wurde angenommen, dass es täglich ist, und wenn wir den Zeitunterschied zwischen den Tagen kennen, können wir berechnen, für welchen Zeitraum die Daten hochgeladen wurden. Es stellte sich heraus, dass dies Transaktionen für 6 Monate waren. Dies wurde später im Telegrammkanal bestätigt, in dem der Wettbewerb besprochen wurde.

Die obige Grafik zeigt die stündliche Häufigkeit von Transaktionen am Beispiel von einmonatigen Daten. Drei markante Gipfel pro Woche ähneln Freitag-, Samstag- und Sonntagabenden.
Folglich haben wir sechs Monate Zeit, und Filme müssen für die nächsten zwei Monate vorhergesagt werden. Wir werden das letzte Drittel der Trainingsbeispielzeit als Validierungsdatensatz verwenden.

Die nächsten Einreichungen zeigten, dass die Aufteilung gut gewählt wurde und die lokale Validierungsgeschwindigkeit hervorragend mit der Rangliste korrelierte.
Versuch, Daten zu dekanonymisieren
Zunächst habe ich beschlossen, alle Filme zu dekanonymisieren, damit:
- Generieren Sie eine Reihe von Zeichen durch Metainformationen des Inhalts. Zumindest kommen folgende Personen in den Sinn: Genres, Besetzung, Eintrag in Abonnements, Textbeschreibung usw.;
- Wirf den Ofen der Wechselwirkungen von der Seite ein, um die Kargheit der Matrix zu verringern. Ja, die Wettbewerbsregeln haben die Verwendung externer Daten nicht verboten. Natürlich gab es keine Hoffnung auf eine Übereinstimmung mit offenen Datensätzen, aber niemand hat das Parsen russischer Portale abgesagt.
Es scheint eine logische Motivation zu sein, die nach meinen Erwartungen zu einer Killer-Lösung werden sollte.
Zunächst habe ich beschlossen, die Okko-Website zu analysieren und alle Filme zusammen mit ihren Eigenschaften (Bewertung, Dauer, Altersbeschränkungen und andere) herauszuholen. Nun, wie man analysiert - alles stellte sich als recht einfach heraus. In diesem Fall könnten Sie die API verwenden:

Nachdem Sie in den Katalog gegangen waren und ein bestimmtes Genre oder Abonnement ausgewählt hatten, mussten Sie nur noch auf eines der Elemente eingehen. In Reaktion auf die obige Anfrage fällt die gesamte Reihe von Filmen im Genre / Abonnement mit allen Attributen aus. Sehr bequem :)
So sahen die Attribute eines Elements in der Struktur aus"element": { "id": "c2f98ef4-2eb5-4bfd-b765-b96589d4c470", "type": "SERIAL", "name": " ", "originalName": " ", "covers": {...}, "basicCovers": {...}, "description": " , ...", "title": null, "worldReleaseDate": 1558731600000, "ageAccessType": "16", "ageAccessDescription": "16+ 16 ", "duration": null, "trailers": {...}, "kinopoiskRating": 6, "okkoRating": 4, "imdbRating": null, "alias": "staraja-gvardija", "has3d": false, "hasHd": true, "hasFullHd": true, "hasUltraHd": false, "hasDolby": false, "hasSound51": false, "hasMultiAudio": false, "hasSubtitles": false, "inSubscription": true, "inNovelty": true, "earlyWindow": false, "releaseType": "RELEASE", "playbackStartDate": null, "playbackTimeMark": null, "products": { "items": [ { "type": "PURCHASE", "consumptionMode": "SUBSCRIPTION", "fromConsumptionMode": null, "qualities": [ "Q_FULL_HD" ], "fromQuality": null, "price": { "value": 0, "currencyCode": "RUB" }, "priceCategory": "679", "startDate": 1554670800000, "endDate": null, "description": null, "subscription": { "element": { "id": "bc682dc6-c0f7-498e-9064-7d6cafd8ca66", "type": "SUBSCRIPTION", "alias": "119228" } }, "offer": null, "originalPrice": null }, ... ], "emptyReason": null }, "licenses": null, "assets": {...}, "genres": { "items": [ { "element": { "id": "Detective", "type": "GENRE", "name": "", "alias": "Detective" } }, ... ], "totalSize": 2 }, "countries": { "items": [ { "element": { "id": "3b9706f4-a681-47fb-918e-182ea9dfef0b", "type": "COUNTRY", "name": "", "alias": "russia" } } ], "totalSize": 1 }, "subscriptions": { "items": [ { "element": { "id": "bc682dc6-c0f7-498e-9064-7d6cafd8ca66", "type": "SUBSCRIPTION", "name": " ", "alias": "119228" } }, ... ], "totalSize": 7 }, "promoText": null, "innerColor": null, "updateRateDescription": null, "contentCountDescription": null, "copyright": null, "subscriptionStartDate": null, "subscriptionEndDate": null, "subscriptionActivateDate": null, "stickerText": null, "fullSeasonPriceText": null, "purchaseDate": null, "expireDate": null, "lastWatchedChildId": null, "bookmarkDate": null, "userRating": null, "consumeDate": null, "lastStartingDate": null, "watchDate": null, "startingDate": null, "earlyWatchDate": null }
Es bleibt, alle Genres durchzugehen, JSON zu analysieren und dann Duplikate zuzulassen, da ein Film zu mehreren Genres / Abonnements gehören kann.
Ja, hier hatte ich Glück und habe viel Zeit gespart. Wenn dies nicht der Fall ist und Sie HTML-Inhalte analysieren müssen, gibt es Artikel auf dem Hub, die Ihnen beispielsweise
hier helfen können.
"Das Ding ist der Hut", dachte ich, "wir können ihn nur zurückhalten." „Der Punkt ist der Hut“, stellte ich am nächsten Tag fest: Die Daten stimmten nicht absolut überein. Darüber unten.
Erstens war die Größe des Katalogs erheblich unterschiedlich: im Datensatz - 10.200, auf der Website gesammelt - 8870. Dies folgt aus der Historizität des Datensatzes: Es wurde nur das heruntergeladen, was sich jetzt auf der Website befindet, und die Wettbewerbsdaten für 2018. Einige der Filme sind nicht mehr verfügbar. Ups
Zweitens war von den möglichen Attributen für das Match eine anhaltende Intuition nur in Bezug auf Folgendes:
feature5 - Altersgrenze. Es war leicht zu verstehen. Die Kardinalität des Attributs beträgt 5 eindeutige Gleitkommawerte und "-1". Unter den gesammelten Daten wurde das Attribut "ageAccessType" mit einer Kardinalität von 5 gefunden. Die Zuordnung sah folgendermaßen aus:
catalogue.age_rating = catalogue.age_rating.map({0: 0, 0.4496666915: 6 0.5927161087: 12 0.6547073468: 16 0.6804096966000001: 18})
feature2 - konvertierte Filmbewertung aus der Filmsuche. In der EDA-Phase wurde die Idee, dass es sich um ein Rating handelt, zunächst durch die Korrelation des Parameters mit der Gesamtzahl der Ansichten eingereicht. Anschließend bestätigte die Annahme, dass diese Bewertung aus einer Filmsuche stammt, das Vorhandensein des Parameters „kinopoiskRating“ in den Site-Daten.
Dem Spiel einen Schritt näher! Jetzt bleibt noch eine Möglichkeit zu finden, die Konvertierung für den in anonymer Form dargestellten Parameter
feature2 umzukehren.
So sieht die Werteverteilung in
Feature2 aus :

Und so die Verteilung der
kinopoiskRating- Parameterwerte:

Als ich diese Bilder meinem Kollegen Sasha zeigte, sah er sofort, dass dies ein Grad von drei war. Drei Mathematiker werden nicht respektiert, aber die Zahl Pi ist sehr gerade. Infolgedessen stellte sich Folgendes heraus:

Es scheint alles zu sein, aber nicht ganz. Wir sehen identische Verteilungen, aber die Nennwerte und die Menge konvergieren immer noch nicht. Wenn wir eine bestimmte Anzahl von Vergleichsbeispielen kennen würden, müsste nur eine lineare Funktion angenähert werden, um den Faktor zu finden. Aber wir hatten sie nicht.
Eine Annäherung ist übrigens nicht das am besten geeignete Wort. Wir brauchen eine Lösung mit einem Fehler fast gleich Null. Die Genauigkeit der gesammelten Daten beträgt 2 Zeichen nach dem Trennzeichen. Wenn Sie bedenken, dass es viele Filme mit einer Bewertung von 6.xx und Filme mit derselben Bewertung gibt, sollten Sie hier um Präzision kämpfen.
Was können Sie noch versuchen? Sie können sich auf die Minimal- und Maximalwerte verlassen und MinMaxScaler verwenden, aber die Unzuverlässigkeit dieser Methode lässt sofort Zweifel aufkommen. Ich möchte Sie daran erinnern, dass die Anzahl der Filme anfangs nicht übereinstimmte und unser Datensatz historisch ist und den aktuellen Status auf der Website aufweist. Das heißt, Es gibt keine Garantie dafür, dass die Filme mit den Mindest- und Höchstbewertungen in beiden Gruppen identisch sind (es stellte sich heraus, dass sie eine unterschiedliche Altersgrenze hatten und die Dauer nicht mit dem Wort „vollständig“ übereinstimmte), und es gibt kein Verständnis dafür, wie oft OKKO aktualisiert wird API täglich wechselnde Bewertung der Filmsuche.
So wurde klar, dass ich mehr Attributkandidaten für das Matching brauchte.
Was ist sonst noch interessant?feature1 ist eine Art Datum. Theoretisch versprachen die Organisatoren für Daten die Wahrung der Trennung von Staaten, was eine lineare Funktion implizierte. Im Allgemeinen sollte die Transformation mit dem
ts- Attribut für die Interaktionsmatrizen identisch sein. Wenn Sie sich die Verteilung von Filmen nach
Feature_1 ansehen ...

... dann wird die Hypothese des Veröffentlichungsdatums des Films sofort weggefegt. Die Intuition legt nahe, dass die Anzahl der von der Industrie produzierten Filme im Laufe der Zeit zunehmen sollte. Dies wird unten bestätigt.
Die Daten, die wir von der Site erhalten haben, enthalten 14 Attribute. Tatsächlich waren die Werte leider nur für Folgendes enthalten:



Keines der obigen Beispiele ähnelt
feature_1 . Nun, es gab keine Vergleichsideen mehr, und es scheint, dass die ganze Aufregung um diese Aufgabe vergebens war. Natürlich habe ich von Wettbewerben gehört, bei denen die Jungs die Daten manuell markiert haben, aber nicht, wenn es um Hunderte und Tausende von Kopien geht.
Lösung
1. Einfache ModelleAls mir klar wurde, dass nicht alles so einfach ist, begann ich demütig mit dem zu arbeiten, was ist. Für den Anfang wollte ich mit einem einfachen beginnen. Ich habe verschiedene Lösungen ausprobiert, die in der Branche häufig verwendet werden:
kollaboratives Filtern (in unserem Fall artikelbasiert) und
Faktorisieren von Matrizen .
Die Community nutzt in großem Umfang einige Python-Bibliotheken, die für diese Aufgaben geeignet sind:
implizit und
LightFM . Der erste ist in der Lage, basierend auf ALS sowie Nearest Neighbor Collaborative Filtering mit mehreren Optionen zur Vorverarbeitung der Artikel-Artikel-Matrix zu faktorisieren. Der zweite hat zwei unterscheidende Faktoren:
- Die Faktorisierung basiert auf SGD, wodurch es möglich ist, stichprobenbasierte Verlustfunktionen, einschließlich WARP, zu verwenden .
- Es verwendet einen hybriden Ansatz, bei dem Informationen zu Benutzerattributen und Elementen im Modell so kombiniert werden, dass der latente Vektor des Benutzers die Summe der latenten Vektoren seiner Attribute ist. Und ähnlich für Artikel. Dieser Ansatz ist äußerst praktisch, wenn für den Benutzer / Artikel ein Kaltstartproblem vorliegt.
Wir hatten keine Benutzerattribute (abgesehen von der Möglichkeit, sie basierend auf der Interaktion mit Filmen anzuzeigen), daher habe ich nur die Attribute von Elementen verwendet.
Insgesamt wurden 6 Einstellungen vorgenommen, um die Parameter aufzulisten. Eine Kombination von drei Matrizen wurde als Interaktionsmatrix verwendet, wobei die Bewertungen in binär umgewandelt wurden. Vergleichsergebnisse mit den besten Hyperparametern für jede Einstellung in der folgenden Tabelle.
Wie Sie sehen können, hat sich die klassische kollaborative Filterung als viel besser erwiesen als andere Modelle. Nicht perfekt, aber von der Basislinie wird nicht viel verlangt. Senden mit dieser Konfiguration ergab 0.03048 in der öffentlichen Rangliste. Ich erinnere mich nicht an die Position zu diesem Zeitpunkt, aber zum Zeitpunkt des Abschlusses des Wettbewerbs hätte diese Einreichung definitiv die Top 80 erreicht und eine Bronzemedaille geliefert.
2. Hallo BoostingWas könnte besser sein als ein Modell? Richtig: mehrere Modelle.
Daher war die nächste Option ein Ensemble oder im Rahmen von Empfehlungen ein Ranking-Modell der zweiten Ebene. Als Ansatz habe ich
diesen Artikel von den Jungs aus Avito genommen. Es scheint streng nach dem Rezept zu kochen, regelmäßig umzurühren und mit den Eigenschaften von Filmen zu würzen. Die einzige Abweichung war die Anzahl der Kandidaten: Ich habe die Top 200 von LightFM genommen, weil mit 500.000 Benutzern passten einfach nicht in den Speicher.
Infolgedessen war die von mir bei der Validierung erzielte Geschwindigkeit schlechter als bei einem Modell.
Nach mehreren Tagen des Experimentierens stellte sich heraus, dass nichts funktionierte und nichts von alleine funktionieren würde. Oder ich weiß nicht, wie ich es kochen soll (Spoiler: die richtige zweite Antwort). Was mache ich falsch? Zwei Gründe kamen mir in den Sinn:
- Einerseits ist es sinnvoll, die Top 200 aus dem Modell der ersten Ebene zu nehmen, um "harte negative" Proben zu erzeugen, d. H. jene Filme, die auch für den Benutzer relevant sind, aber von ihm nicht gesehen werden. Andererseits können einige dieser Filme während des Testzeitraums angesehen werden, und wir präsentieren diese Beispiele als negativ. Als nächstes beschloss ich, das Risiko dieser Tatsache zu verringern und die Hypothese mit dem folgenden Experiment zu überprüfen: Ich nahm alle positiven Beispiele + zufällig für die Trainingsstichprobe. Die Geschwindigkeit der Testprobe verbesserte sich nicht. Hier muss klargestellt werden, dass es in der Stichprobe des Tests auch Top-Vorhersagen aus dem First-Level-Modell gab, da mir auf der Rangliste niemand alle positiven Beispiele nennen wird.
- Von den 10.200 im Katalog verfügbaren Filmen haben nur 8.296 Filme Wechselwirkungen hergestellt. Fast 2.000 Filme wurden der Aufmerksamkeit des Benutzers beraubt, teilweise weil sie im Rahmen eines Abonnements nicht zum Kauf / Verleih / zur Verfügung standen. Die Jungs im Chat fragten, ob unzugängliche Filme im Testzeitraum verfügbar werden könnten. Die Antwort war ja. Es ist definitiv unmöglich, sie rauszuwerfen. Daher schlug ich vor, dass in den nächsten 2 Monaten fast 2.000 weitere Filme verfügbar sein werden. Warum sollten Sie sie sonst in den Datensatz werfen?
3. NeuronenAus dem vorherigen Absatz wurde die Frage gestellt: Wie können wir mit Filmen arbeiten, für die es überhaupt keine Interaktionen gibt? Ja, wir erinnern uns an Elementfunktionen in LightFM, aber wie wir uns erinnern, wurden sie nicht eingegeben. Was sonst? Neuronen!
Das Open-Source-Arsenal verfügt über einige recht beliebte High-Level-Bibliotheken für die Arbeit mit Empfehlungssystemen:
Spotlight von Maciej Kula (Autor von LightFM) und
TensorRec . Der erste unter der Haube PyTorch, der zweite - Tensorflow.
Spotlight kann implizite / explizite Datensätze mit Neuronen und Modellsequenzen faktorisieren. Gleichzeitig gibt es in der Faktorisierung "out of the box" keine Möglichkeit, Benutzer- / Artikelfunktionen hinzuzufügen. Lassen Sie sie also fallen.
TensorRec hingegen weiß nur zu faktorisieren und ist ein interessanter Rahmen:
- Darstellungsdiagramm - Eine Methode zur Transformation (kann für Benutzer / Element unterschiedlich eingestellt werden) von Eingabedaten beim Einbetten, basierend darauf, welche Berechnungen im Vorhersagediagramm durchgeführt werden. Die Auswahl besteht aus Ebenen mit unterschiedlichen Aktivierungsoptionen. Es ist auch möglich, eine abstrakte Klasse zu verwenden und an einer benutzerdefinierten Transformation teilzunehmen, die aus einer Folge von Keras-Ebenen besteht.
- Mit dem Vorhersagediagramm können Sie die Operation am Ende auswählen: Ihr bevorzugtes Punktprodukt, euklidischer und Kosinusabstand.
- Verlust - es gibt auch viel zur Auswahl. Wir waren mit der Implementierung von WMRB zufrieden (im Wesentlichen das gleiche WARP, weiß nur, wie man Batch lernt und verteilt)
Am wichtigsten ist, dass TensorRec mit Kontextfunktionen arbeiten kann, und der Autor gibt tatsächlich zu, dass er ursprünglich von der Idee von LightFM inspiriert war. Nun, mal sehen. Wir übernehmen Interaktionen (nur Transaktionen) und Artikelfunktionen.
Wir senden zur Suche nach verschiedenen Konfigurationen und warten. Im Vergleich zu LightFM dauern Schulung und Validierung lange.
Darüber hinaus gab es einige Unannehmlichkeiten, die auftreten mussten:
- Durch das Ändern des ausführlichen Flags hat die Anpassungsmethode nichts geändert, und es wurden keine Rückrufe für Sie bereitgestellt. Ich musste eine Funktion schreiben, die eine Ära intern mit der Methode fit_partial trainierte, und dann die Validierung für Zug und Test ausführen (in beiden Fällen wurden Stichproben verwendet, um den Prozess zu beschleunigen).
- Im Allgemeinen ist der Autor des Frameworks ein großartiger Kerl und verwendet tf.SparseTensor überall. Es lohnt sich jedoch zu verstehen, dass Sie als Vorhersage, auch zur Validierung, das Ergebnis in dicht als Vektor mit der Länge n_items für jeden Benutzer erhalten. Daraus ergeben sich zwei Tipps: Erstellen Sie einen Zyklus zum Generieren von Vorhersagen mit Stapeln (die Bibliotheksmethode hat keinen solchen Parameter) mit Top-k-Filterung und bereiten Sie die Streifen mit RAM vor.
Letztendlich gelang es mir bei der besten Konfigurationsoption, 0,02869 auf mein Testmuster zu drücken. Es gab etwas Ähnliches wie LB.
Was habe ich mir erhofft? Das Hinzufügen von Nichtlinearität zu Elementmerkmalen führt zu einer Verdoppelung der Metrik? Es ist naiv.
4. Beck diese AufgabeAlso warte einen Moment. Es scheint, dass ich wieder auf Jonglierneuronen gestoßen bin. Welche Hypothese wollte ich testen, als ich dieses Geschäft aufnahm? Die Hypothese lautete: „In den nächsten zwei Monaten der verspäteten Auswahl werden fast 2.000 neue Filme auf der Rangliste zu sehen sein. Einige von ihnen werden einen großen Teil der Ansichten einnehmen. “
Sie können dies also in zwei Schritten überprüfen:
- Es wäre schön zu sehen, wie viele Filme wir in der von uns ehrlich aufgeteilten Testphase bezüglich Zug hinzugefügt haben. Wenn wir nur die Ansichten vertreten, dann sind die "neuen" Filme nur 240 (!). Die Hypothese zitterte sofort. Es scheint, dass der Kauf neuer Inhalte von Periode zu Periode nicht um diesen Betrag abweichen kann.
- Wir beenden. Wir haben die Möglichkeit, das Modell so zu trainieren, dass nur die Präsentation basierend auf Elementfunktionen verwendet wird (in LightFM erfolgt dies beispielsweise standardmäßig, wenn wir die Attributmatrix nicht mit der Identitätsmatrix vorab ausgefüllt haben). Außerdem können wir uns wegen Verletzung nur (!) Unseren unzugänglichen und nie gesehenen Filmen unterwerfen. Aus diesen Ergebnissen senden wir 0,0000136.
Bingo! Dies bedeutet, dass Sie aufhören können, Semantik aus Filmattributen herauszupressen. Übrigens, später beim DataFest sagten Leute von OKKO, dass der größte Teil des unzugänglichen Inhalts nur einige alte Filme waren.
Sie müssen etwas Neues und Neues ausprobieren - das alte vergessen. In unserem Fall nicht ganz vergessen, aber was ist vor ein paar Tagen passiert. Kollaboratives Filtern?
5. Stimmen Sie die Basislinie abWie kann ich der CF-Baseline helfen?
Idee Nummer 1Im Internet fand ich eine Präsentation über die Verwendung des Likelihood-Ratio-Tests zum Herausfiltern kleinerer Filme.
Unten werde ich meinen Python-Code verlassen, um den LLR-Score zu berechnen, den ich auf mein Knie schreiben musste, um diese Idee zu testen.
LLR-Berechnung import numpy as np from scipy.sparse import csr_matrix from tqdm import tqdm class LLR: def __init__(self, interaction_matrix, interaction_matrix_2=None): interactions, lack_of_interactions = self.make_two_tables(interaction_matrix) if interaction_matrix_2 is not None: interactions_2, lack_of_interactions_2 = self.make_two_tables(interaction_matrix_2) else: interactions_2, lack_of_interactions_2 = interactions, lack_of_interactions self.num_items = interaction_matrix.shape[1] self.llr_matrix = np.zeros((self.num_items, self.num_items))
Infolgedessen kann die resultierende Matrix als Maske verwendet werden, um nur die wichtigsten Wechselwirkungen zu belassen, und es gibt zwei Optionen: Schwellenwert verwenden oder Top-k-Elemente mit dem höchsten Wert belassen. Auf die gleiche Weise wird die Kombination mehrerer Einflüsse auf einen Kauf in einer Geschwindigkeit verwendet, um Artikel zu bewerten. Mit anderen Worten, der Test zeigt, wie wichtig es ist, beispielsweise Favoriten hinsichtlich einer möglichen Umwandlung in einen Kauf hinzuzufügen. Es sieht vielversprechend aus, aber die Verwendung hat gezeigt, dass das Filtern mit dem LLR-Score eine sehr kleine Steigerung ergibt und das Kombinieren mehrerer Scores das Ergebnis nur verschlechtert. Anscheinend ist die Methode nicht für diese Daten. Von den Pluspunkten kann ich nur feststellen, dass ich mich bei der Umsetzung dieser Idee mit dem Impliziten unter der Haube befassen musste.
Ein Beispiel für die implizite Anwendung dieser benutzerdefinierten Logik bleibt unter der Katze.
Änderung der Matrix implizit Idee Nummer 2Es kam eine weitere Idee auf, die die Vorhersagen für eine einfache kollaborative Filterung verbessern könnte. Die Industrie verwendet oft eine Dämpfungsfunktion für alte Schätzungen, aber wir haben einen nicht so einfachen Fall. Wahrscheinlich müssen Sie 2 mögliche Fälle irgendwie berücksichtigen:
- Benutzer, die den Dienst sehen, sind größtenteils neu
- "Prüfer." Das heißt, diejenigen, die vor relativ kurzer Zeit gekommen sind und sich zuvor beliebte Filme ansehen können.
Somit ist es möglich, die kollaborative Komponente automatisch in zwei verschiedene Gruppen zu unterteilen. Zu diesem Zweck habe ich eine Funktion erfunden, die anstelle impliziter Werte, die an der Schnittstelle zwischen Benutzer und Film auf „1“ oder „0“ gesetzt sind, zeigt, wie wichtig dieser Film im Betrachtungsverlauf des Benutzers ist.
Dabei ist
StartTime das Veröffentlichungsdatum des Films und
ΔWatchTime die Differenz zwischen dem Veröffentlichungsdatum und dem Datum, das der Benutzer gesehen hat, und
α und
β sind Hyperparameter.
Hier ist der erste Begriff für die Erhöhung der Geschwindigkeit von Filmen verantwortlich, die kürzlich veröffentlicht wurden, und der zweite für die Berücksichtigung der Sucht der Benutzer nach alten Filmen. Wenn ein Film vor langer Zeit veröffentlicht wurde und der Benutzer ihn sofort gekauft hat, sollte diese Tatsache heute nicht viel berücksichtigt werden. Wenn dies eine Art Neuheit ist, müssen wir sie einer größeren Anzahl von Benutzern empfehlen, die auch neue Artikel ansehen. Wenn der Film ziemlich alt ist und der Benutzer ihn erst jetzt gesehen hat, kann dies auch für Leute wie ihn wichtig sein.
Es ist noch eine Kleinigkeit übrig - um die Koeffizienten
α und
β zu sortieren. Gehen Sie für die Nacht, und die Arbeit ist erledigt. Es gab überhaupt keine Annahmen über den Bereich, daher war er anfangs groß, und unten sind die Ergebnisse einer lokalen optimalen Suche aufgeführt.

Unter Verwendung dieser Idee ergab ein einfaches Modell auf einer Matrix eine Geschwindigkeit von 0,03627 bei lokaler Validierung und 0,03685 bei öffentlicher LB, was im Vergleich zu früheren Ergebnissen sofort einen guten Schub darstellt. Zu dieser Zeit brachte es mich zu den Top 20.
Idee Nr. 3 Dieletzte Idee war, dass alte Filme, die der Benutzer lange gesehen hatte, überhaupt ignoriert werden können. Diese CF-Screening-Methode wird oft als Beschneiden bezeichnet. Lassen Sie uns einige Werte durchgehen und die Hypothese testen:
Es stellt sich heraus, dass es für Benutzer mit einer langen Geschichte sinnvoll ist, nur die letzten 25 Interaktionen zu belassen.Insgesamt erreichten wir durch die Arbeit mit Daten eine Geschwindigkeit von 0,040312 für die lokale Testprobe, und die Einreichung mit diesen Parametern ergab das Ergebnis von 0,03870 bzw. 0,03990 für den öffentlichen / privaten Teil und gab mir den 14. Platz und ein T-Shirt.Anerkannte Segmente
Das Ausführen von Projekten im Jupyter-Notizbuch ist ein undankbarer Job. Sie verlieren sich ständig in Ihrem Code, der auf mehrere Notizbücher verteilt ist. Und Ergebnisse nur in Ausgabezellen zu verfolgen, ist hinsichtlich der Reproduzierbarkeit völlig gefährlich. Daher bewältigen Datasaentisten so viel wie möglich. Meine Kollegen und ich haben unser Cookie-Cutter-Data-Science- Framework erstellt - Ocean. Dies ist ein Werkzeug zum Erstellen von Struktur- und Projektmanagement. Über die Vorteile können Sie in unserem Artikel lesen . Vor allem aufgrund des guten Ansatzes zur Trennung von Experimenten verlor ich nicht den Verstand und wurde beim Testen von Hypothesen nicht verwirrt.Das Erfolgsgeheimnis (nicht meins)
Wie unmittelbar nach der Eröffnung des privaten Teils der Rangliste bekannt wurde, verwendeten fast alle Leute mit Top-Lösungen einfache Modelle auf der ersten Ebene und verstärkten sie mit zusätzlichen Funktionen auf der zweiten. Wie ich später verstand, war meine Punktion in diesem Experiment in erster Linie eine Möglichkeit, die Probe beim Training des Modells der zweiten Ebene aufzuteilen. Ich habe es versucht:
Als ich merkte, dass das dumm war, suchte ich nach ziemlich ausgefeilten Methoden wie dieser:
Nun, ich fand den richtigen Weg auf der Folie aus der Präsentation von Evgeny Smirnov, der den 2. Platz belegte. Es war eine Aufteilung der Benutzer im Testteil des Modells der ersten Ebene. Es scheint trivial, aber diese Idee kam mir nicht.
Fazit
Wettbewerbe sind Wettbewerbe. Schwere Modelle bieten wirklich mehr Genauigkeit, besonders wenn Sie sie kochen können. Wird diese Erfahrung nützlich sein? Anstelle einer Antwort möchte ich sagen, dass die Organisatoren nach dem Ende des Wettbewerbs einen Spoiler abgeworfen haben - ein Feature-Wichtigkeits-Diagramm aus dem Produktmodell, nach dem es offensichtlich ist, dass sie denselben „erfolgreichen“ Ansatz in der Produktion verwenden. Es stellt sich heraus, dass sie auch im Stoß fließen.Es stellt sich heraus, dass die Erfahrung der Teilnahme für mich beruflich sehr nützlich war. Vielen Dank für das Lesen des Artikels; Fragen, Anregungen, Kommentare sind willkommen.