Ich habe einen Artikel geschrieben, weil es nicht viele Tutorials auf der Welt gab, die anhand von Beispieldaten zu Empfehlungen implementiert wurden.
Es gibt Methoden wie maschinelles Lernen, um Empfehlungen zu erstellen. Dies ist jedoch ein Artikel zum Erstellen von Empfehlungen mithilfe statistischer Methoden.
Ich werde mit Python und Open Dataset erklären.
Dies ist ein Artikel über die Implementierung durch Python. In den folgenden Artikeln finden Sie das Konzept der Empfehlungen. Empfehlungs-Tutorial mit Assoziationsanalyse (Konzept)
Es wird gemäß dem Ablauf des Artikels der Concept Edition implementiert.
Es wird eine Gebühr erhoben, aber wir haben eine Ausführungsumgebung für Google Colaboratory unter [hier] vorbereitet (https://note.com/mlpanda/n/n74e0557d6960).
Importieren Sie die erforderlichen Bibliotheken.
#Bibliothek importieren
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
Laden Sie den in diesem Lernprogramm verwendeten Datensatz. Dadurch wird ein Datensatz aus dem Github-Repository geladen.
#Datensatz laden
import urllib.request
from io import StringIO
url = "https://raw.githubusercontent.com/tachiken0210/dataset/master/dataset_cart.csv"
#Funktion zum Lesen von CSV
def read_csv(url):
res = urllib.request.urlopen(url)
res = res.read().decode("utf-8")
df = pd.read_csv(StringIO( res) )
return df
#Lauf
df_cart_ori = read_csv(url)
Überprüfen Sie den Inhalt des diesmal verwendeten Datensatzes.
df_cart_ori.head()
cart_id | goods_id | action | create_at | update_at | last_update | time | |
---|---|---|---|---|---|---|---|
0 | 108750017 | 583266 | UPD | 2013-11-26 03:11:06 | 2013-11-26 03:11:06 | 2013-11-26 03:11:06 | 1385478215 |
1 | 108750017 | 662680 | UPD | 2013-11-26 03:11:06 | 2013-11-26 03:11:06 | 2013-11-26 03:11:06 | 1385478215 |
2 | 108750017 | 664077 | UPD | 2013-11-26 03:11:06 | 2013-11-26 03:11:06 | 2013-11-26 03:11:06 | 1385478215 |
3 | 108199875 | 661648 | ADD | 2013-11-26 03:11:10 | 2013-11-26 03:11:10 | 2013-11-26 03:11:10 | 1385478215 |
4 | 105031004 | 661231 | ADD | 2013-11-26 03:11:41 | 2013-11-26 03:11:41 | 2013-11-26 03:11:41 | 1385478215 |
Dieser Datensatz enthält die Protokolldaten, wenn ein Kunde auf einer bestimmten EC-Site ein Produkt in den Warenkorb legt.
** ・ card_id: Mit dem Kunden verknüpfte Warenkorb-ID (Es ist in Ordnung, sie als Kunden-ID zu betrachten, daher wird sie unten als Kunde bezeichnet.)
**** ・ Waren-ID: Produkt-ID
**** ・ Aktion: Kundenaktion (HINZUFÜGEN: Zum Warenkorb hinzufügen, ENTF: Aus dem Warenkorb löschen usw.)
**** ・ create_at: Zeitpunkt, zu dem das Protokoll erstellt wurde
**** ・ update_at: Das Protokoll wird aktualisiert Zeit (diesmal nicht verwendet)
**** ・ last_update: Zeit, zu der das Protokoll aktualisiert wurde (diesmal nicht verwendet)
**** ・ Zeit: Zeitstempel
**
Darüber hinaus enthalten allgemeine offene Datensätze, einschließlich des diesmal verwendeten Datensatzes, selten bestimmte Namen wie Produktnamen im Datensatz und werden im Wesentlichen durch die Produkt-ID ausgedrückt. Daher ist es schwierig zu wissen, um welche Art von Produkt es sich handelt. Bitte beachten Sie jedoch, dass dies auf den Inhalt der Daten zurückzuführen ist.
Schauen wir uns als nächstes den Inhalt dieser Daten an. Dieser Datensatz enthält Daten für alle Kunden als chronologisches Protokoll. Konzentrieren wir uns also auf nur einen Kunden. Lassen Sie uns zunächst den Kunden mit der größten Anzahl von Protokollen in den Daten extrahieren.
df_cart_ori["cart_id"].value_counts().head()
#Ausgabe
110728794 475
106932411 426
115973611 264
109269739 205
112332751 197
Name: cart_id, dtype: int64
Es gibt 475 Protokolle für 110728794 Benutzer, was am meisten protokolliert zu sein scheint. Lassen Sie uns das Protokoll dieses Kunden extrahieren.
df_cart_ori[df_cart_ori["cart_id"]==110728794].head(10)
cart_id | goods_id | action | create_at | update_at | last_update | time | |
---|---|---|---|---|---|---|---|
32580 | 110728794 | 664457 | ADD | 2013-11-26 22:54:13 | 2013-11-26 22:54:13 | 2013-11-26 22:54:13 | 1385478215 |
32619 | 110728794 | 664885 | ADD | 2013-11-26 22:55:09 | 2013-11-26 22:55:09 | 2013-11-26 22:55:09 | 1385478215 |
33047 | 110728794 | 664937 | ADD | 2013-11-26 22:58:52 | 2013-11-26 22:58:52 | 2013-11-26 22:58:52 | 1385478215 |
33095 | 110728794 | 664701 | ADD | 2013-11-26 23:00:25 | 2013-11-26 23:00:25 | 2013-11-26 23:00:25 | 1385478215 |
34367 | 110728794 | 665050 | ADD | 2013-11-26 23:02:40 | 2013-11-26 23:02:40 | 2013-11-26 23:02:40 | 1385478215 |
34456 | 110728794 | 664989 | ADD | 2013-11-26 23:05:03 | 2013-11-26 23:05:03 | 2013-11-26 23:05:03 | 1385478215 |
34653 | 110728794 | 664995 | ADD | 2013-11-26 23:07:00 | 2013-11-26 23:07:00 | 2013-11-26 23:07:00 | 1385478215 |
34741 | 110728794 | 664961 | ADD | 2013-11-26 23:09:41 | 2013-11-26 23:09:41 | 2013-11-26 23:09:41 | 1385478215 |
296473 | 110728794 | 665412 | DEL | 2013-12-03 17:17:30 | 2013-12-03 17:17:30 | 2013-12-03 07:41:13 | 1386083014 |
296476 | 110728794 | 665480 | DEL | 2013-12-03 17:17:37 | 2013-12-03 17:17:37 | 2013-12-03 07:42:29 | 1386083014 |
Wenn Sie sich diesen Kunden ansehen, können Sie feststellen, dass er den ganzen Tag über kontinuierlich Einkaufswagen zu seinen Produkten hinzufügt.
Wenn man dies für andere Kunden auf die gleiche Weise analysiert, ist es leicht zu erkennen, dass das Produkt y wahrscheinlich in den Warenkorb neben dem im Allgemeinen vorhandenen Produkt x gelegt wird.
Auf diese Weise besteht der Zweck dieser Zeit darin, das Muster zu analysieren, dass ** "Produkt y wahrscheinlich neben einem bestimmten Produkt x" aus diesem Datensatz in den Warenkorb gelegt wird. **
Wir werden die Daten ab dem nächsten tatsächlich verarbeiten, aber die oben genannten in der Ecke Ihres Kopfes behalten.
Von hier aus werden wir die Daten vorverarbeiten. Wenn Sie sich die Spalte "Aktion" ansehen, gibt es zunächst verschiedene Dinge wie HINZUFÜGEN und ENTF. Konzentrieren wir uns zunächst auf das Protokoll ADD (dem Warenkorb hinzugefügt). Dies bedeutet, dass Sie sich nur auf die Produktnachfrage des Kunden konzentrieren.
df = df_cart_ori.copy()
df = df[df["action"]=="ADD"]
df.head()
cart_id | goods_id | action | create_at | update_at | last_update | time | |
---|---|---|---|---|---|---|---|
3 | 108199875 | 661648 | ADD | 2013-11-26 03:11:10 | 2013-11-26 03:11:10 | 2013-11-26 03:11:10 | 1385478215 |
4 | 105031004 | 661231 | ADD | 2013-11-26 03:11:41 | 2013-11-26 03:11:41 | 2013-11-26 03:11:41 | 1385478215 |
6 | 110388732 | 661534 | ADD | 2013-11-26 03:11:55 | 2013-11-26 03:11:55 | 2013-11-26 03:11:55 | 1385478215 |
7 | 110388740 | 662336 | ADD | 2013-11-26 03:11:58 | 2013-11-26 03:11:58 | 2013-11-26 03:11:58 | 1385478215 |
8 | 110293997 | 661648 | ADD | 2013-11-26 03:12:13 | 2013-11-26 03:12:13 | 2013-11-26 03:12:13 | 1385478215 |
Sortieren Sie anschließend den Datensatz so, dass die Reihenfolge, in der die Artikel für jeden Kunden in den Warenkorb gelegt wurden, chronologisch ist.
df = df[["cart_id","goods_id","create_at"]]
df = df.sort_values(["cart_id","create_at"],ascending=[True,True])
df.head()
cart_id | goods_id | create_at | |
---|---|---|---|
548166 | 78496306 | 661142 | 2013-11-15 23:07:02 |
517601 | 79100564 | 662760 | 2013-11-24 18:17:24 |
517404 | 79100564 | 661093 | 2013-11-24 18:25:29 |
23762 | 79100564 | 664856 | 2013-11-26 13:41:47 |
22308 | 79100564 | 562296 | 2013-11-26 13:44:20 |
Der Prozess von hier aus formatiert die Daten so, dass sie in die Assoziationsanalysebibliothek passen.
Für jeden Kunden fügen wir die Artikel im Warenkorb der Reihe nach der Liste hinzu.
df = df[["cart_id","goods_id"]]
df["goods_id"] = df["goods_id"].astype(int).astype(str)
df = df.groupby(["cart_id"])["goods_id"].apply(lambda x:list(x)).reset_index()
df.head()
| cart_id | goods_id |
|---:|----------:|:---------------------------------------------------------------------------------------------------------------------------------------------|
| 0 | 78496306 | ['661142'] |
| 1 | 79100564 | ['662760', '661093', '664856', '562296', '663364', '664963', '664475', '583266'] |
| 2 | 79455669 | ['663801', '664136', '664937', '663932', '538673', '663902', '667859'] |
| 3 | 81390353 | ['663132', '661725', '664236', '663331', '659679', '663847', '662340', '662292', '664099', '664165', '663581', '665426', '663899', '663405'] |
| 4 | 81932021 | ['662282', '664218']
Als nächstes überprüfen wir den Inhalt des obigen Datenrahmens.
Beachten Sie den Kunden in der zweiten Zeile (79100564).
Zunächst wird nach dem ersten Produkt 663801 664136 in den Warenkorb gelegt. Das heißt, X = "663801" und Y = "664136". <
Nach 664136 wird 664937 in den Warenkorb gelegt. Für diese ist X = "664136" und Y = "664937".
Auf diese Weise ist es durch Anordnen dieses XY-Paares für jeden Kunden möglich, eine Assoziationsanalyse durchzuführen.
Formatieren wir nun die Daten so, dass dieses XY gepaart ist.
def get_combination(l):
length = len(l)
list_output = []
list_pair = []
for i in range(length-1):
if l[i]==l[i+1]:
pass
else:
list_pair =[l[i],l[i+1]]
list_output.append(list_pair)
return list_output
df["comb_goods_id"] = df["goods_id"].apply(lambda x:get_combination(x))
#Erstellen Sie eine Liste der Zuordnungseingaben
dataset= []
for i,contents in enumerate(df["comb_goods_id"].values):
for c in contents:
dataset.append(c)
print("Die Anzahl der XY-Paare beträgt",len(dataset))
print("Inhalt des XY-Paares",dataset[:5])
#Ausgabe
Die Anzahl der XY-Paare beträgt 141956
Inhalt des XY-Paares[['662760', '661093'], ['661093', '664856'], ['664856', '562296'], ['562296', '663364'], ['663364', '664963']]
Das Obige wird als Eingabe für die Assoziationsanalyse verwendet. Ich habe eine Methode erstellt, die eine Assoziationsanalyse als Assoziationsmethode durchführt, daher werde ich diese verwenden.
#Vereinsbibliothek
def association(dataset):
df = pd.DataFrame(dataset,columns=["x","y"])
num_dataset = df.shape[0]
df["sum_count_xy"]=1
print("calculating support....")
df_a_support = (df.groupby("x").sum()/num_dataset).rename(columns={"sum_count_xy":"support_x"})
df_b_support = (df.groupby("y").sum()/num_dataset).rename(columns={"sum_count_xy":"support_y"})
df = df.groupby(["x","y"]).sum()
df["support_xy"]=df["sum_count_xy"]/num_dataset
df = df.reset_index()
df = pd.merge(df,df_a_support,on="x")
df = pd.merge(df,df_b_support,on="y")
print("calculating confidence....")
df_temp = df.groupby("x").sum()[["sum_count_xy"]].rename(columns={"sum_count_xy":"sum_count_x"})
df = pd.merge(df,df_temp,on="x")
df_temp = df.groupby("y").sum()[["sum_count_xy"]].rename(columns={"sum_count_xy":"sum_count_y"})
df = pd.merge(df,df_temp,on="y")
df["confidence"]=df["sum_count_xy"]/df["sum_count_x"]
print("calculating lift....")
df["lift"]=df["confidence"]/df["support_y"]
df["sum_count"] = num_dataset
df_output = df
return df_output
#Wenden Sie den Datensatz auf die Assoziationsanalyse an
df_output = association(dataset)
df_output.head()
x | y | sum_count_xy | support_xy | support_x | support_y | sum_count_x | sum_count_y | confidence | lift | sum_count | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 485836 | 662615 | 1 | 7.04444e-06 | 7.04444e-06 | 0.000147933 | 1 | 21 | 1 | 6759.81 | 141956 |
1 | 549376 | 662615 | 1 | 7.04444e-06 | 2.11333e-05 | 0.000147933 | 3 | 21 | 0.333333 | 2253.27 | 141956 |
2 | 654700 | 662615 | 1 | 7.04444e-06 | 0.000464933 | 0.000147933 | 66 | 21 | 0.0151515 | 102.421 | 141956 |
3 | 661475 | 662615 | 1 | 7.04444e-06 | 0.000965088 | 0.000147933 | 137 | 21 | 0.00729927 | 49.3417 | 141956 |
4 | 661558 | 662615 | 1 | 7.04444e-06 | 0.000408577 | 0.000147933 | 58 | 21 | 0.0172414 | 116.548 | 141956 |
Ich habe das Ergebnis.
Der Inhalt jeder Spalte ist wie folgt
** ・ x: Bedingungsteil X
・ y: Schlussfolgerungsteil Y
・ sum_count_xy: Anzahl der für XY geltenden Daten
・ support_xy: XY-Unterstützung
・ support_x: X-Unterstützung
> ・ Support_y: Y-Unterstützung
・ sum_count_x: Anzahl der für X geltenden Daten
・ sum_count_y: Anzahl der für Y geltenden Daten
・ Vertrauen: Vertrauen
・ Aufzug: Aufzug
**
Nun, die Ausführung des Vereins ist beendet, aber es gibt eine Einschränkung.
** Grundsätzlich scheint ein hoher Hubwert von hoher Relevanz zu sein. Wenn jedoch die Anzahl der Daten gering ist, besteht der Verdacht, dass dies versehentlich passiert ist. **
Nehmen Sie zum Beispiel die oberste Zeile. Dies ist der Teil von x = "485836", y = "662615".
Dies hat einen sehr hohen Hubwert von 6760, aber dies ist nur einmal passiert (= support_xy). Unter der Annahme, dass die Anzahl der Daten ausreicht, ist es sehr wahrscheinlich, dass dies versehentlich passiert ist.
Wie leiten Sie den support_xy-Schwellenwert ab, der bestimmt, ob er versehentlich ist oder nicht?
.. .. .. In Wirklichkeit ist es schwierig, diese Schwelle abzuleiten. (Es gibt keine richtige Antwort)
Hier überprüfen wir das Histogramm von support_xy einmal.
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.hist(df_output["sum_count_xy"], bins=100)
ax.set_title('')
ax.set_xlabel('xy')
ax.set_ylabel('freq')
#Es ist schwer zu erkennen, also begrenzen Sie den Bereich der y-Achse
ax.set_ylim(0,500)
fig.show()
Sie können sehen, dass bei den meisten Daten die x-Achse support_xy nahe 0 konzentriert ist.
In diesem Lernprogramm werden alle Daten in der Nähe von 0 als Zufall betrachtet und gelöscht.
Beim Einstellen des Schwellenwerts wird der Bruch verwendet und der Schwellenwert so eingestellt, dass die Daten der unteren 98% als Zufall angesehen werden können.
df = df_output.copy()
df = df[df["support_xy"]>=df["support_xy"].quantile(0.98)]
df.head()
x | y | sum_count_xy | support_xy | support_x | support_y | sum_count_x | sum_count_y | confidence | lift | sum_count | |
---|---|---|---|---|---|---|---|---|---|---|---|
58 | 662193 | 667129 | 8 | 5.63555e-05 | 0.0036138 | 0.00281073 | 513 | 399 | 0.0155945 | 5.54822 | 141956 |
59 | 665672 | 667129 | 12 | 8.45332e-05 | 0.00395193 | 0.00281073 | 561 | 399 | 0.0213904 | 7.61026 | 141956 |
60 | 666435 | 667129 | 30 | 0.000211333 | 0.0082279 | 0.00281073 | 1168 | 399 | 0.0256849 | 9.13817 | 141956 |
62 | 666590 | 667129 | 7 | 4.93111e-05 | 0.00421257 | 0.00281073 | 598 | 399 | 0.0117057 | 4.16464 | 141956 |
63 | 666856 | 667129 | 8 | 5.63555e-05 | 0.00390966 | 0.00281073 | 555 | 399 | 0.0144144 | 5.12835 | 141956 |
Dadurch wurden mir die Daten für das xy-Paar gespeichert, von denen ich dachte, dass sie zufällig passiert sind.
Dann der letzte Prozess, bei dem nur y übrig bleibt, was für x relevant ist. Wie bereits erläutert, bedeutet dies, dass nur noch xy-Paare mit hohen Auftriebswerten übrig bleiben müssen.
Hier lassen wir nur Paare mit einem Auftrieb von 2,0 oder höher.
** Übrigens ist es ein Bild der Bedeutung von Auftrieb (Hubwert), aber es ist ein Wert, der zeigt, wie einfach es ist, y Produkte in den Warenkorb zu legen, wenn x Produkte in den Warenkorb gelegt werden, verglichen mit anderen Produkten. **
Wenn beispielsweise im Inhalt des obigen Datenrahmens das Produkt "662193" (x) zum Warenkorb hinzugefügt wird, ist das Produkt "667129" (y) ** 5,5-mal einfacher zum Warenkorb hinzuzufügen * * Es bedeutet.
df = df[df["lift"]>=2.0]
df_recommendation = df.copy()
df_recommendation.head()
x | y | sum_count_xy | support_xy | support_x | support_y | sum_count_x | sum_count_y | confidence | lift | sum_count | |
---|---|---|---|---|---|---|---|---|---|---|---|
58 | 662193 | 667129 | 8 | 5.63555e-05 | 0.0036138 | 0.00281073 | 513 | 399 | 0.0155945 | 5.54822 | 141956 |
59 | 665672 | 667129 | 12 | 8.45332e-05 | 0.00395193 | 0.00281073 | 561 | 399 | 0.0213904 | 7.61026 | 141956 |
60 | 666435 | 667129 | 30 | 0.000211333 | 0.0082279 | 0.00281073 | 1168 | 399 | 0.0256849 | 9.13817 | 141956 |
62 | 666590 | 667129 | 7 | 4.93111e-05 | 0.00421257 | 0.00281073 | 598 | 399 | 0.0117057 | 4.16464 | 141956 |
63 | 666856 | 667129 | 8 | 5.63555e-05 | 0.00390966 | 0.00281073 | 555 | 399 | 0.0144144 | 5.12835 | 141956 |
Damit ist die Generierung grundlegender Empfehlungsdaten abgeschlossen.
Die spezifische Verwendung ist so einfach wie die Bewerbung des Produkts "667129" bei der Person, die beispielsweise das Produkt "662193" in den Warenkorb gelegt hat.
Tatsächlich werden die Daten dieser Empfehlung in der Datenbank gespeichert, so dass y ausgegeben wird, wenn x eingegeben wird.
Nachdem ich die Empfehlungsdaten erstellt habe, zeige ich Ihnen die Probleme mit dieser Empfehlung (ohne sie auszublenden).
Das heißt ** es ist nicht möglich, alle Eingabeprodukte (x) anzuvisieren. **
Lassen Sie uns dies überprüfen.
Lassen Sie uns zunächst überprüfen, wie viele Arten von x in den ursprünglichen Transaktionsdaten enthalten sind.
#x ist die Ware der Originaldaten_Da es sich um eine ID handelt, wird die eindeutige Anzahl aggregiert.
df_cart_ori["goods_id"].nunique()
#Ausgabe
8398
Ursprünglich gibt es 8398 Arten von x.
Mit anderen Worten, wir sollten in der Lage sein, hochrelevante Produkte (y) für diese 8398 Arten von Eingaben (x) zu empfehlen.
Überprüfen wir nun, wie viel Eingabe (x) der vorherigen Ausgabe entspricht.
#Aggregieren Sie die eindeutige Anzahl von x im Empfehlungsergebnis.
df_recommendation["x"].nunique()
#Ausgabe
463
Die Eingabe (x), die von den obigen ** Empfehlungsdaten unterstützt wird, unterstützt nur 463 Typen. ** (463/8392, also ungefähr 5%)
Dies ist eine Schwäche der Empfehlungen zum Benutzerverhalten.
Vielleicht muss dies in der Realität angegangen werden.
Folgendes kann als Gegenmaßnahme angesehen werden.
Für Empfehlungen, die Assoziationen verwenden, ist es relativ einfach, Empfehlungsdaten zu erstellen, wenn Transaktionsdaten akkumuliert werden. Wenn Sie versuchen, eine Empfehlungs-Engine für Ihre eigentliche Arbeit zu erstellen, probieren Sie es bitte aus!
Recommended Posts