Hallo, ich bin Ingenieur für maschinelles Lernen. Das ist Kawamoto. Es war zu kalt und ich erkältete mich. Heute werde ich darüber schreiben, wie eine Vorverarbeitung durchgeführt und gleichzeitig der Speicherverbrauch für Protokolldaten reduziert wird, bei denen Zeitreiheninformationen berücksichtigt werden müssen.
Angenommen, Sie haben für jeden Benutzer ein Dataset mit solchen Verhaltensprotokollen
userid itemid categoryid timestamp
0 0 3 1 2019-01-04
1 0 4 1 2019-01-08
2 0 4 1 2019-01-19
3 0 5 1 2019-01-02
4 0 7 2 2019-01-17
5 0 8 2 2019-01-07
6 1 0 0 2019-01-06
7 1 1 0 2019-01-14
8 1 2 0 2019-01-20
9 1 6 2 2019-01-01
10 1 7 2 2019-01-12
11 1 8 2 2019-01-18
12 2 3 1 2019-01-16
13 2 4 1 2019-01-15
14 2 5 1 2019-01-10
15 2 5 1 2019-01-13
16 2 6 2 2019-01-03
17 2 7 2 2019-01-05
18 2 8 2 2019-01-11
19 2 8 2 2019-01-21
20 2 9 3 2019-01-09
Seriendaten variabler Länge, sortiert nach Zeit für jeden Benutzer, wie unten gezeigt,
Itemid (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat
[[5, 3, 8, 4, 7, 4],
[6, 0, 7, 1, 8, 2],
[6, 7, 9, 5, 8, 5, 4, 3, 8]]
Kategorie-ID (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat
[[1, 1, 2, 1, 2, 1],
[2, 0, 2, 0, 2, 0],
[2, 2, 3, 1, 2, 1, 1, 1, 2]]
Ich möchte eine kategoriale Variable erstellen, die die folgenden Zeitreihen berücksichtigt. Hier wird angenommen, dass der neueste Datensatz für itemid und categoryid verwendet wird.
Die neueste Artikel-ID, die jeder Benutzer kontaktiert hat
[4, 2, 8]
Die neueste Kategorie-ID, die jeder Benutzer kontaktiert hat
[1, 0, 2]
Wenn Sie beispielsweise für Seriendaten eine solche Liste erstellen können, kann Keras (funktionale API) durch Auffüllen wie folgt als sequentielle Daten eingegeben werden.
import tensorflow as tf
inputs = []
inputs.append(tf.keras.preprocessing.sequence.pad_sequences(
df['itemid'].values.tolist(), padding='post', truncating='post', maxlen=10))
inputs.append(tf.keras.preprocessing.sequence.pad_sequences(
df['categoryid'].values.tolist(), padding='post', truncating='post', maxlen=10))
In Bezug auf Seriendaten in Pandas, wenn Sie wie folgt schreiben:
#Benutzeridentifikation,In chronologischer Reihenfolge sortieren
df = df.sort_values(by=['userid','timestamp'])
#Gruppieren nach als Liste für jeden Benutzer
df = df.groupby('userid').agg(list).reset_index(drop=False)
print('Itemid (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat')
pprint.pprint(df['itemid'].values.tolist())
print('Kategorie-ID (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat')
pprint.pprint(df['categoryid'].values.tolist()
Sie erhalten das obige Ergebnis.
Itemid (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat
[[5, 3, 8, 4, 7, 4],
[6, 0, 7, 1, 8, 2],
[6, 7, 9, 5, 8, 5, 4, 3, 8]]
Kategorie-ID (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat
[[1, 1, 2, 1, 2, 1],
[2, 0, 2, 0, 2, 0],
[2, 2, 3, 1, 2, 1, 1, 1, 2]]
Auch in Bezug auf Kategoriedaten,
#Gruppieren Sie nach, um für jeden Benutzer die neueste zu erhalten
df_cate = df.loc[df.groupby('userid')['timestamp'].idxmax()]
print(df_cate)
print('Die neueste Artikel-ID, die jeder Benutzer kontaktiert hat')
pprint.pprint(df_cate['itemid'].values.tolist())
print('Die neueste Kategorie-ID, die jeder Benutzer kontaktiert hat')
pprint.pprint(df_cate['categoryid'].values.tolist())
Sie können das obige Ergebnis erhalten, indem Sie wie schreiben.
Die neueste Artikel-ID, die jeder Benutzer kontaktiert hat
[4, 2, 8]
Die neueste Kategorie-ID, die jeder Benutzer kontaktiert hat
[1, 0, 2]
Wenn der obige Datensatz groß wird, verursacht Pandas einen Speicherfehler und eine Stapelkonvertierung ist nicht möglich. Wenn das Dataset selbst nicht in den Speicher passt, kann es auch nicht damit umgehen. Wenn Datensätze separat verarbeitet werden, müssen die Zeitreiheninformationen von Datensätzen beibehalten werden, die nicht in jedem Datensatz enthalten sind.
Aus dem obigen Hintergrund
Wir brauchten eine Methode, um Seriendaten in chronologischer Reihenfolge wie diese zu erstellen.
Im Folgenden werde ich über die spezifische Methode schreiben.
Erstellen Sie hier eine Liste mit Zeitreiheninformationen, die darauf basiert
--Series-Funktionen unter Berücksichtigung von Zeitreihen --Category Feature Quantity unter Berücksichtigung von Zeitreihen
Ich werde darüber schreiben, wie man erstellt.
Danach erklären wir, was mit dem geteilten Datensatz zu tun ist.
Erstellen Sie zunächst eine Liste, aus der Sie Vorgänge in chronologischer Reihenfolge ausführen können. Wenn der Wert, den Sie als Seriendaten in chronologischer Reihenfolge und für jeden Benutzer haben möchten, "Element" ist und die Zeitreiheninformationen dieses Werts "Zeitstempel" sind,
[[[item,timestamp],[item,timestamp]...[item,timestamp]],
[[item,timestamp],[item,timestamp]...[item,timestamp]],
...
[[item,timestamp],[item,timestamp]...[item,timestamp]]]
Erstellen Sie eine dreidimensionale Liste mit dem Namen. Hier verwendet die erste Dimension die Benutzer-ID als Index.
Der Prozess ist wie folgt.
def create_list(df, user_index_col, sort_col, target_col, user_num):
"""
:param user_index_col:Benutzer-ID-Spalte
:param sort_col:Spalte mit dem für die Sortierung verwendeten Wert
:param target_col:Spalte, die Sie sortieren möchten
:param user_num:Anzahl der Benutzer (vom Encoder usw. erhalten)
"""
inputs = [[] for _ in range(user_num)]
for _, user_index, sort_value, target_value in df[[user_index_col, sort_col, target_col]].itertuples():
inputs[user_index].append([target_value, sort_value])
return inputs
Wenn Sie dies für den ersten Datensatz tun, der herauskommt,
itemid_inputs = create_list(df, user_index_col='userid', sort_col='timestamp', target_col='itemid', user_num=3)
categoryid_inputs = create_list(df, user_index_col='userid', sort_col='timestamp', target_col='categoryid', user_num=3)
print('itemid')
pprint.pprint(itemid_inputs)
print('categoryid')
pprint.pprint(categoryid_inputs)
Eine Liste wie die folgende wird erstellt.
itemid
[[[3, Timestamp('2019-01-04 00:00:00')],
[4, Timestamp('2019-01-08 00:00:00')],
[4, Timestamp('2019-01-19 00:00:00')],
[5, Timestamp('2019-01-02 00:00:00')],
[7, Timestamp('2019-01-17 00:00:00')],
[8, Timestamp('2019-01-07 00:00:00')]],
[[0, Timestamp('2019-01-06 00:00:00')],
[1, Timestamp('2019-01-14 00:00:00')],
[2, Timestamp('2019-01-20 00:00:00')],
[6, Timestamp('2019-01-01 00:00:00')],
[7, Timestamp('2019-01-12 00:00:00')],
[8, Timestamp('2019-01-18 00:00:00')]],
[[3, Timestamp('2019-01-16 00:00:00')],
[4, Timestamp('2019-01-15 00:00:00')],
[5, Timestamp('2019-01-10 00:00:00')],
[5, Timestamp('2019-01-13 00:00:00')],
[6, Timestamp('2019-01-03 00:00:00')],
[7, Timestamp('2019-01-05 00:00:00')],
[8, Timestamp('2019-01-11 00:00:00')],
[8, Timestamp('2019-01-21 00:00:00')],
[9, Timestamp('2019-01-09 00:00:00')]]]
categoryid
[[[1, Timestamp('2019-01-04 00:00:00')],
[1, Timestamp('2019-01-08 00:00:00')],
[1, Timestamp('2019-01-19 00:00:00')],
[1, Timestamp('2019-01-02 00:00:00')],
[2, Timestamp('2019-01-17 00:00:00')],
[2, Timestamp('2019-01-07 00:00:00')]],
[[0, Timestamp('2019-01-06 00:00:00')],
[0, Timestamp('2019-01-14 00:00:00')],
[0, Timestamp('2019-01-20 00:00:00')],
[2, Timestamp('2019-01-01 00:00:00')],
[2, Timestamp('2019-01-12 00:00:00')],
[2, Timestamp('2019-01-18 00:00:00')]],
[[1, Timestamp('2019-01-16 00:00:00')],
[1, Timestamp('2019-01-15 00:00:00')],
[1, Timestamp('2019-01-10 00:00:00')],
[1, Timestamp('2019-01-13 00:00:00')],
[2, Timestamp('2019-01-03 00:00:00')],
[2, Timestamp('2019-01-05 00:00:00')],
[2, Timestamp('2019-01-11 00:00:00')],
[2, Timestamp('2019-01-21 00:00:00')],
[3, Timestamp('2019-01-09 00:00:00')]]]
Fügen Sie als Nächstes den Vorgang zum Sortieren der erstellten Liste in chronologischer Reihenfolge hinzu.
def sort_list(inputs, is_descending):
"""
:param is_descending:Ob in absteigender Reihenfolge
"""
return [sorted(i_input, key=lambda i: i[1], reverse=is_descending) for i_input in inputs]
Wenn dieser Vorgang ausgeführt wird,
itemid_inputs = sort_list(itemid_inputs, is_descending=False)
categoryid_inputs = sort_list(categoryid_inputs, is_descending=False)
print('itemid')
pprint.pprint(itemid_inputs)
print('categoryid')
pprint.pprint(categoryid_inputs)
Eine in chronologischer Reihenfolge sortierte Liste wird wie unten gezeigt erstellt.
itemid
[[[5, Timestamp('2019-01-02 00:00:00')],
[3, Timestamp('2019-01-04 00:00:00')],
[8, Timestamp('2019-01-07 00:00:00')],
[4, Timestamp('2019-01-08 00:00:00')],
[7, Timestamp('2019-01-17 00:00:00')],
[4, Timestamp('2019-01-19 00:00:00')]],
[[6, Timestamp('2019-01-01 00:00:00')],
[0, Timestamp('2019-01-06 00:00:00')],
[7, Timestamp('2019-01-12 00:00:00')],
[1, Timestamp('2019-01-14 00:00:00')],
[8, Timestamp('2019-01-18 00:00:00')],
[2, Timestamp('2019-01-20 00:00:00')]],
[[6, Timestamp('2019-01-03 00:00:00')],
[7, Timestamp('2019-01-05 00:00:00')],
[9, Timestamp('2019-01-09 00:00:00')],
[5, Timestamp('2019-01-10 00:00:00')],
[8, Timestamp('2019-01-11 00:00:00')],
[5, Timestamp('2019-01-13 00:00:00')],
[4, Timestamp('2019-01-15 00:00:00')],
[3, Timestamp('2019-01-16 00:00:00')],
[8, Timestamp('2019-01-21 00:00:00')]]]
categoryid
[[[1, Timestamp('2019-01-02 00:00:00')],
[1, Timestamp('2019-01-04 00:00:00')],
[2, Timestamp('2019-01-07 00:00:00')],
[1, Timestamp('2019-01-08 00:00:00')],
[2, Timestamp('2019-01-17 00:00:00')],
[1, Timestamp('2019-01-19 00:00:00')]],
[[2, Timestamp('2019-01-01 00:00:00')],
[0, Timestamp('2019-01-06 00:00:00')],
[2, Timestamp('2019-01-12 00:00:00')],
[0, Timestamp('2019-01-14 00:00:00')],
[2, Timestamp('2019-01-18 00:00:00')],
[0, Timestamp('2019-01-20 00:00:00')]],
[[2, Timestamp('2019-01-03 00:00:00')],
[2, Timestamp('2019-01-05 00:00:00')],
[3, Timestamp('2019-01-09 00:00:00')],
[1, Timestamp('2019-01-10 00:00:00')],
[2, Timestamp('2019-01-11 00:00:00')],
[1, Timestamp('2019-01-13 00:00:00')],
[1, Timestamp('2019-01-15 00:00:00')],
[1, Timestamp('2019-01-16 00:00:00')],
[2, Timestamp('2019-01-21 00:00:00')]]]
Erstens ist der Prozess zum Erstellen von Serienmerkmalen variabler Länge (sequentielle Merkmale) aus der oben erstellten Liste wie folgt.
def create_sequential(inputs):
#Löschen Sie die Liste der Zeitstempel in der Liste
return [[i[0] for i in i_input] for i_input in inputs]
Wenn Sie dies tun,
print('Itemid (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat')
pprint.pprint(create_sequential(itemid_inputs))
print('Kategorie-ID (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat')
pprint.pprint(create_sequential(categoryid_inputs))
Sie können das gewünschte Ergebnis erzielen.
Itemid (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat
[[5, 3, 8, 4, 7, 4],
[6, 0, 7, 1, 8, 2],
[6, 7, 9, 5, 8, 5, 4, 3, 8]]
Kategorie-ID (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat
[[1, 1, 2, 1, 2, 1],
[2, 0, 2, 0, 2, 0],
[2, 2, 3, 1, 2, 1, 1, 1, 2]]
Als Nächstes wird wie folgt vorgegangen, um den neuesten Datensatz jedes Benutzers als kategoriale Variable aus der oben erstellten Liste abzurufen.
def create_category(inputs, n=-1):
"""
:param n:Welche Nummer soll in der chronologischen Liste aufbewahrt werden?
"""
#Löschen Sie die Liste der Zeitstempel in der Liste
#Belassen Sie nur die Daten der n-ten Reihe in chronologischer Reihenfolge
return [[i[0] for i in i_input][n] for i_input in inputs]
Wenn Sie dies tun,
print('Die neueste Artikel-ID, die jeder Benutzer kontaktiert hat')
pprint.pprint(create_category(itemid_inputs, -1))
print('Die neueste Kategorie-ID, die jeder Benutzer kontaktiert hat')
pprint.pprint(create_category(categoryid_inputs, -1))
Sie können das gesuchte Ergebnis wie folgt erhalten:
Die neueste Artikel-ID, die jeder Benutzer kontaktiert hat
[4, 2, 8]
Die neueste Kategorie-ID, die jeder Benutzer kontaktiert hat
[1, 0, 2]
Hier werden die für die obige Erklärung getrennten Funktionen wie folgt integriert.
def create_features(
df, user_index_col, sort_col, target_col, user_num, is_descending, is_sequence, n=-1):
"""
:param user_index_col:Benutzer-ID-Spalte
:param sort_col:Spalte mit dem für die Sortierung verwendeten Wert
:param target_col:Spalte, die Sie sortieren möchten
:param user_num:Anzahl der Benutzer (vom Encoder usw. erhalten)
:param is_descending:Ob in absteigender Reihenfolge
:param is_sequence:Ob es sequentiell ist
:param n:Welche Nummer soll in der chronologischen Liste bleiben (nur Kategorie)
"""
#Liste erstellen
inputs = [[] for _ in range(user_num)]
for _, user_index, sort_value, target_value in df[[user_index_col, sort_col, target_col]].itertuples():
inputs[user_index].append([target_value, sort_value])
#Sortierliste
inputs = [sorted(i_input, key=lambda i: i[1], reverse=is_descending) for i_input in inputs]
if is_sequence:
return [[i[0] for i in i_input] for i_input in inputs]
else:
return [[i[0] for i in i_input][n] for i_input in inputs]
Hier wollte ich am meisten schreiben, wenn Sie eine Liste mit Zeitreiheninformationen wie oben beschrieben erstellen, wenn Sie nicht alle Daten im Speicher ablegen können, den Datensatz teilen und vor jeder Teilungseinheit lesen Es kann auch zur Verarbeitung verwendet werden.
Angenommen, der erste DataFrame ist in drei Teile unterteilt und wie unten gezeigt im Wörterbuch gespeichert. (Ich glaube nicht, dass es tatsächlich der Fall ist, aber als Beispiel ...)
{'df1': userid itemid categoryid timestamp
0 0 3 1 2019-01-04
1 0 4 1 2019-01-08
2 0 4 1 2019-01-19
3 0 5 1 2019-01-02
4 0 7 2 2019-01-17
5 0 8 2 2019-01-07
6 1 0 0 2019-01-06,
'df2': userid itemid categoryid timestamp
7 1 1 0 2019-01-14
8 1 2 0 2019-01-20
9 1 6 2 2019-01-01
10 1 7 2 2019-01-12
11 1 8 2 2019-01-18
12 2 3 1 2019-01-16
13 2 4 1 2019-01-15,
'df3': userid itemid categoryid timestamp
14 2 5 1 2019-01-10
15 2 5 1 2019-01-13
16 2 6 2 2019-01-03
17 2 7 2 2019-01-05
18 2 8 2 2019-01-11
19 2 8 2 2019-01-21
20 2 9 3 2019-01-09}
Da Zeitreiheninformationen in der Liste gespeichert sind, können sie verarbeitet werden, indem beispielsweise die Funktion wie folgt geändert wird.
def create_features_by_datasets(
df_dict, user_index_col, sort_col, target_col, user_num, is_descending, is_sequence, n=-1):
inputs = [[] for _ in range(user_num)]
#Verarbeitung für jede Teilungseinheit des Datensatzes
for df in df_dict.values():
for _, user_index, sort_value, target_value in df[[user_index_col, sort_col, target_col]].itertuples():
inputs[user_index].append([target_value, sort_value])
inputs = [sorted(i_input, key=lambda i: i[1], reverse=is_descending) for i_input in inputs]
if is_sequence:
return [[i[0] for i in i_input] for i_input in inputs]
else:
return [[i[0] for i in i_input][n] for i_input in inputs]
Wenn Sie Folgendes tun,
print('Itemid (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat')
pprint.pprint(create_features_by_datasets(df_dict, user_index_col='userid', sort_col='timestamp', target_col='itemid', user_num=3, is_descending=False, is_sequence=True))
print('Die neueste Artikel-ID, die jeder Benutzer kontaktiert hat')
pprint.pprint(create_features_by_datasets(df_dict, user_index_col='userid', sort_col='timestamp', target_col='itemid', user_num=3, is_descending=False, is_sequence=False))
Das Ergebnis ist das gleiche wie oben.
Itemid (in chronologischer Reihenfolge), die jeder Benutzer kontaktiert hat
[[5, 3, 8, 4, 7, 4],
[6, 0, 7, 1, 8, 2],
[6, 7, 9, 5, 8, 5, 4, 3, 8]]
Die neueste Artikel-ID, die jeder Benutzer kontaktiert hat
[4, 2, 8]
Außerdem haben wir diesmal die Sortierkriterien auf Zeitreiheninformationen eingegrenzt, aber es ist auch möglich, nach anderen Spalten oder in absteigender Reihenfolge zu sortieren. Durch Ändern der für die obige Verarbeitung übergebenen Variablen sind aufsteigende / absteigende Reihenfolge und Sortierung durch Angabe von Spalten möglich.
Zum Beispiel im folgenden Datensatz
userid itemid categoryid score
0 0 3 1 0.730968
1 0 3 1 0.889117
2 0 3 1 0.714828
3 0 4 1 0.430737
4 0 5 1 0.734746
5 0 7 2 0.412346
6 1 0 0 0.660430
7 1 3 1 0.095672
8 1 4 1 0.985072
9 1 5 1 0.629274
10 1 6 2 0.617733
11 1 7 2 0.636219
12 1 8 2 0.246769
13 1 8 2 0.020140
14 2 0 0 0.812525
15 2 1 0 0.671100
16 2 2 0 0.174011
17 2 2 0 0.164321
18 2 3 1 0.783329
19 2 4 1 0.068837
20 2 5 1 0.265281
Selbst wenn es eine Spalte namens Score gibt, ist der Vorgang wie folgt, wenn Sie Seriendaten und Kategoriedaten in absteigender Reihenfolge erstellen möchten.
print('Ergebnisreihenfolge (itemid)')
pprint.pprint(create_features(df, user_index_col='userid', sort_col='score', target_col='itemid', user_num=3, is_descending=True, is_sequence=True))
print('Maximale Punktzahl (itemid)')
pprint.pprint(create_features(df, user_index_col='userid', sort_col='score', target_col='itemid', user_num=3, is_descending=True, is_sequence=False, n=0))
Das Ergebnis ist wie folgt.
Ergebnisreihenfolge (itemid)
[[3, 5, 3, 3, 4, 7],
[4, 0, 7, 5, 6, 8, 3, 8],
[0, 3, 1, 5, 2, 2, 4]]
Maximale Punktzahl (itemid)
[3, 4, 0]
Dieses Mal schrieb ich darüber, wie Protokolldaten speichersparend in Serien- und Kategoriefeatures konvertiert werden können, während Zeitreiheninformationen berücksichtigt werden. Wenn es einen besseren Weg gibt, lass es mich bitte in den Kommentaren wissen. Vielen Dank.
Recommended Posts