Kapitel 4. Erfassen eines ersten Datensatzes

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Sobald du einen Plan zur Lösung deiner Produktanforderungen hast und einen ersten Prototyp gebaut hast, um zu überprüfen, ob dein vorgeschlagener Arbeitsablauf und dein Modell solide sind, ist es an der Zeit, tiefer in deinen Datensatz einzutauchen. Was wir finden, nutzen wir, um unsere Modellierungsentscheidungen zu treffen. Oftmals führt ein gutes Verständnis deiner Daten zu den größten Leistungsverbesserungen.

In diesem Kapitel werden wir uns zunächst ansehen, wie man die Qualität eines Datensatzes effizient beurteilen kann. Dann befassen wir uns damit, wie du deine Daten vektorisieren kannst und wie du diese vektorisierte Darstellung nutzen kannst, um einen Datensatz effizienter zu beschriften und zu untersuchen. Zum Schluss gehen wir darauf ein, wie diese Prüfung die Strategien zur Feature-Generierung leiten sollte.

Beginnen wir damit, einen Datensatz zu entdecken und seine Qualität zu beurteilen.

Iterieren von Datensätzen

Der schnellste Weg, ein ML-Produkt zu entwickeln, besteht darin, Modelle schnell zu erstellen, zu bewerten und zu iterieren. Die Datensätze selbst sind ein wesentlicher Bestandteil des Erfolgs der Modelle. Deshalb sollte das Sammeln, Aufbereiten und Beschriften von Daten als iterativer Prozess betrachtet werden, genau wie die Modellierung. Beginne mit einem einfachen Datensatz, den du sofort erfassen kannst, und sei offen dafür, ihn auf der Grundlage deiner Erkenntnisse zu verbessern.

Dieser iterative Umgang mit Daten kann zunächst verwirrend erscheinen. In der ML-Forschung wird die Leistung oft anhand von Standarddatensätzen gemessen, die von der Community als Benchmarks verwendet werden und daher unveränderlich sind. In der traditionellen Softwareentwicklung schreiben wir deterministische Regeln für unsere Programme, also behandeln wir Daten als etwas, das wir empfangen, verarbeiten und speichern.

ML-Engineering kombiniert Technik und ML, um Produkte zu entwickeln. Unser Datensatz ist also nur ein weiteres Werkzeug, mit dem wir Produkte entwickeln können. Im ML-Engineering machen die Auswahl eines Anfangsdatensatzes, seine regelmäßige Aktualisierung und Erweiterung oft den größten Teil der Arbeit aus. Dieser Unterschied zwischen den Arbeitsabläufen in der Forschung und in der Industrie ist in Abbildung 4-1 dargestellt.

Datasets are fixed in research, but part of a product in industry
Abbildung 4-1. Datensätze sind in der Forschung fix, aber Teil des Produkts in der Industrie

Daten als Teil deines Produkts zu betrachten, das du wiederholen, verändern und verbessern kannst (und solltest), ist für Neulinge in der Branche oft ein großer Paradigmenwechsel. Wenn du dich aber erst einmal daran gewöhnt hast, werden Daten zu deiner besten Inspirationsquelle für die Entwicklung neuer Modelle und zur ersten Anlaufstelle für Antworten, wenn etwas schief läuft.

Datenwissenschaft betreiben

Ich habe erlebt, dass der Prozess der Datenbeschaffung das größte Hindernis bei der Entwicklung von ML-Produkten ist. Das liegt zum Teil daran, dass es relativ wenig Ausbildung zu diesem Thema gibt (die meisten Online-Kurse liefern den Datensatz und konzentrieren sich auf die Modelle), was dazu führt, dass viele Praktiker diesen Teil der Arbeit fürchten.

Es ist leicht, die Arbeit mit Daten als lästige Pflicht zu betrachten, bevor man mit lustigen Modellen spielt, aber Modelle dienen nur dazu, Trends und Muster aus vorhandenen Daten zu extrahieren. Sicherzustellen, dass die von uns verwendeten Daten Muster aufweisen, die für ein Modell aussagekräftig genug sind (und zu prüfen, ob sie eindeutige Verzerrungen enthalten), ist daher ein grundlegender Teil der Arbeit eines Data Scientist (du hast vielleicht bemerkt, dass die Rolle nicht Model Scientist heißt).

In diesem Kapitel geht es um diesen Prozess, vom Sammeln eines ersten Datensatzes bis zur Prüfung und Validierung seiner Anwendbarkeit für ML. Beginnen wir mit der effizienten Erkundung eines Datensatzes, um seine Qualität zu beurteilen.

Erkunde deinen ersten Datensatz

Wie gehen wir also vor, um einen ersten Datensatz zu erforschen? Der erste Schritt besteht natürlich darin, einen Datensatz zu sammeln. Das ist der Punkt, an dem ich am häufigsten sehe, dass Praktiker auf der Suche nach dem perfekten Datensatz stecken bleiben. Erinnere dich, unser Ziel ist es, einen einfachen Datensatz zu erhalten, aus dem wir erste Ergebnisse gewinnen können. Wie auch bei anderen Dingen in der ML, fang einfach an und baue dann darauf auf.

Effizient sein, klein anfangen

Bei den meisten ML-Problemen können mehr Daten zu einem besseren Modell führen, aber das bedeutet nicht, dass du mit dem größtmöglichen Datensatz beginnen solltest. Wenn du mit einem Projekt beginnst, ermöglicht dir ein kleiner Datensatz, deine Daten zu überprüfen und zu verstehen, wie du sie besser modellieren kannst. Du solltest einen ersten Datensatz anstreben, mit dem du leicht arbeiten kannst. Erst wenn du dich für eine Strategie entschieden hast, ist es sinnvoll, sie auf eine größere Menge zu erweitern.

Wenn du in einem Unternehmen arbeitest, in dem Terabytes von Daten in einem Cluster gespeichert sind, kannst du damit beginnen, eine gleichmäßig abgetastete Teilmenge zu extrahieren, die in den Speicher deines lokalen Rechners passt. Wenn du an einem Nebenprojekt arbeiten möchtest, bei dem es darum geht, die Automarken zu identifizieren, die vor deinem Haus fahren, kannst du zum Beispiel mit ein paar Dutzend Bildern von Autos auf Straßen beginnen.

Wenn du gesehen hast, wie dein erstes Modell funktioniert und wo es Schwierigkeiten hat, kannst du deinen Datensatz auf fundierte Weise iterieren!

Du kannst viele bestehende Datensätze online auf Plattformen wie Kaggle oder Reddit finden oder selbst ein paar Beispiele sammeln, indem du entweder das Internet durchforstest, große offene Datensätze wie die auf der Common Crawl Website nutzt oder Daten generierst! Weitere Informationen findest du unter "Offene Daten".

Das Sammeln und Analysieren von Daten ist nicht nur notwendig, sondern beschleunigt auch deine Arbeit, besonders zu Beginn der Projektentwicklung. Wenn du dir deinen Datensatz ansiehst und seine Merkmale kennenlernst, ist das der einfachste Weg, eine gute Modellierungs- und Merkmalsgenerierungspipeline zu entwickeln.

Die meisten Praktiker/innen überschätzen die Auswirkungen der Arbeit am Modell und unterschätzen den Wert der Arbeit an den Daten. Ich empfehle daher, sich immer darum zu bemühen, diesen Trend zu korrigieren und sich auf die Daten zu konzentrieren.

Bei der Untersuchung von Daten ist es gut, Trends explorativ zu erkennen, aber du solltest dabei nicht stehen bleiben. Wenn es dein Ziel ist, ML-Produkte zu entwickeln, solltest du dich fragen, wie du diese Trends am besten automatisiert nutzen kannst. Wie können diese Trends dir helfen, ein automatisiertes Produkt zu entwickeln?

Einblicke statt Produkte

Sobald du einen Datensatz hast, ist es an der Zeit, in ihn einzutauchen und seinen Inhalt zu erkunden. Dabei sollten wir uns den Unterschied zwischen der Datenexploration für Analysezwecke und der Datenexploration für die Produktentwicklung vor Augen halten. Während beide darauf abzielen, Trends in den Daten zu erkennen und zu verstehen, geht es bei ersterer darum, aus Trends Erkenntnisse zu gewinnen (z. B. dass die meisten betrügerischen Logins auf einer Website donnerstags stattfinden und aus der Gegend von Seattle stammen), während es bei letzterer darum geht, Trends zu nutzen, um Funktionen zu entwickeln (z. B. anhand des Zeitpunkts eines Login-Versuchs und der IP-Adresse einen Dienst zu entwickeln, der betrügerische Logins von Accounts verhindert).

Auch wenn der Unterschied gering erscheint, führt er bei der Produktentwicklung zu einer zusätzlichen Komplexität. Wir müssen darauf vertrauen können, dass die Muster, die wir sehen, auch auf die Daten zutreffen, die wir in Zukunft erhalten, und die Unterschiede zwischen den Daten, die wir trainieren, und den Daten, die wir in der Produktion erwarten, quantifizieren.

Bei der Betrugsvorhersage ist der erste Schritt die Feststellung einer Saisonalität bei betrügerischen Anmeldungen. Dann sollten wir diesen beobachteten saisonalen Trend nutzen, um abzuschätzen, wie oft wir unsere Modelle auf kürzlich gesammelten Daten trainieren müssen. Im weiteren Verlauf dieses Kapitels werden wir unsere Daten genauer untersuchen.

Bevor Vorhersagetrends feststellt, sollten wir zunächst die Qualität prüfen. Wenn unser ausgewählter Datensatz nicht den Qualitätsstandards entspricht, sollten wir ihn verbessern, bevor wir mit der Modellierung fortfahren.

Eine Rubrik zur Datenqualität

In diesem Abschnitt gehen wir auf einige Aspekte ein, die du bei der ersten Arbeit mit einem neuen Datensatz beachten solltest. Jeder Datensatz hat seine eigenen Verzerrungen und Eigenheiten, die unterschiedliche Werkzeuge erfordern, um ihn zu verstehen. Daher würde es den Rahmen dieses Buches sprengen, eine umfassende Rubrik zu verfassen, die alles abdeckt, worauf du bei einem Datensatz achten solltest. Dennoch gibt es ein paar Kategorien, auf die du achten solltest, wenn du dich zum ersten Mal einem Datensatz näherst. Beginnen wir mit der Formatierung.

Datenformat

Ist der Datensatz bereits so formatiert, dass du eindeutige Eingaben und Ausgaben hast, oder sind zusätzliche Vorverarbeitungen und Kennzeichnungen erforderlich?

Wenn du ein Modell erstellst, das vorhersagen soll, ob ein Nutzer auf eine Anzeige klickt, besteht ein üblicher Datensatz beispielsweise aus einem historischen Protokoll aller Klicks in einem bestimmten Zeitraum. Du musst diesen Datensatz so umwandeln, dass er mehrere Instanzen einer Anzeige enthält, die einem Nutzer präsentiert wurde und ob er geklickt hat. Außerdem solltest du alle Merkmale des Nutzers oder der Anzeige einbeziehen, die du für dein Modell nutzen möchtest.

Wenn du einen Datensatz erhältst, der bereits für dich verarbeitet oder aggregiert wurde, solltest du überprüfen, ob du die Art und Weise, wie die Daten verarbeitet wurden, verstehst. Wenn eine der Spalten, die du erhalten hast, zum Beispiel eine durchschnittliche Konversionsrate enthält, kannst du diese Rate selbst berechnen und überprüfen, ob sie mit dem angegebenen Wert übereinstimmt?

In manchen Fällen hast du keinen Zugang zu den erforderlichen Informationen, um die Vorverarbeitungsschritte zu reproduzieren und zu validieren. In diesen Fällen hilft dir ein Blick auf die Qualität der Daten, um herauszufinden, welchen Merkmalen du vertrauen kannst und welche du lieber ignorieren solltest.

Datenqualität

Es ist wichtig, die Qualität eines Datensatzes zu prüfen, bevor du mit der Modellierung beginnst. Wenn du weißt, dass die Hälfte der Werte für ein wichtiges Merkmal fehlt, brauchst du nicht stundenlang ein Modell zu debuggen, um zu verstehen, warum es nicht gut funktioniert.

Es gibt viele Möglichkeiten, wie Daten von schlechter Qualität sein können. Sie können fehlen, ungenau sein oder sogar beschädigt werden. Wenn du dir ein genaues Bild von der Qualität der Daten machst, kannst du nicht nur abschätzen, welches Leistungsniveau angemessen ist, sondern auch mögliche Merkmale und Modelle leichter auswählen.

Wenn du mit Protokollen von Nutzeraktivitäten arbeitest, um die Nutzung eines Online-Produkts vorherzusagen, kannst du dann abschätzen, wie viele protokollierte Ereignisse fehlen? Wie viele der Ereignisse, die dir vorliegen, enthalten nur eine Teilmenge der Informationen über den Nutzer?

Wenn du an einem Text in natürlicher Sprache arbeitest, wie würdest du die Qualität des Textes bewerten? Gibt es zum Beispiel viele unverständliche Zeichen? Ist die Rechtschreibung sehr fehlerhaft oder inkonsistent?

Wenn du mit Bildern arbeitest, sind sie klar genug, dass du die Aufgabe selbst lösen kannst? Wenn es dir schwerfällt, ein Objekt in einem Bild zu erkennen, glaubst du, dass es deinem Modell schwerfallen wird, dies zu tun?

Welcher Anteil deiner Daten scheint generell verrauscht oder falsch zu sein? Wie viele Eingaben sind für dich schwer zu interpretieren oder zu verstehen? Wenn die Daten beschriftet sind, stimmst du ihnen eher zu oder stellst du ihre Richtigkeit oft in Frage?

Ich habe an einigen Projekten mitgearbeitet, die darauf abzielen, Informationen aus Satellitenbildern zu extrahieren, zum Beispiel. Im besten Fall haben diese Projekte Zugang zu einem Datensatz von Bildern mit entsprechenden Anmerkungen, die interessante Objekte wie Felder oder Flugzeuge bezeichnen. In manchen Fällen können diese Beschriftungen jedoch ungenau sein oder sogar fehlen. Solche Fehler haben einen erheblichen Einfluss auf jeden Modellierungsansatz, deshalb ist es wichtig, sie frühzeitig zu erkennen. Wir können mit fehlenden Beschriftungen arbeiten, indem wir entweder einen ersten Datensatz selbst beschriften oder eine schwache Beschriftung finden, die wir verwenden können, aber das können wir nur, wenn wir die Qualität rechtzeitig erkennen.

Nach der Überprüfung des Formats und der Qualität der Daten kann ein zusätzlicher Schritt helfen, Probleme proaktiv zu erkennen: die Untersuchung der Datenmenge und der Merkmalsverteilung.

Datenmenge und -verteilung

Lass uns abschätzen, ob wir genug Daten haben und ob die Merkmalswerte in einem vernünftigen Bereich liegen.

Wie viele Daten haben wir? Wenn wir einen großen Datensatz haben, sollten wir eine Teilmenge auswählen, mit der wir unsere Analyse beginnen. Wenn unser Datensatz jedoch zu klein ist oder einige Klassen unterrepräsentiert sind, besteht die Gefahr, dass die von uns trainierten Modelle genauso verzerrt sind wie unsere Daten. Der beste Weg, um solche Verzerrungen zu vermeiden, ist, die Vielfalt unserer Daten durch Datenerfassung und -erweiterung zu erhöhen. Wie du die Qualität deiner Daten misst, hängt von deinem Datensatz ab, aber Tabelle 4-1 enthält ein paar Fragen, die dir den Einstieg erleichtern.

Tabelle 4-1. Eine Rubrik zur Datenqualität
Qualität Format Menge und Verteilung

Sind relevante Felder jemals leer?

Wie viele Vorverarbeitungsschritte sind für deine Daten erforderlich?

Wie viele Beispiele hast du?

Gibt es mögliche Messfehler?

Kannst du es in der Produktion auf die gleiche Weise vorverarbeiten?

Wie viele Beispiele pro Klasse? Fehlen welche?

Ein praktisches Beispiel: Bei der Entwicklung eines Modells zur automatischen Kategorisierung von Kundensupport-E-Mails in verschiedene Fachgebiete erhielt Alex Wahl, ein Datenwissenschaftler, mit dem ich zusammenarbeitete, neun verschiedene Kategorien mit nur einem Beispiel pro Kategorie. Ein solcher Datensatz ist für ein Modell zu klein, um daraus zu lernen, also konzentrierte er sich hauptsächlich auf eine Strategie zur Datengenerierung. Er benutzte Templates mit gängigen Formulierungen für jede der neun Kategorien, um Tausende weiterer Beispiele zu erzeugen, aus denen ein Modell lernen konnte. Mit dieser Strategie gelang es ihm, eine Pipeline mit viel höherer Genauigkeit zu erstellen, als wenn er versucht hätte, ein Modell zu entwickeln, das komplex genug ist, um aus nur neun Beispielen zu lernen.

Wenden wir diesen Erkundungsprozess auf den Datensatz an, den wir für unseren ML-Editor ausgewählt haben, und schätzen wir seine Qualität ein!

ML Editor Datenprüfung

Für, unseren ML-Editor, haben wir uns zunächst für den anonymisierten Stack Exchange Data Dump als Datensatz entschieden. Stack Exchange ist ein Netzwerk von Frage-und-Antwort-Websites, die sich jeweils auf ein Thema wie Philosophie oder Spiele konzentrieren. Der Datendump enthält viele Archive, eines für jede Website im Stack Exchange-Netzwerk.

Für unseren ersten Datensatz wählen wir eine Website, die genügend Fragen enthält, um daraus nützliche Heuristiken zu erstellen. Auf den ersten Blick scheint die Writing Community gut geeignet zu sein.

Jedes Website-Archiv wird in Form einer XML-Datei bereitgestellt. Wir müssen eine Pipeline erstellen, die diese Dateien aufnimmt und in Text umwandelt, aus dem wir dann Merkmale extrahieren können. Das folgende Beispiel zeigt die Datei Posts.xml für datascience.stackexchange.com:

<?xml version="1.0" encoding="utf-8"?>
<posts>
  <row Id="5" PostTypeId="1" CreationDate="2014-05-13T23:58:30.457"
Score="9" ViewCount="516" Body="&lt;p&gt; &quot;Hello World&quot; example? "
OwnerUserId="5" LastActivityDate="2014-05-14T00:36:31.077"
Title="How can I do simple machine learning without hard-coding behavior?"
Tags="&lt;machine-learning&gt;" AnswerCount="1" CommentCount="1" />
  <row Id="7" PostTypeId="1" AcceptedAnswerId="10" ... />

Um diese Daten nutzen zu können, müssen wir in der Lage sein, die XML-Datei zu laden, die HTML-Tags im Text zu dekodieren und die Fragen und die damit verbundenen Daten in einem Format darzustellen, das leichter zu analysieren ist, wie z. B. ein Pandas DataFrame. Die folgende Funktion macht genau das. Zur Erinnerung: Den Code für diese Funktion und alle anderen Codes in diesem Buch findest du im GitHub-Repository dieses Buches.

import xml.etree.ElementTree as ElT


def parse_xml_to_csv(path, save_path=None):
    """
    Open .xml posts dump and convert the text to a csv, tokenizing it in the
         process
    :param path: path to the xml document containing posts
    :return: a dataframe of processed text
    """

    # Use python's standard library to parse XML file
    doc = ElT.parse(path)
    root = doc.getroot()

    # Each row is a question
    all_rows = [row.attrib for row in root.findall("row")]

    # Using tdqm to display progress since preprocessing takes time
    for item in tqdm(all_rows):
        # Decode text from HTML
        soup = BeautifulSoup(item["Body"], features="html.parser")
        item["body_text"] = soup.get_text()

    # Create dataframe from our list of dictionaries
    df = pd.DataFrame.from_dict(all_rows)
    if save_path:
        df.to_csv(save_path)
    return df

Selbst bei einem relativ kleinen Datensatz mit nur 30.000 Fragen dauert dieser Prozess mehr als eine Minute, also serialisieren wir die verarbeitete Datei zurück auf die Festplatte, um sie nur einmal verarbeiten zu müssen. Dazu können wir einfach die Funktion to_csv von Panda verwenden, wie in der letzten Zeile des Snippets gezeigt.

Dies ist generell eine empfohlene Vorgehensweise für alle Vorverarbeitungen, die für das Training eines Modells erforderlich sind. Vorverarbeitender Code, der direkt vor der Modelloptimierung ausgeführt wird, kann das Experimentieren erheblich verlangsamen. Verarbeite die Daten so weit wie möglich im Voraus und speichere sie auf der Festplatte.

Sobald wir unsere Daten in diesem Format haben, können wir die Aspekte untersuchen, die wir zuvor beschrieben haben. Der gesamte Erkundungsprozess, den wir im Folgenden beschreiben, kann im Dataset Exploration Notebook im GitHub-Repository dieses Buches nachgelesen werden.

Zunächst verwenden wir df.info(), um eine Zusammenfassung unseres Datenrahmens sowie alle leeren Werte anzuzeigen. Das ist das, was es zurückgibt:

>>>> df.info()

AcceptedAnswerId         4124 non-null float64
AnswerCount              33650 non-null int64
Body                     33650 non-null object
ClosedDate               969 non-null object
CommentCount             33650 non-null int64
CommunityOwnedDate       186 non-null object
CreationDate             33650 non-null object
FavoriteCount            3307 non-null float64
Id                       33650 non-null int64
LastActivityDate         33650 non-null object
LastEditDate             10521 non-null object
LastEditorDisplayName    606 non-null object
LastEditorUserId         9975 non-null float64
OwnerDisplayName         1971 non-null object
OwnerUserId              32117 non-null float64
ParentId                 25679 non-null float64
PostTypeId               33650 non-null int64
Score                    33650 non-null int64
Tags                     7971 non-null object
Title                    7971 non-null object
ViewCount                7971 non-null float64
body_text                33650 non-null object
full_text                33650 non-null object
text_len                 33650 non-null int64
is_question              33650 non-null bool

Wir können sehen, dass wir etwas mehr als 31.000 Beiträge haben, von denen nur etwa 4.000 eine akzeptierte Antwort haben. Außerdem können wir feststellen, dass einige der Werte für Body, die den Inhalt eines Beitrags darstellen, Null sind, was verdächtig erscheint. Wir würden erwarten, dass alle Beiträge Text enthalten. Ein Blick auf die Zeilen mit einem Nullwert Body zeigt schnell, dass sie zu einem Beitragstyp gehören, der in der Dokumentation des Datensatzes nicht erwähnt wird.

Lass uns kurz in das Format eintauchen und sehen, ob wir es verstehen. Jeder Beitrag hat einen PostTypeId Wert von 1 für eine Frage bzw. 2 für eine Antwort. Wir möchten sehen, welche Art von Fragen eine hohe Punktzahl erhalten, denn wir möchten die Punktzahl einer Frage als schwaches Label für unser eigentliches Label, die Qualität einer Frage, verwenden.

Zuerst wollen wir die Fragen mit den dazugehörigen Antworten abgleichen. Der folgende Code wählt alle Fragen aus, die eine akzeptierte Antwort haben, und verbindet sie mit dem Text für diese Antwort. Dann können wir uns die ersten paar Zeilen ansehen und überprüfen, ob die Antworten mit den Fragen übereinstimmen. So können wir auch den Text schnell durchsehen und seine Qualität beurteilen.

questions_with_accepted_answers = df[
    df["is_question"] & ~(df["AcceptedAnswerId"].isna())
]
q_and_a = questions_with_accepted_answers.join(
    df[["Text"]], on="AcceptedAnswerId", how="left", rsuffix="_answer"
)

pd.options.display.max_colwidth = 500
q_and_a[["Text", "Text_answer"]][:5]

In Tabelle 4-2 sehen wir, dass die Fragen und Antworten übereinstimmen und dass der Text größtenteils korrekt zu sein scheint. Wir vertrauen jetzt darauf, dass wir die Fragen mit den dazugehörigen Antworten abgleichen können.

Tabelle 4-2. Fragen mit den dazugehörigen Antworten
Id body_text body_text_answer

1

Ich wollte schon immer mit dem Schreiben anfangen (ganz amateurhaft), aber jedes Mal, wenn ich etwas anfangen will, bin ich sofort blockiert, weil ich viele Fragen und Zweifel habe.\n Gibt es Ressourcen, wie man anfängt, ein Schriftsteller zu werden?\n Ich denke an etwas mit Tipps und einfachen Übungen, um den Ball ins Rollen zu bringen.\n

Wenn ich darüber nachdenke, wo ich am meisten gelernt habe, wie man schreibt, denke ich, dass das Lesen der wichtigste Ratgeber für mich war. Das mag albern klingen, aber durch das Lesen von gut geschriebenen Zeitungsartikeln (Fakten, Meinungen, wissenschaftliche Artikel und vor allem Film- und Musikkritiken) habe ich gelernt, wie andere ihre Arbeit machen, was funktioniert und was nicht. Bei meinem eigenen Schreiben versuche ich, den Stil anderer Leute nachzuahmen, der mir gefällt. Außerdem lerne ich durch das Lesen neue Dinge, die mir einen breiteren Hintergrund geben, den ich brauche, wenn ich wieder...

2

Welche Art von Geschichte eignet sich besser für jede Sichtweise? Gibt es Vor- oder Nachteile? Wenn du zum Beispiel in der ersten Person schreibst, folgst du immer einer Figur, während du in der dritten Person zwischen den Handlungssträngen "springen" kannst.

Wenn du in der ersten Person erzählst, möchtest du, dass sich der Leser mit der Hauptfigur verbunden fühlt. Da der Leser sieht, was die Figur sieht, und fühlt, was sie fühlt, wird der Leser eine emotionale Bindung zu dieser Figur aufbauen. In der dritten Person gibt es diese enge Bindung nicht; der Leser kann zwar emotional involviert werden, aber nicht so stark wie in der ersten Person.\nNatürlich kannst du in der ersten Person nicht mehrere Hauptfiguren haben, ohne...

3

Ich habe meinen Roman fertiggestellt, und alle, mit denen ich gesprochen habe, sagen, dass ich einen Agenten brauche. Wie finde ich einen?\n

Versuche, eine Liste von Agenten zu finden, die in deinem Genre schreiben, und sieh dir ihre Websites an!\nFinde heraus, ob sie neue Kunden annehmen. Wenn nicht, dann suche dir einen anderen Agenten. Wenn ja, schick ihnen ein paar Kapitel aus deiner Geschichte, ein Exposé und ein kurzes Anschreiben, in dem du sie bittest, dich zu vertreten.\n Im Anschreiben solltest du deine bisherigen Veröffentlichungen erwähnen. Wenn du das Anschreiben per Post schickst, solltest du ihnen eine Antwortmöglichkeit geben, sei es eine E-Mail oder ein frankierter und adressierter Rückumschlag.\nAgenten...

Als letzte Überprüfung wollen wir uns ansehen, auf wie viele Fragen keine Antwort gegeben wurde, auf wie viele Fragen mindestens eine Antwort gegeben wurde und auf wie viele Fragen eine Antwort gegeben wurde, die akzeptiert wurde.

has_accepted_answer = df[df["is_question"] & ~(df["AcceptedAnswerId"].isna())]
no_accepted_answers = df[
    df["is_question"]
    & (df["AcceptedAnswerId"].isna())
    & (df["AnswerCount"] != 0)
]
no_answers = df[
    df["is_question"]
    & (df["AcceptedAnswerId"].isna())
    & (df["AnswerCount"] == 0)
]

print(
    "%s questions with no answers, %s with answers, %s with an accepted answer"
    % (len(no_answers), len(no_accepted_answers), len(has_accepted_answer))
)

3584 questions with no answers, 5933 with answers, 4964 with an accepted answer.

Wir haben eine relativ gleichmäßige Verteilung zwischen beantworteten, teilweise beantworteten und unbeantworteten Fragen. Das scheint vernünftig zu sein, sodass wir zuversichtlich genug sein können, um mit unserer Erkundung fortzufahren.

Wir verstehen das Format unserer Daten und haben genug davon, um loszulegen. Wenn du an einem Projekt arbeitest und dein aktueller Datensatz entweder zu klein ist oder einen Großteil der Merkmale enthält, die zu schwer zu interpretieren sind, solltest du mehr Daten sammeln oder einen ganz anderen Datensatz ausprobieren.

Unser Datensatz ist von ausreichender Qualität, um weiterzumachen. Jetzt ist es an der Zeit, ihn genauer zu untersuchen, um unsere Modellierungsstrategie zu verbessern.

Etikett zum Finden von Datentrends

Bei der Identifizierung von Trends in unserem Datensatz geht es um mehr als nur um Qualität. In diesem Teil der Arbeit versetzen wir uns in die Lage unseres Modells und versuchen vorherzusagen, welche Strukturen es erkennen wird. Dazu werden wir die Daten in verschiedene Cluster aufteilen (das Clustering erkläre ich im Abschnitt "Clustering") und versuchen, Gemeinsamkeiten in den einzelnen Clustern zu finden.

Im Folgenden findest du eine Schritt-für-Schritt-Liste, um dies in der Praxis umzusetzen. Wir beginnen mit der Erstellung von zusammenfassenden Statistiken unseres Datensatzes und sehen dann, wie wir ihn mit Hilfe von Vektorisierungstechniken schnell erkunden können. Mithilfe von Vektorisierung und Clustering werden wir unseren Datensatz effizient erkunden.

Zusammenfassende Statistik

Wenn du dir einen Datensatz ansiehst, ist es in der Regel eine gute Idee, sich einige zusammenfassende Statistiken für jedes deiner Merkmale anzusehen. So bekommst du einen allgemeinen Eindruck von den Merkmalen in deinem Datensatz und erkennst, wie du deine Klassen leicht trennen kannst.

Das frühzeitige Erkennen von Unterschieden in der Verteilung zwischen Datenklassen ist beim ML hilfreich, weil es entweder unsere Modellierungsaufgabe erleichtert oder uns davor bewahrt, die Leistung eines Modells zu überschätzen, das vielleicht nur ein besonders informatives Merkmal nutzt.

Wenn du z.B. mit vorhersagen willst, ob Tweets eine positive oder negative Meinung ausdrücken, könntest du damit beginnen, die durchschnittliche Anzahl der Wörter in jedem Tweet zu zählen. Dann kannst du ein Histogramm dieses Merkmals erstellen, um etwas über seine Verteilung zu erfahren.

Anhand eines Histogramms könntest du feststellen, ob alle positiven Tweets kürzer als die negativen sind. Das könnte dazu führen, dass du die Wortlänge als Prädiktor hinzufügst, um deine Aufgabe zu erleichtern, oder im Gegenteil zusätzliche Daten sammelst, um sicherzustellen, dass dein Modell über den Inhalt der Tweets und nicht nur über ihre Länge lernen kann.

Um dies zu verdeutlichen, wollen wir ein paar zusammenfassende Statistiken für unseren ML-Editor erstellen.

Zusammenfassende Statistik für ML Editor

Für unser Beispiel können wir ein Histogramm der Länge der Fragen in unserem Datensatz erstellen, das die unterschiedlichen Trends zwischen Fragen mit hoher und niedriger Punktzahl aufzeigt. Hier sehen wir, wie wir das mit Pandas machen:

import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle

"""
df contains questions and their answer counts from writers.stackexchange.com
We draw two histograms:
one for questions with scores under the median score
one for questions with scores over
For both, we remove outliers to make our visualization simpler
"""

high_score = df["Score"] > df["Score"].median()
# We filter out really long questions
normal_length = df["text_len"] < 2000

ax = df[df["is_question"] & high_score & normal_length]["text_len"].hist(
    bins=60,
    density=True,
    histtype="step",
    color="orange",
    linewidth=3,
    grid=False,
    figsize=(16, 10),
)

df[df["is_question"] & ~high_score & normal_length]["text_len"].hist(
    bins=60,
    density=True,
    histtype="step",
    color="purple",
    linewidth=3,
    grid=False,
)

handles = [
    Rectangle((0, 0), 1, 1, color=c, ec="k") for c in ["orange", "purple"]
]
labels = ["High score", "Low score"]
plt.legend(handles, labels)
ax.set_xlabel("Sentence length (characters)")
ax.set_ylabel("Percentage of sentences")

In Abbildung 4-2 sehen wir, dass die Verteilungen größtenteils ähnlich sind, wobei die Fragen mit hoher Punktzahl tendenziell etwas länger sind (dieser Trend ist besonders bei der 800-Zeichen-Marke zu beobachten). Dies ist ein Hinweis darauf, dass die Länge der Frage ein nützliches Merkmal für ein Modell zur Vorhersage der Punktzahl einer Frage sein kann.

Wir können andere Variablen auf ähnliche Weise darstellen, um weitere potenzielle Merkmale zu identifizieren. Wenn wir einige Merkmale identifiziert haben, sollten wir unseren Datensatz etwas genauer betrachten, damit wir detailliertere Trends erkennen können.

Text length for questions with high or low scores
Abbildung 4-2. Histogramm der Textlänge für Fragen mit hoher und niedriger Punktzahl

Effizientes Erkunden und Beschriften

Du kannst nur so weit kommen, wenn du dir deskriptive Statistiken wie Durchschnittswerte und Diagramme wie Histogramme ansiehst. Um ein Gespür für deine Daten zu entwickeln, solltest du einige Zeit damit verbringen, dir einzelne Datenpunkte anzusehen. Es ist jedoch ziemlich ineffizient, die Punkte eines Datensatzes wahllos durchzugehen. In diesem Abschnitt erfährst du, wie du deine Effizienz bei der Visualisierung einzelner Datenpunkte maximieren kannst.

Clustering ist eine nützliche Methode, die hier zum Einsatz kommt. Beim Clustering geht es darum, eine Menge von Objekten so zu gruppieren, dass die Objekte in derselben Gruppe (genannt Cluster) einander (in gewisser Weise) ähnlicher sind als die Objekte in anderen Gruppen (Clustern). Wir werden das Clustering sowohl für die Erkundung unserer Daten als auch für unsere Modellvorhersagen verwenden (siehe "Dimensionalitätsreduktion").

Viele Clustering-Algorithmen gruppieren Datenpunkte, indem sie den Abstand zwischen den Punkten messen und die Punkte, die nahe beieinander liegen, demselben Cluster zuordnen. Abbildung 4-3 zeigt ein Beispiel für einen Clustering-Algorithmus, der einen Datensatz in drei verschiedene Cluster aufteilt. Das Clustering ist eine unbeaufsichtigte Methode, und es gibt oft keinen einzigen richtigen Weg, einen Datensatz zu clustern. In diesem Buch werden wir das Clustering nutzen, um eine Struktur zu schaffen, die uns bei der Erkundung hilft.

Da das Clustering auf der Berechnung des Abstands zwischen Datenpunkten beruht, hat die Art und Weise, wie wir unsere Datenpunkte numerisch darstellen, einen großen Einfluss darauf, welche Cluster erzeugt werden. Darauf gehen wir im nächsten Abschnitt, "Vektorisierung", näher ein.

Generating three clusters from a dataset
Abbildung 4-3. Generierung von drei Clustern aus einem Datensatz

Die überwiegende Mehrheit der Datensätze kann auf der Grundlage ihrer Merkmale, Bezeichnungen oder einer Kombination aus beidem in Cluster eingeteilt werden. Die Untersuchung jedes einzelnen Clusters sowie der Ähnlichkeiten und Unterschiede zwischen den Clustern ist eine gute Möglichkeit, die Struktur eines Datensatzes zu erkennen.

Hier gibt es mehrere Dinge, auf die du achten solltest:

  • Wie viele Cluster kannst du in deinem Datensatz identifizieren?

  • Kommt dir jedes dieser Cluster anders vor? Auf welche Weise?

  • Gibt es Cluster, die viel dichter sind als andere? Wenn das der Fall ist, wird dein Modell in den dünneren Bereichen wahrscheinlich nur schwer funktionieren. Das Hinzufügen von Merkmalen und Daten kann helfen, dieses Problem zu lindern.

  • Stellen alle Cluster Daten dar, die "schwer" zu modellieren sind? Wenn einige Cluster komplexere Datenpunkte zu repräsentieren scheinen, notiere sie, damit du sie bei der Bewertung der Leistung unseres Modells erneut betrachten kannst.

Wie bereits erwähnt, arbeiten Clustering-Algorithmen mit Vektoren. Wir können also nicht einfach einen Satz von Sätzen an einen Clustering-Algorithmus übergeben. Um unsere Daten für das Clustern vorzubereiten, müssen wir sie zunächst vektorisieren.

Vektorisierung

Vektorisierung Ein Datensatz wird von den Rohdaten in einen Vektor umgewandelt, der ihn darstellt. Abbildung 4-4 zeigt ein Beispiel für vektorisierte Darstellungen von Text- und Tabellendaten.

Examples of vectorized representations
Abbildung 4-4. Beispiele für vektorisierte Darstellungen

Es gibt viele Möglichkeiten, Daten zu vektorisieren. Wir werden uns daher auf einige einfache Methoden konzentrieren, die für einige der gängigsten Datentypen funktionieren, z. B. für Tabellendaten, Text und Bilder.

Tabellarische Daten

Für tabellarische Daten, die sowohl aus kategorialen als auch aus kontinuierlichen Merkmalen bestehen, ist eine mögliche Vektordarstellung einfach die Verkettung der Vektordarstellungen der einzelnen Merkmale.

Kontinuierliche Merkmale sollten auf eine gemeinsame Skala normalisiert werden, damit Merkmale mit einer größeren Skala nicht dazu führen, dass kleinere Merkmale von den Modellen vollständig ignoriert werden. Es gibt verschiedene Möglichkeiten, Daten zu normalisieren, aber es ist oft ein guter erster Schritt, jedes Merkmal so zu transformieren, dass sein Mittelwert gleich Null und seine Varianz gleich Eins ist. Diese wird oft als Standard-Score bezeichnet.

Kategorische Merkmale wie Farben können in eine One-Hot-Codierung umgewandelt werden: eine Liste, die so lang ist wie die Anzahl der verschiedenen Werte des Merkmals und nur aus Nullen und einer einzigen Eins besteht, deren Index den aktuellen Wert darstellt (in einem Datensatz mit vier verschiedenen Farben könnten wir zum Beispiel Rot als [1, 0, 0, 0] und Blau als [0, 0, 1, 0] codieren). Du fragst dich vielleicht, warum wir nicht einfach jedem möglichen Wert eine Zahl zuweisen, z. B. 1 für Rot und 3 für Blau. Das liegt daran, dass ein solches Kodierungsschema eine Ordnung zwischen den Werten implizieren würde (blau ist größer als rot), was bei kategorialen Variablen oft nicht stimmt.

Eine Eigenschaft der One-Hot-Codierung ist, dass der Abstand zwischen zwei gegebenen Merkmalswerten immer eins ist. In manchen Fällen, wie z. B. bei den Wochentagen, sind sich einige Werte jedoch ähnlicher als die anderen (Samstag und Sonntag liegen beide am Wochenende, so dass ihre Vektoren idealerweise näher beieinander liegen würden als z. B. Mittwoch und Sonntag). Neuronale Netze haben sich als nützlich erwiesen, um solche Repräsentationen zu lernen (siehe den Artikel "Entity Embeddings of Categorical Variables" von C. Guo und F. Berkhahn). Es hat sich gezeigt, dass diese Repräsentationen die Leistung von Modellen verbessern, die sie anstelle von anderen Kodierungsschemata verwenden.

Schließlich sollten komplexere Merkmale wie z. B. Daten in einige wenige numerische Merkmale umgewandelt werden, die ihre hervorstechenden Eigenschaften erfassen.

Lass uns ein praktisches Beispiel für die Vektorisierung von Tabellendaten durchgehen. Den Code für das Beispiel findest du im Tabellendaten-Vektorisierungs-Notizbuch im GitHub-Repository dieses Buches.

Angenommen, wir wollen uns nicht den Inhalt der Fragen ansehen, sondern anhand der Tags, der Anzahl der Kommentare und des Erstellungsdatums vorhersagen, welche Punktzahl eine Frage erhalten wird. In Tabelle 4-3 siehst du ein Beispiel dafür, wie dieser Datensatz für writers.stackexchange.com aussehen würde.

Tabelle 4-3. Tabellarische Eingaben ohne jegliche Verarbeitung
Id Tags KommentarZahl CreationDate Ergebnis

1

<resources><first-time-author>

7

2010-11-18T20:40:32.857

32

2

<Belletristik><Grammatische-Person><Dritte-Person>

0

2010-11-18T20:42:31.513

20

3

<Veröffentlichung><Roman><Agent>

1

2010-11-18T20:43:28.903

34

5

<Handlung><Kurzgeschichte><Planung><Brainstorming>

0

2010-11-18T20:43:59.693

28

7

<Belletristik><Genre><Kategorien>

1

2010-11-18T20:45:44.067

21

Jede Frage hat mehrere Tags, ein Datum und eine Reihe von Kommentaren. Wir werden jede dieser Angaben vorverarbeiten. Zuerst normalisieren wir die numerischen Felder:

def get_norm(df, col):
    return (df[col] - df[col].mean()) / df[col].std()

tabular_df["NormComment"]= get_norm(tabular_df, "CommentCount")
tabular_df["NormScore"]= get_norm(tabular_df, "Score")

Dann extrahieren wir relevante Informationen aus dem Datum. Wir könnten zum Beispiel das Jahr, den Monat, den Tag und die Stunde der Buchung auswählen. Jede dieser Angaben ist ein numerischer Wert, den unser Modell verwenden kann.

# Convert our date to a pandas datetime
tabular_df["date"] = pd.to_datetime(tabular_df["CreationDate"])

# Extract meaningful features from the datetime object
tabular_df["year"] = tabular_df["date"].dt.year
tabular_df["month"] = tabular_df["date"].dt.month
tabular_df["day"] = tabular_df["date"].dt.day
tabular_df["hour"] = tabular_df["date"].dt.hour

Unsere Tags sind kategorische Merkmale, wobei jede Frage eine beliebige Anzahl von Tags haben kann. Wie wir bereits gesehen haben, ist es am einfachsten, kategoriale Eingaben zu kodieren, indem jedes Tag in eine eigene Spalte umgewandelt wird, wobei jede Frage für ein bestimmtes Tag-Merkmal nur dann den Wert 1 erhält, wenn dieses Tag mit dieser Frage verknüpft ist.

Da wir mehr als dreihundert Tags in unserem Datensatz haben, haben wir uns entschieden, nur eine Spalte für die fünf beliebtesten Tags zu erstellen, die in mehr als fünfhundert Fragen verwendet werden. Wir könnten zwar jedes einzelne Tag hinzufügen, aber da die meisten von ihnen nur einmal vorkommen, wäre das nicht hilfreich, um Muster zu erkennen.

# Select our tags, represented as strings, and transform them into arrays of tags
tags = tabular_df["Tags"]
clean_tags = tags.str.split("><").apply(
    lambda x: [a.strip("<").strip(">") for a in x])

# Use pandas' get_dummies to get dummy values
# select only tags that appear over 500 times
tag_columns = pd.get_dummies(clean_tags.apply(pd.Series).stack()).sum(level=0)
all_tags = tag_columns.astype(bool).sum(axis=0).sort_values(ascending=False)
top_tags = all_tags[all_tags > 500]
top_tag_columns = tag_columns[top_tags.index]

# Add our tags back into our initial DataFrame
final = pd.concat([tabular_df, top_tag_columns], axis=1)

# Keeping only the vectorized features
col_to_keep = ["year", "month", "day", "hour", "NormComment",
               "NormScore"] + list(top_tags.index)
final_features = final[col_to_keep]

In Tabelle 4-4 siehst du, dass unsere Daten jetzt vollständig vektorisiert sind und jede Zeile nur aus numerischen Werten besteht. Wir können diese Daten einem Clustering-Algorithmus oder einem überwachten ML-Modell zuführen.

Tabelle 4-4. Vektorisierte tabellarische Eingaben
Id Jahr Monat Tag Stunde Norm-Kommentar Norm-Score Kreatives Schreiben Belletristik Stil Charaktere Tech-nik Roman Pub-lishing

1

2010

11

18

20

0.165706

0.140501

0

0

0

0

0

0

0

2

2010

11

18

20

-0.103524

0.077674

0

1

0

0

0

0

0

3

2010

11

18

20

-0.065063

0.150972

0

0

0

0

0

1

1

5

2010

11

18

20

-0.103524

0.119558

0

0

0

0

0

0

0

7

2010

11

18

20

-0.065063

0.082909

0

1

0

0

0

0

0

Verschiedene Arten von Daten erfordern unterschiedliche Vektorisierungsmethoden. Vor allem Textdaten erfordern oft kreativere Ansätze.

Textdaten

Die einfachste Art, Text zu vektorisieren ist die Verwendung eines Zählvektors, der das Wortäquivalent einer One-Hot-Codierung ist. Beginne damit, ein Vokabular zu erstellen, das aus der Liste der eindeutigen Wörter in deinem Datensatz besteht. Ordne jedem Wort in unserem Vokabular einen Index zu (von 0 bis zur Größe des Vokabulars). Dann kannst du jeden Satz oder Absatz durch eine Liste darstellen, die so lang ist wie unser Vokabular. Für jeden Satz steht die Zahl bei jedem Index für die Anzahl der Vorkommen des zugehörigen Wortes in dem jeweiligen Satz.

Diese Methode ignoriert die Reihenfolge der Wörter in einem Satz und wird daher als Bag-of-Words bezeichnet. Abbildung 4-5 zeigt zwei Sätze und ihre Bag-of-Words-Darstellungen. Beide Sätze werden in Vektoren umgewandelt, die Informationen darüber enthalten, wie oft ein Wort in einem Satz vorkommt, aber nicht die Reihenfolge, in der die Wörter in dem Satz vorkommen.

Getting bag of words vectors from sentences
Abbildung 4-5. Bag-of-Word-Vektoren aus Sätzen gewinnen

Die Verwendung von einer Bag-of-Words-Darstellung oder ihrer normalisierten Version TF-IDF (kurz für Term Frequency-Inverse Document Frequency) ist mit scikit-learn einfach, wie du hier sehen kannst:

# Create an instance of a tfidf vectorizer,
# We could use CountVectorizer for a non normalized version
vectorizer = TfidfVectorizer()

# Fit our vectorizer to questions in our dataset
# Returns an array of vectorized text
bag_of_words = vectorizer.fit_transform(df[df["is_question"]]["Text"])

Mehrere neuartige Methoden zur Vektorisierung von Texten wurden im Laufe der Jahre entwickelt. Den Anfang machte 2013 Word2Vec (siehe den Artikel "Efficient Estimation of Word Representations in Vector Space" von Mikolov et al.) und neuere Ansätze wie fastText (siehe den Artikel "Bag of Tricks for Efficient Text Classification" von Joulin et al.). Diese Vektorisierungstechniken erzeugen Wortvektoren, die versuchen, eine Darstellung zu erlernen, die Ähnlichkeiten zwischen Konzepten besser erfasst als eine TF-IDF-Kodierung. Dies geschieht, indem sie lernen, welche Wörter in großen Textbeständen wie Wikipedia in ähnlichen Kontexten vorkommen. Dieser Ansatz basiert auf der Distributionshypothese, die besagt, dass sprachliche Elemente mit ähnlicher Verteilung auch ähnliche Bedeutungen haben.

Konkret geschieht dies durch das Lernen eines Vektors für jedes Wort und das Trainieren eines Modells zur Vorhersage eines fehlenden Wortes in einem Satz anhand der Wortvektoren der umliegenden Wörter. Die Anzahl der zu berücksichtigenden Nachbarwörter wird als Fenstergröße bezeichnet. In Abbildung 4-6 siehst du eine Darstellung dieser Aufgabe für eine Fenstergröße von zwei. Auf der linken Seite werden die Wortvektoren für die beiden Wörter vor und nach dem Ziel in ein einfaches Modell eingegeben. Dieses einfache Modell und die Werte der Wortvektoren werden dann so optimiert, dass die Ausgabe mit dem Wortvektor des fehlenden Wortes übereinstimmt.

Es gibt viele vorgefertigte Open-Source-Modelle zur Vektorisierung von Wörtern. Die Verwendung von Vektoren, die von einem Modell erzeugt wurden, das auf einem großen Korpus (oft Wikipedia oder ein Archiv mit Nachrichten) vortrainiert wurde, kann unseren Modellen helfen, die semantische Bedeutung gängiger Wörter besser zu nutzen.

Die Wortvektoren, die in der FastText-Arbeit von Joulin et al. erwähnt werden, sind beispielsweise als eigenständiges Tool online verfügbar. Für eine individuellere Herangehensweise ist spaCy ein NLP-Toolkit, das vortrainierte Modelle für eine Vielzahl von Aufgaben anbietet, aber auch einfache Möglichkeiten, eigene Modelle zu erstellen.

Hier ist ein Beispiel für die Verwendung von spaCy, um vortrainierte Wortvektoren zu laden und aus ihnen einen semantisch sinnvollen Satzvektor zu bilden. Unter der Haube holt spaCy den vortrainierten Wert für jedes Wort in unserem Datensatz ab (oder ignoriert ihn, wenn er nicht Teil der vortrainierten Aufgabe war) und bildet den Durchschnitt aller Vektoren in einer Frage, um eine Darstellung der Frage zu erhalten.

import spacy

# We load a large model, and disable pipeline unnecessary parts for our task
# This speeds up the vectorization process significantly
# See https://spacy.io/models/en#en_core_web_lg for details about the model
nlp = spacy.load('en_core_web_lg', disable=["parser", "tagger", "ner",
      "textcat"])

# We then simply get the vector for each of our questions
# By default, the vector returned is the average of all vectors in the sentence
# See https://spacy.io/usage/vectors-similarity for more
spacy_emb = df[df["is_question"]]["Text"].apply(lambda x: nlp(x).vector)

Einen Vergleich eines TF-IDF-Modells mit vortrainierten Worteinbettungen für unseren Datensatz findest du im Vectorizing Text Notebook im GitHub-Repository des Buches.

Seit 2018 liefert die Wortvektorisierung mit großen Sprachmodellen auf noch größeren Datensätzen die genauesten Ergebnisse (siehe die Artikel "Universal Language Model Fine-Tuning for Text Classification" von J. Howard und S. Ruder und "BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding" von J. Devlin et al.) Diese großen Modelle haben jedoch den Nachteil, dass sie langsamer und komplexer sind als einfache Worteinbettungen.

Zum Schluss wollen wir die Vektorisierung für einen anderen häufig verwendeten Datentyp untersuchen: Bilder.

Bilddaten

Die Daten des Bildes sind bereits vektorisiert, denn ein Bild ist nichts anderes als ein mehrdimensionales Zahlenfeld, das in der ML-Gemeinde oft als Tensor bezeichnet wird. Die meisten Standard-RGB-Bilder mit drei Kanälen ( ) werden zum Beispiel einfach als eine Liste von Zahlen gespeichert, deren Länge der Höhe des Bildes in Pixeln entspricht, multipliziert mit seiner Breite, multipliziert mit drei (für die Kanäle Rot, Grün und Blau). In Abbildung 4-7 siehst du, wie wir ein Bild als einen Zahlentensor darstellen können, der die Intensität jeder der drei Grundfarben repräsentiert.

Wir können diese Darstellung zwar unverändert verwenden, aber wir möchten, dass unsere Tensoren etwas mehr über die semantische Bedeutung unserer Bilder aussagen. Um dies zu erreichen, können wir einen ähnlichen Ansatz wie für Text verwenden und große vortrainierte neuronale Netze nutzen.

Modelle, die auf massiven Klassifizierungsdatensätzen wie VGG (siehe den Artikel von A. Simonyan und A. Zimmerman, "Very Deep Convolutional Networks for Large-Scale Image Recognition") oder Inception (siehe den Artikel von C. Szegedy et al., "Going Deeper with Convolutions") auf dem ImageNet-Datensatz trainiert wurden, lernen schließlich sehr aussagekräftige Repräsentationen, um gut klassifizieren zu können. Diese Modelle folgen meist einer ähnlichen Struktur. Die Eingabe ist ein Bild, das viele aufeinanderfolgende Berechnungsschichten durchläuft, die jeweils eine andere Darstellung des Bildes erzeugen.

Schließlich wird die vorletzte Schicht an eine Funktion weitergegeben, die Klassifizierungswahrscheinlichkeiten für jede Klasse erzeugt. Diese vorletzte Schicht enthält also eine Darstellung des Bildes, die ausreicht, um zu klassifizieren, welches Objekt es enthält, was sie zu einer nützlichen Darstellung für andere Aufgaben macht.

An image is simply a tensor
Abbildung 4-7. Darstellung einer 3 als Matrix mit Werten von 0 bis 1 (nur der rote Kanal wird angezeigt)

Die Extraktion dieser Repräsentationsebene erweist sich bei der Erzeugung aussagekräftiger Vektoren für Bilder als äußerst effizient. Dazu ist außer dem Laden des trainierten Modells keine weitere Arbeit erforderlich. In Abbildung 4-8 stellt jedes Rechteck eine andere Schicht für eines dieser trainierten Modelle dar. Die nützlichste Darstellung ist hervorgehoben. Sie befindet sich in der Regel kurz vor der Klassifizierungsschicht, da diese das Bild am besten zusammenfassen muss, damit der Klassifizierer gut funktioniert.

Using a pre-trained model to vectorize images
Abbildung 4-8. Verwendung eines trainierten Modells zur Vektorisierung von Bildern

Die Verwendung von modernen Bibliotheken wie Keras macht diese Aufgabe viel einfacher. Hier ist eine Funktion, die Bilder aus einem Ordner lädt und in semantisch aussagekräftige Vektoren für die nachfolgende Analyse umwandelt, indem sie ein in Keras verfügbares, vortrainiertes Netzwerk verwendet:

import numpy as np

from keras.preprocessing import image
from keras.models import Model
from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input


def generate_features(image_paths):
    """
    Takes in an array of image paths
    Returns pretrained features for each image
    :param image_paths: array of image paths
    :return: array of last-layer activations,
    and mapping from array_index to file_path
    """

    images = np.zeros(shape=(len(image_paths), 224, 224, 3))

    # loading a  pretrained model
    pretrained_vgg16 = VGG16(weights='imagenet', include_top=True)

    # Using only the penultimate layer, to leverage learned features
    model = Model(inputs=pretrained_vgg16.input,
                  outputs=pretrained_vgg16.get_layer('fc2').output)

    # We load all our dataset in memory (works for small datasets)
    for i, f in enumerate(image_paths):
        img = image.load_img(f, target_size=(224, 224))
        x_raw = image.img_to_array(img)
        x_expand = np.expand_dims(x_raw, axis=0)
        images[i, :, :, :] = x_expand

    # Once we've loaded all our images, we pass them to our model
    inputs = preprocess_input(images)
    images_features = model.predict(inputs)
    return images_features

Sobald du eine vektorisierte Darstellung hast, kannst du sie clustern oder deine Daten an ein Modell weitergeben, aber du kannst sie auch nutzen, um deinen Datensatz effizienter zu untersuchen. Indem du Datenpunkte mit ähnlichen Darstellungen in Gruppen zusammenfasst, kannst du Trends in deinem Datensatz schneller erkennen. Wir sehen uns an, wie das geht.

Dimensionalitätsreduktion

Die Vektordarstellungen sind für Algorithmen notwendig, aber wir können diese Darstellungen auch nutzen, um Daten direkt zu visualisieren! Das mag schwierig erscheinen, denn die Vektoren, die wir beschrieben haben, haben oft mehr als zwei Dimensionen, was es schwierig macht, sie in einem Diagramm darzustellen. Wie könnten wir einen 14-dimensionalen Vektor darstellen?

Geoffrey Hinton, der für seine Arbeit im Bereich Deep Learning mit dem Turing Award ausgezeichnet wurde, würdigt dieses Problem in seinem Vortrag mit folgendem Tipp: "Um mit Hyperebenen in einem 14-dimensionalen Raum umzugehen, visualisiere einen 3D-Raum und sage sehr laut vierzehn zu dir selbst. Jeder macht das." (Siehe Folie 16 aus der Vorlesung von G. Hinton et al. "An Overview of the Main Types of Neural Network Architecture" hier.) Wenn dir das schwerfällt, wirst du dich über die Dimensionalitätsreduktion freuen. Dabei handelt es sich um die Technik, Vektoren in weniger Dimensionen darzustellen und dabei so viel wie möglich von ihrer Struktur zu bewahren.

Dimensionalität Reduktionstechniken wie t-SNE (siehe das Papier von L. van der Maaten und G. Hinton, PCA, "Visualizing Data Using t-SNE") und UMAP (siehe das Papier von L. McInnes et al, "UMAP: Uniform Manifold Approximation and Projection for Dimension Reduction") ermöglichen es dir, hochdimensionale Daten wie Vektoren, die Sätze, Bilder oder andere Merkmale darstellen, auf eine 2D-Ebene zu projizieren.

Diese Projektionen sind nützlich, um Muster in den Daten zu erkennen, die du dann untersuchen kannst. Sie sind jedoch nur eine ungefähre Darstellung der tatsächlichen Daten. Deshalb solltest du jede Hypothese, die du aus einer solchen Darstellung ableitest, mit anderen Methoden überprüfen. Wenn du Gruppen von Punkten siehst, die alle zu einer Klasse gehören und ein gemeinsames Merkmal zu haben scheinen, überprüfe zum Beispiel, ob dein Modell dieses Merkmal tatsächlich ausnutzt.

Für den Anfang solltest du deine Daten mit einem Verfahren zur Dimensionalitätsreduzierung darstellen und jeden Punkt nach einem Attribut einfärben, das du untersuchen möchtest. Bei Klassifizierungsaufgaben färbst du jeden Punkt anhand seines Labels ein. Bei unüberwachten Aufgaben kannst du die Punkte z. B. anhand der Werte bestimmter Merkmale einfärben, die du untersuchst. So kannst du sehen, ob bestimmte Regionen für dein Modell leicht oder schwer zu trennen sind.

Wir zeigen dir, wie du das mit UMAP ganz einfach machen kannst, indem du ihm die Einbettungen übergibst, die wir in "Vektorisieren" erstellt haben :

import umap

# Fit UMAP to our data, and return the transformed data
umap_emb = umap.UMAP().fit_transform(embeddings)

fig = plt.figure(figsize=(16, 10))
color_map = {
    True: '#ff7f0e',
    False:'#1f77b4'
}
plt.scatter(umap_emb[:, 0], umap_emb[:, 1],
            c=[color_map[x] for x in sent_labels],
            s=40, alpha=0.4)

Zur Erinnerung: Wir haben uns entschieden, zunächst nur Daten aus der Writer-Community von Stack Exchange zu verwenden. Das Ergebnis für diesen Datensatz ist in Abbildung 4-9 dargestellt. Auf den ersten Blick sehen wir einige Regionen, die wir untersuchen sollten, wie z. B. die dichte Region der unbeantworteten Fragen oben links. Wenn wir herausfinden können, welche Merkmale sie gemeinsam haben, entdecken wir vielleicht ein nützliches Klassifizierungsmerkmal.

Nachdem die Daten vektorisiert und geplottet wurden, ist es in der Regel eine gute Idee, systematisch Gruppen ähnlicher Datenpunkte zu identifizieren und sie zu untersuchen. Dazu können wir uns einfach UMAP-Diagramme ansehen, aber wir können auch das Clustering nutzen.

UMAP plot colored by whether a given question was successfully answered or not
Abbildung 4-9. UMAP-Diagramm, gefärbt danach, ob eine bestimmte Frage erfolgreich beantwortet wurde

Clustering

Wir haben bereits erwähnt, dass Clustering eine Methode ist, um Struktur aus Daten zu gewinnen. Egal, ob du Daten clusterst, um einen Datensatz zu untersuchen, oder ob du damit die Leistung eines Modells analysierst, wie wir es in Kapitel 5 tun werden, Clustering ist ein wichtiges Werkzeug in deinem Arsenal. Ich verwende das Clustering auf ähnliche Weise wie die Dimensionalitätsreduktion, als zusätzliche Möglichkeit, Probleme und interessante Datenpunkte aufzudecken.

Eine einfache Methode zum Clustern von Daten in der Praxis besteht darin, zunächst einige einfache Algorithmen wie k-means auszuprobieren und deren Hyperparameter wie die Anzahl der Cluster zu verändern, bis du eine zufriedenstellende Leistung erreichst.

Die Clustering-Leistung ist schwer zu quantifizieren. In der Praxis reicht eine Kombination aus Datenvisualisierung und Methoden wie der Ellbogenmethode oder einem Silhouettenplot für unseren Anwendungsfall aus, bei dem es nicht darum geht, unsere Daten perfekt zu trennen, sondern darum, Regionen zu identifizieren, in denen unser Modell Probleme haben könnte.

Im Folgenden findest du einen Beispielcode für das Clustering unseres Datensatzes und die Visualisierung unserer Cluster mithilfe einer Dimensionalitätstechnik, die wir bereits beschrieben haben: UMAP.

from sklearn.cluster import KMeans
import matplotlib.cm as cm

# Choose number of clusters and colormap
n_clusters=3
cmap = plt.get_cmap("Set2")

# Fit clustering algorithm to our vectorized features
clus = KMeans(n_clusters=n_clusters, random_state=10)
clusters = clus.fit_predict(vectorized_features)

# Plot the dimentionality reduced features on a 2D plane
plt.scatter(umap_features[:, 0], umap_features[:, 1],
            c=[cmap(x/n_clusters) for x in clusters], s=40, alpha=.4)
plt.title('UMAP projection of questions, colored by clusters', fontsize=14)

Wie du in Abbildung 4-10 sehen kannst, stimmt die Art und Weise, wie wir instinktiv die 2D-Darstellung clustern würden, nicht immer mit den Clustern überein, die unser Algorithmus in den vektorisierten Daten findet. Das kann an Artefakten in unserem Algorithmus zur Dimensionalitätsreduktion liegen oder an einer komplexen Datentopologie. Tatsächlich kann das Hinzufügen des einem Punkt zugewiesenen Clusters als Merkmal die Leistung eines Modells manchmal verbessern, indem es die Topologie nutzt.

Sobald du Cluster hast, untersuchst du jedes Cluster und versuchst, Trends in deinen Daten zu erkennen. Dazu wählst du einige Punkte pro Cluster aus und tust so, als ob du das Modell wärst, indem du die Punkte mit dem beschriftest, was deiner Meinung nach die richtige Antwort sein sollte. Im nächsten Abschnitt beschreibe ich, wie du diese Beschriftung vornimmst.

Visualizing our questions, colored by cluster
Abbildung 4-10. Visualisierung unserer Fragen, eingefärbt nach Clustern

Sei der Algorithmus

Sobald du dir die aggregierten Metriken und Cluster-Informationen angesehen hast, empfehle ich dir, den Ratschlag in "Monica Rogati: How to Choose and Prioritize ML Projects" zu befolgen und zu versuchen, die Arbeit deines Modells zu erledigen, indem du einige Datenpunkte in jedem Cluster mit den Ergebnissen beschriftest, die du dir von einem Modell erhoffst.

Wenn du noch nie versucht hast, die Arbeit deines Algorithmus zu machen, ist es schwer, die Qualität seiner Ergebnisse zu beurteilen. Wenn du hingegen einige Zeit damit verbringst, die Daten selbst zu beschriften, wirst du oft Trends erkennen, die deine Modellierungsaufgabe viel einfacher machen.

Diesen Ratschlag kennst du vielleicht aus dem vorherigen Abschnitt über Heuristiken, und er sollte dich nicht überraschen. Bei der Auswahl eines Modellierungsansatzes müssen wir fast genauso viele Annahmen über unsere Daten treffen wie bei der Erstellung von Heuristiken, daher ist es sinnvoll, dass diese Annahmen datenbasiert sind.

Du solltest Daten beschriften, auch wenn dein Datensatz Beschriftungen enthält. So kannst du überprüfen, ob deine Kennzeichnungen die richtigen Informationen erfassen und ob sie korrekt sind. In unserer Fallstudie verwenden wir die Punktzahl einer Frage als Maßstab für ihre Qualität, was ein schwaches Label ist. Indem wir selbst einige Beispiele beschriften, können wir die Annahme überprüfen, dass dieses Label angemessen ist.

Sobald du ein paar Beispiele beschriftet hast, kannst du deine Vektorisierungsstrategie aktualisieren, indem du alle Merkmale hinzufügst, die du entdeckst, um deine Datendarstellung so informativ wie möglich zu machen, und dann zur Beschriftung zurückkehren. Dies ist ein iterativer Prozess, wie in Abbildung 4-11 dargestellt.

The process of labeling data.
Abbildung 4-11. Der Prozess der Kennzeichnung von Daten

Um die Beschriftung zu beschleunigen, solltest du deine vorherige Analyse nutzen, indem du für jeden identifizierten Cluster und für jeden gemeinsamen Wert in deiner Merkmalsverteilung ein paar Datenpunkte beschriftest.

Eine Möglichkeit, dies zu tun, ist die Nutzung der Visualisierungsbibliotheken, um deine Daten interaktiv zu erkunden. Bokeh bietet die Möglichkeit, interaktive Diagramme zu erstellen. Eine schnelle Möglichkeit, Daten zu beschriften, ist, unsere vektorisierten Beispiele durchzugehen und für jedes Cluster ein paar Beispiele zu beschriften.

Abbildung 4-12 zeigt ein repräsentatives Einzelbeispiel aus einem Cluster mit überwiegend unbeantworteten Fragen. Die Fragen in dieser Gruppe waren meist recht vage und schwer objektiv zu beantworten und wurden nicht beantwortet. Diese Fragen werden als schlechte Fragen bezeichnet. Unter findest du den Quellcode für dieses Diagramm und ein Beispiel für seine Verwendung im ML-Editor. Navigiere zum Notebook "Exploring data to generate features" im GitHub-Repository dieses Buches.

Using Bokeh to inspect and label data
Abbildung 4-12. Bokeh zum Prüfen und Beschriften von Daten verwenden

Bei der Beschriftung von Daten kannst du wählen, ob du die Beschriftungen zusammen mit den Daten selbst (z. B. als zusätzliche Spalte in einem Datenrahmen) oder separat über eine Zuordnung von Datei oder Bezeichner zu Beschriftung speichern möchtest. Das ist eine reine Frage der Präferenz.

Wenn du Beispiele beschriftest, solltest du darauf achten, nach welchem Verfahren du deine Entscheidungen triffst. Das hilft dir dabei, Trends zu erkennen und Merkmale zu entwickeln, die dir bei deinen Modellen helfen.

Daten Trends

Nachdem du eine Zeit lang mit gelabelten Daten versorgt hast, wirst du in der Regel Trends erkennen. Einige davon können informativ sein (kurze Tweets sind in der Regel einfacher als positive oder negative zu klassifizieren) und dir helfen, nützliche Merkmale für deine Modelle zu entwickeln. Bei anderen kann es sich um irrelevante Korrelationen handeln, die auf die Art und Weise zurückzuführen sind, wie die Daten gesammelt wurden.

Vielleicht sind alle Tweets, die wir gesammelt haben und die auf Französisch sind, negativ, was dazu führen würde, dass ein Modell französische Tweets automatisch als negativ einstuft. Ich überlasse es dir zu entscheiden, wie ungenau das bei einer breiteren, repräsentativeren Stichprobe sein könnte.

Wenn du etwas in dieser Richtung bemerkst, verzweifle nicht! Solche Trends müssen unbedingt erkannt werden , bevor du mit der Erstellung von Modellen beginnst, denn sie würden die Genauigkeit der Trainingsdaten künstlich aufblähen und könnten dazu führen, dass du ein Modell in Produktion gibst, das nicht gut funktioniert.

Der beste Weg, mit solchen verzerrten Beispielen umzugehen, ist, zusätzliche Daten zu sammeln, um deine Trainingsdaten repräsentativer zu machen. Du könntest auch versuchen, diese Merkmale aus deinen Trainingsdaten zu eliminieren, um eine Verzerrung deines Modells zu vermeiden, aber das ist in der Praxis möglicherweise nicht effektiv, da Modelle häufig Verzerrungen aufgreifen, indem sie Korrelationen mit anderen Merkmalen nutzen (siehe Kapitel 8).

Sobald du einige Trends erkannt hast, ist es an der Zeit, sie zu nutzen. Meistens kannst du dies auf zwei Arten tun: indem du ein Merkmal erstellst, das diesen Trend charakterisiert, oder indem du ein Modell verwendest, das diesen Trend leicht nutzen kann.

Daten als Grundlage für Merkmale und Modelle nutzen

Wir möchten die Trends, die wir in den Daten entdecken, als Grundlage für unsere Datenverarbeitung, Merkmalsgenerierung und Modellierungsstrategie nutzen. Schauen wir uns zunächst an, wie wir Merkmale erzeugen können, die uns helfen, diese Trends zu erfassen.

Funktionen aus Mustern erstellen

Bei ML geht es darum, statistische Lernalgorithmen einzusetzen, um Muster in den Daten zu nutzen, aber manche Muster sind für Modelle leichter zu erfassen als andere. Man stelle sich das triviale Beispiel vor, einen Zahlenwert vorherzusagen, indem man den Wert selbst durch 2 geteilt als Merkmal verwendet. Das Modell müsste einfach lernen, mit 2 zu multiplizieren, um das Ziel perfekt vorherzusagen. Die Vorhersage des Aktienmarktes anhand historischer Daten ist dagegen ein Problem, das die Nutzung viel komplexerer Muster erfordert.

Deshalb besteht ein großer Teil der praktischen Vorteile von ML darin, zusätzliche Merkmale zu erzeugen, die unseren Modellen helfen, nützliche Muster zu erkennen. Wie leicht ein Modell Muster erkennen kann, hängt davon ab, wie wir die Daten darstellen und wie viele Daten wir haben. Je mehr Daten wir haben und je weniger verrauscht sie sind, desto weniger müssen wir uns mit dem Feature Engineering befassen.

Es ist jedoch oft sinnvoll, mit der Erstellung von Merkmalen zu beginnen. Erstens, weil wir in der Regel mit einem kleinen Datensatz beginnen, und zweitens, weil es uns hilft, unsere Überzeugungen über die Daten zu kodieren und unsere Modelle zu testen.

Saisonalität ist ein weit verbreiteter Trend, der von der Erstellung spezifischer Funktionen profitiert. Nehmen wir an, ein Online-Händler hat festgestellt, dass die meisten seiner Verkäufe an den letzten beiden Wochenenden des Monats stattfinden. Bei der Entwicklung eines Modells zur Vorhersage zukünftiger Verkäufe möchte er sicherstellen, dass es dieses Muster erfassen kann.

Wie du sehen wirst, kann die Aufgabe für die Modelle ziemlich schwierig sein, je nachdem, wie sie Daten darstellen. Die meisten Modelle können nur numerische Eingaben verarbeiten (siehe "Vektorisierung" für Methoden zur Umwandlung von Text und Bildern in numerische Eingaben), also schauen wir uns ein paar Möglichkeiten an, wie man Daten darstellen kann.

Rohdatenzeit

Die einfachste Art, Zeit darzustellen, ist die Unix-Zeit, die "die Anzahl der Sekunden, die seit 00:00:00 Uhr am Donnerstag, dem 1. Januar 1970, verstrichen sind", darstellt.

Diese Darstellung ist zwar einfach, aber unser Modell müsste einige ziemlich komplexe Muster lernen, um die letzten beiden Wochenenden des Monats zu erkennen. Das letzte Wochenende des Jahres 2018 zum Beispiel (von 00:00:00 Uhr am 29. bis 23:59:59 Uhr am 30. Dezember) wird in der Unix-Zeit als der Bereich von 1546041600 bis 1546214399 dargestellt (du kannst das überprüfen, wenn du die Differenz zwischen den beiden Zahlen nimmst, die in Sekunden gemessen ein Intervall von 23 Stunden, 59 Minuten und 59 Sekunden darstellt).

Nichts an dieser Spanne macht es besonders einfach, einen Bezug zu anderen Wochenenden in anderen Monaten herzustellen, so dass es für ein Modell ziemlich schwierig sein wird, relevante Wochenenden von anderen zu trennen, wenn es die Unix-Zeit als Eingabe verwendet. Wir können diese Aufgabe für ein Modell einfacher machen, indem wir Merkmale erzeugen.

Wochentag und Tag des Monats extrahieren

Eine Möglichkeit, unsere Datumsdarstellung übersichtlicher zu gestalten, wäre es, den Wochentag und den Tag des Monats in zwei separate Attribute aufzuteilen.

Wir würden zum Beispiel 23:59:59 am 30. Dezember 2018 mit der gleichen Zahl wie zuvor und zwei zusätzlichen Werten für den Wochentag (z.B. 0 für Sonntag) und den Tag des Monats (30) darstellen.

Diese Darstellung macht es unserem Modell leichter zu lernen, dass die Werte, die sich auf Wochenenden (0 und 6 für Sonntag und Samstag) und auf spätere Daten im Monat beziehen, einer höheren Aktivität entsprechen.

Es ist auch wichtig zu wissen, dass Repräsentationen oft zu Verzerrungen in unserem Modell führen. Wenn wir zum Beispiel den Wochentag als Zahl kodieren, ist die Kodierung für Freitag (gleich fünf) fünfmal größer als die für Montag (gleich eins). Diese numerische Skala ist ein Artefakt unserer Darstellung und repräsentiert nicht das, was unser Modell lernen soll.

Merkmal Kreuze

Während die vorherige Darstellung die Aufgabe für unsere Modelle erleichtert, müssten sie immer noch eine komplexe Beziehung zwischen dem Wochentag und dem Tag des Monats lernen: Hoher Verkehr findet nicht an Wochenenden am Anfang des Monats oder an Wochentagen am Ende des Monats statt.

Einige Modelle, wie z. B. tiefe neuronale Netze, nutzen nichtlineare Merkmalskombinationen und können so diese Zusammenhänge erkennen, benötigen aber oft eine große Menge an Daten. Eine gängige Methode, dieses Problem zu lösen, besteht darin, die Aufgabe noch einfacher zu machen und Merkmalskreuze einzuführen.

Ein Merkmalskreuz ist ein Merkmal, das einfach durch die Multiplikation (Kreuzung) von zwei oder mehr Merkmalen erzeugt wird. Durch die Einführung einer nichtlinearen Kombination von Merkmalen kann unser Modell leichter auf der Grundlage einer Kombination von Werten aus mehreren Merkmalen unterscheiden.

In Tabelle 4-5 kannst du sehen, wie jede der beschriebenen Darstellungen für ein paar Beispieldatenpunkte aussehen würde.

Tabelle 4-5. Wenn du deine Daten klarer darstellst, wird es für deine Algorithmen viel einfacher, gut zu funktionieren
Menschliche Darstellung Rohdaten (Unix datetime) Tag der Woche (DoW) Tag des Monats (DoM) Kreuz (DoW / DoM)

Samstag, 29. Dezember 2018, 00:00:00

1,546,041,600

7

29

174

Samstag, Dezember 29, 2018, 01:00:00

1,546,045,200

7

29

174

...

...

...

...

...

Sonntag, Dezember 30, 2018, 23:59:59

1,546,214,399

1

30

210

In Abbildung 4-13 kannst du sehen, wie sich diese Merkmalswerte mit der Zeit verändern und welche es einem Modell einfacher machen, bestimmte Datenpunkte von anderen zu trennen.

Last weekends of the month are easiest to separate using feature crosses and extracted features
Abbildung 4-13. Die letzten Wochenenden des Monats sind mit Hilfe von Merkmalskreuzen und extrahierten Merkmalen leichter zu trennen

Es gibt noch eine letzte Möglichkeit, unsere Daten darzustellen, die es unserem Modell noch einfacher macht, den Vorhersagewert der letzten beiden Wochenenden des Monats zu lernen.

Deinem Modell die Antwort geben

Es mag wie Betrug aussehen, aber wenn du genau weißt, dass eine bestimmte Kombination von Merkmalswerten besonders vorhersagekräftig ist, kannst du ein neues binäres Merkmal erstellen, das nur dann einen Wert ungleich Null annimmt, wenn diese Merkmale die entsprechende Kombination von Werten annehmen. In unserem Fall würde das zum Beispiel bedeuten, dass du ein Merkmal namens "is_last_two_weekends" hinzufügst, das nur an den letzten beiden Wochenenden des Monats den Wert Eins annimmt.

Wenn die letzten beiden Wochenenden so vorhersagekräftig sind, wie wir angenommen haben, wird das Modell einfach lernen, diese Eigenschaft zu nutzen und viel genauer sein. Wenn du ML-Produkte entwickelst, solltest du nie zögern, die Aufgabe für dein Modell einfacher zu machen. Es ist besser, ein Modell zu haben, das bei einer einfachen Aufgabe funktioniert, als eines, das sich mit einer komplexen Aufgabe abmüht.

Die Erstellung von Merkmalen ist ein weites Feld, und es gibt Methoden für die meisten Datentypen. Es würde den Rahmen dieses Buches sprengen, auf jedes Merkmal einzugehen, das für die verschiedenen Datentypen nützlich ist. Wenn du mehr praktische Beispiele und Methoden sehen möchtest, empfehle ich dir einen Blick in Feature Engineering for Machine Learning (O'Reilly) von Alice Zheng und Amanda Casari.

Generell ist der beste Weg, nützliche Merkmale zu erzeugen, wenn du dir deine Daten mit den beschriebenen Methoden ansiehst und dich fragst, wie du sie am einfachsten so darstellen kannst, dass dein Modell seine Muster lernt. Im folgenden Abschnitt beschreibe ich ein paar Beispiele für Merkmale, die ich mit diesem Verfahren für den ML Editor erstellt habe.

ML Editor Eigenschaften

Für haben wir mit unserem ML-Editor und den zuvor beschriebenen Techniken zur Untersuchung unseres Datensatzes (Details zur Untersuchung findest du im Notizbuch "Exploring data to generate features" im GitHub-Repository dieses Buches) die folgenden Merkmale erstellt:

  • Aktionsverben wie "kann" und " sollte" sagen voraus, dass eine Frage beantwortet wird. Deshalb haben wir einen binären Wert hinzugefügt, der prüft, ob sie in jeder Frage vorhanden sind.

  • Fragezeichen sind auch gute Prädiktoren, deshalb haben wir ein has_question Feature erstellt.

  • Fragen zum korrekten Gebrauch der englischen Sprache wurden oft nicht beantwortet, deshalb haben wir eine is_language_question Funktion hinzugefügt.

  • Die Länge des Fragentextes ist ein weiterer Faktor, denn sehr kurze Fragen werden tendenziell nicht beantwortet. Aus diesem Grund wurde eine Funktion zur Normalisierung der Fragelänge hinzugefügt.

  • In unserem Datensatz enthält auch der Titel der Frage wichtige Informationen, und die Betrachtung der Titel bei der Beschriftung erleichterte die Aufgabe erheblich. Dies führte dazu, dass wir den Titeltext in alle früheren Merkmalsberechnungen einbezogen haben.

Sobald wir einen ersten Satz von Merkmalen haben, können wir mit der Erstellung eines Modells beginnen. Der Aufbau dieses ersten Modells ist das Thema des nächsten Kapitels, Kapitel 5.

Bevor ich mich den Modellen zuwende, wollte ich tiefer in das Thema eintauchen, wie man einen Datensatz sammelt und aktualisiert. Zu diesem Zweck habe ich mich mit Robert Munro, einem Experten auf diesem Gebiet, zusammengesetzt. Ich hoffe, dass dir die Zusammenfassung unseres Gesprächs gefällt und dass du dich auf den nächsten Teil freuen kannst: die Erstellung unseres ersten Modells!

Robert Munro: Wie kannst du Daten finden, kennzeichnen und nutzen?

Robert Munro hat mehrere KI-Unternehmen gegründet und einige der besten Teams im Bereich der künstlichen Intelligenz aufgebaut. Er war Chief Technology Officer bei Figure Eight, einem führenden Unternehmen für Datenkennzeichnung, während dessen größter Wachstumsphase. Davor leitete er die Produktentwicklung für die ersten nativen AWS-Dienste für natürliche Sprachverarbeitung und maschinelle Übersetzung. In unserem Gespräch erzählt Robert, was er bei der Erstellung von Datensätzen für ML gelernt hat.

F: Wie fängst du mit einem ML-Projekt an?

A: Am besten fängst du mit dem Geschäftsproblem an, denn so bekommst du einen Rahmen, mit dem du arbeiten kannst. Bearbeitest du im Beispiel deines ML-Editors einen Text, den eine andere Person geschrieben hat, nachdem sie ihn abgeschickt hat, oder schlägst du Änderungen live vor, während jemand schreibt? Im ersten Fall könntest du die Anfragen mit einem langsameren Modell im Stapel verarbeiten, während im zweiten Fall etwas Schnelleres erforderlich wäre.

Was die Modelle betrifft, so würde der zweite Ansatz die Sequenz-zu-Sequenz-Modelle außer Kraft setzen, da sie zu langsam wären. Außerdem gehen Sequence-to-Sequence-Modelle heute nicht über Empfehlungen auf Satzebene hinaus und erfordern eine große Menge an Paralleltext, um trainiert zu werden. Eine schnellere Lösung wäre es, einen Klassifikator zu nutzen und die wichtigen Merkmale, die er extrahiert, als Vorschläge zu verwenden. Was du von diesem ersten Modell erwartest, ist eine einfache Implementierung und Ergebnisse, auf die du dich verlassen kannst.

Schließlich musst du dir einige Zeit nehmen, um Daten zu betrachten und sie selbst zu beschriften. So bekommst du ein Gespür dafür, wie schwer das Problem ist und welche Lösungen geeignet sind.

F: Wie viele Daten brauchst du, um loszulegen?

A: Wenn du Daten sammelst, musst du sicherstellen, dass du einen repräsentativen und vielfältigen Datensatz hast. Beginne damit, die vorhandenen Daten zu prüfen und festzustellen, ob bestimmte Typen nicht repräsentiert sind, damit du mehr Daten sammeln kannst. Um diesen Prozess zu beschleunigen, kann es hilfreich sein, deinen Datensatz zu clustern und nach Ausreißern zu suchen.

Bei der Kennzeichnung von Daten haben wir im allgemeinen Fall der Klassifizierung gesehen, dass eine Kennzeichnung in der Größenordnung von 1.000 Beispielen deiner selteneren Kategorie in der Praxis gut funktioniert. Dann erhältst du zumindest genug Signale, um zu entscheiden, ob du mit deinem aktuellen Modellierungsansatz weitermachen solltest. Bei etwa 10.000 Beispielen kannst du anfangen, auf das Vertrauen in die Modelle zu vertrauen, die du aufbaust.

Wenn du mehr Daten erhältst, steigt die Genauigkeit deines Modells langsam an und du erhältst eine Kurve, die zeigt, wie deine Leistung mit den Daten skaliert. Dabei ist für dich nur der letzte Teil der Kurve von Bedeutung, der dir eine Schätzung des aktuellen Werts gibt, den du mit mehr Daten erreichen kannst. In den allermeisten Fällen ist die Verbesserung, die du durch die Kennzeichnung weiterer Daten erhältst, größer, als wenn du das Modell iterierst.

F: Welches Verfahren wendest du an, um Daten zu sammeln und zu kennzeichnen?

A: Du kannst dir dein aktuell bestes Modell ansehen und herausfinden, was es stört. Uncertainty Sampling ist ein gängiger Ansatz: Finde die Beispiele, bei denen dein Modell am unsichersten ist (die, die am nächsten an seiner Entscheidungsgrenze liegen), und finde ähnliche Beispiele, die du der Trainingsmenge hinzufügen kannst.

Du kannst auch ein "Fehlermodell" trainieren, um mehr Daten zu finden, mit denen dein aktuelles Modell Schwierigkeiten hat. Verwende die Fehler, die dein Modell macht, als Markierungen (und kennzeichne jeden Datenpunkt als "richtig vorhergesagt" oder "falsch vorhergesagt"). Sobald du ein "Fehlermodell" auf diese Beispiele trainiert hast, kannst du es auf deine unmarkierten Daten anwenden und die Beispiele markieren, bei denen dein Modell fehlschlägt.

Alternativ kannst du auch ein "Beschriftungsmodell" trainieren, um die besten Beispiele für die nächste Beschriftung zu finden. Nehmen wir an, du hast eine Million Beispiele, von denen du nur 1.000 beschriftet hast. Du kannst eine Trainingsmenge mit 1.000 zufällig ausgewählten beschrifteten und 1.000 unbeschrifteten Bildern erstellen und einen binären Klassifikator trainieren, um vorherzusagen, welche Bilder du beschriftet hast. Dieses Modell kannst du dann verwenden, um die Datenpunkte zu identifizieren, die sich am stärksten von den bereits beschrifteten unterscheiden, und diese beschriften.

F: Wie kannst du überprüfen, ob deine Modelle etwas Nützliches lernen?

A: Ein häufiger Fallstrick ist, dass man sich bei der Kennzeichnung auf einen kleinen Teil des relevanten Datensatzes konzentriert. Es kann sein, dass dein Modell Probleme mit Artikeln über Basketball hat. Wenn du immer mehr Basketball-Artikel annotierst, kann es sein, dass dein Modell gut in Basketball, aber schlecht in allem anderen wird. Deshalb solltest du zwar Strategien zum Sammeln von Daten anwenden, aber auch immer eine Zufallsstichprobe aus deinem Testset ziehen, um dein Modell zu validieren.

Schließlich ist es am besten, wenn du verfolgst, wann die Leistung deines eingesetzten Modells abweicht. Du könntest die Unsicherheit des Modells verfolgen oder es idealerweise auf die Geschäftskennzahlen zurückführen: Gehen deine Nutzungskennzahlen allmählich zurück? Das kann auch andere Ursachen haben, ist aber ein guter Anlass, um die Situation zu untersuchen und eventuell dein Trainingsset zu aktualisieren.

Fazit

In diesem Kapitel haben wir wichtige Tipps gegeben, um einen Datensatz effizient und effektiv zu untersuchen.

Zunächst haben wir uns mit der Qualität der Daten befasst und wie wir entscheiden können, ob sie für unsere Bedürfnisse ausreichend sind. Als Nächstes haben wir besprochen, wie du dich am besten mit deinen Daten vertraut machen kannst: Wir haben mit zusammenfassenden Statistiken begonnen und sind dann zu Clustern ähnlicher Punkte übergegangen, um allgemeine Trends zu erkennen.

Dann haben wir besprochen, warum es wichtig ist, viel Zeit mit der Kennzeichnung von Daten zu verbringen, um Trends zu erkennen, die wir dann zur Entwicklung wertvoller Funktionen nutzen können. Zum Schluss konnten wir von Robert Munros Erfahrung lernen, wie er mehreren Teams hilft, moderne Datensätze für ML zu erstellen.

Nachdem wir nun einen Datensatz untersucht und Merkmale erstellt haben, von denen wir hoffen, dass sie vorhersagbar sind, können wir unser erstes Modell erstellen, was wir in Kapitel 5 tun werden.

Get Aufbau von Anwendungen mit maschinellem Lernen now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.