Machine Learning

Feature Engineering

Alle Machine Learning Algorithmen arbeiten auf Vektor-basierten Daten $x \in \mathbb{R}^n$.

Was, wenn unsere Ausgangsdaten keine Vektoren sind?

Beispiel: Wir wollen einen Spam Classifier bauen.

From: BILL GATES FOUNDATION <al8622787@gmail.com>
Subject: HELLO
Reply me urgently i have a very important Donation to share with you.
Have A Blessed Day
Regards
Mr. Bill Gates Foundation

Text Vectorization

Ansatz: Buchstaben → Zahlen

"Hallo Welt" → $[8,1,12,12,15,0,23,5,12,20]$

Nachteile

  • Vektoren haben Variable Länge
  • Einzelne Buchstaben haben wenig Information

Ansatz: Wörter zählen

Für jedes Wort im Text wollen wir wissen, wie oft es vorkommt.

"John likes to watch movies. Mary likes movies too."
→ {"John":1,"likes":2,"to":1,"watch":1, "movies":2,"Mary":1,"too":1}

Um diesen "bag of words" in Vektorform zu bringen, müssen wir jedem Wort einen Vektor Index zuordnen.

"John" 0
"likes" 1
"to" 2
"watch" 3
"movies" 4
"Mary" 5
"too" 6

"John likes to watch movies" → $[1, 1, 1, 1, 1, 0, 0]$

"Mary likes movies too" → $[0, 1, 0, 0, 1, 1, 1]$

Um Speicher zu sparen, können wir uns auf die häufigsten n Worte beschränken

Oder auf Wörter, die mindestens (oder höchstens) in x% der Dokumente vorkommen

    Vorteile "bag of words" Modell:

  • Sehr simpel
  • Oft hinreichend mächtig
  • Nachteile

  • Brauchen Wörterbuch mit Indizes
  • Ignoriert Kontext

    "Mary likes John" = "John likes Mary"

  • Wortverwandtschaften werden ignoriert

    "movie" ≠ "movies"

Um Wortverwandtschaften besser zu finden kann ein Stemmer verwendet werden:
"running" → "run"

Z.B.: NLTK

Wie kodieren wir Strings, die keine sinnvollen Wörter sind?

From: BILL GATES FOUNDATION <al8622787@gmail.com>

Ansatz: Zähle nicht Wörter, sondern N-Gramme

3 Gramme: "example@th-bingen.de"
→ "exa", "xam", "amp", "mpl", ...

Zum Beispiel: Dictionary für die 10000 häufigsten 3-Gramme

Es gibt 17576 3-Gramme der 26 Kleinbuchstaben und 456976 4-Gramme.

Oft macht es Sinn Großbuchstaben auf Kleinbuchstaben zu mappen.

Zu großes N bei den N-Grammen ist oft schädlich

Wort N-Gramme sind auch möglich (so bleibt mehr Kontext erhalten)

2 Gramme: "Reply me urgently i have a very important"
→ "Reply me", "me urgently", "urgently i", "i have", ...

Bei Strings als Input Daten kommt es oft sehr auf das Problem an.

Beispiel: "Berlinstraße 109, 55411 Bingen"

Stadt Bingen One-hot oder Hashing Trick
PLZ 55411 Buckets oder Hashing Trick
Straße Berlinstraße Hashing Trick
Hausnummer 109 Auf 0-1 skalieren

In sklearn: CountVectorizer

Eine verbesserte Zählweise ist term frequency-inverse document frequency (TF-IDF):

\[ \operatorname{tf}(t, x) = \frac{\text{Wie oft kommt } t \text{ in } x \text{ vor}}{\text{Anzahl Worte in } x} \]

\[ \operatorname{idf}(t) = \log(\frac{m}{\text{Anzahl Dokumente, die } t \text{ enthalten}}) \]

\[ \operatorname{tfidf}(t,x) = \operatorname{tf}(t, x) \cdot \operatorname{idf}(t) \]

In sklearn: TfidfVectorizer

Ein Nachteil ist, dass wir immer ein Dictionary mitschleppen müssen.

Wie entscheiden wir, wenn ein neues Wort ein anderes im Dictionary ersetzen soll?

Hashing Trick

Wir brauchen eine Hash Funktion
$\operatorname{hash}(t) \to \{0, 1, 2, \ldots, n-1\}$.

  • Starte mit Null Vektor $x = [0,0, \ldots, 0]$
  • Für jeden Term $t$ im Input:
    • $x^{(\operatorname{hash}(t))} \gets x^{(\operatorname{hash}(t))} + 1$

    Vorteile

  • Kein Dictionary
  • Kein Problem mit neuen Worten
  • Nachteile

  • Feature schwieriger zu interpretieren
  • Hash Kollisionen

In sklearn: HashingVectorizer

Umgang mit Bilddaten

Beispiel: Handschrifterkennung:

Ein Graustufen Bild entspricht einem 2D Array mit Größe $M \times N$.

Jeder Eintrag enspricht einem Pixel und gibt die Intensität wieder.

Ein Farbbild hat noch eine Dimension mehr für den Farbkanal ($M \times N \times C$).

$C$ ist entweder 3 (RGB) oder 4 (RGBA).


          import cv2
          img = cv2.imread('image.png')
        

oder


          import cv2
          img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)
        

Unsere Input Vektoren müssen meistens die gleiche, konstante Größe haben.

Skaliere alle Bilder auf die gleiche Größe


          resized = cv2.resize(img, (200, 200))
          reshaped = resized.reshape([200 * 200 * 3])
        

One-hot Encoding von kategorische Daten:

Eine Dimension für jede Kategorie

Beispiel: Wochentag

$ x \in \{\text{Montag}, \text{Dienstag}, \text{Mittwoch},\\ \text{Donnerstag}, \text{Freitag}, \text{Samstag}, \text{Sonntag}\}$

\[ \phi(\text{"Mittwoch"}) = \left[ {\begin{array}{c} 0 \\ 0 \\ 1 \\ 0 \\ 0 \\ 0 \\ 0 \end{array}} \right] \]

In sklearn: OneHotEncoder

Können wir hier mit logistischer Regression einen sinnvollen Classifier bauen?

Eindimensionale Variante:

Ansatz: Quadratische Features

\[ \phi(x) = \left[ {\begin{array}{c} x \\ x^2 \end{array}} \right] \]

Analog für mehr Dimensionen:

\[ x = \left[ {\begin{array}{c} x^{(1)} \\ x^{(2)} \\ \vdots \\ x^{(n)} \end{array}} \right] \quad \phi(x) = \left[ {\begin{array}{c} 1 \\ x^{(1)} \\ x^{(2)} \\ \vdots \\ x^{(n)} \\ x^{(1)} x^{(1)} \\ x^{(1)} x^{(2)} \\ \vdots \\ x^{(1)} x^{(n)} \\ \vdots \\ x^{(n)} x^{(n)} \end{array}} \right] \]

Neue Dimension: $x^{(1)} x^{(1)} + x^{(2)} x^{(2)}$

https://commons.wikimedia.org/wiki/File:Kernel_trick_idea.svg

Achtung: Bei $n$ Eingangs Features und Grad $d$ bekommen wir $O(n^d)$ polynomiale Features

In sklearn: PolynomialFeatures

Viele Algorithmen gehen davon aus / funktionieren besser, wenn die Feature Mittelwert 0 und Standard Abweichung 1 haben.

\[ \phi(x) = \frac{x - \mu}{\sigma} \]

$\mu$ ist der Mittelwert der Trainingsdaten
$\sigma$ ist die Standardabweichung der Trainingsdaten

Achtung: Feature, die one-hot encoded oder sehr dünn besetzt sind, sollten nicht noch skaliert werden

Bag of words Modelle können dann nicht mehr mit sparsen Vektoren gespeichert werden.

Erst skalieren, dann polynomielle Features bilden.

In sklearn: StandardScaler

Ignorieren von Outliern: RobustScaler

Weitere Feature Transformer: sklearn.preprocessing

Als Daumenregel wollen wir:

  • Binäre Features
  • Features mit Mittelwert 0 und Varianz 1
  • Features in ähnlicher Größenordnung
  • wenige Features, die gut mit der Ausgabegröße korrelieren

Von den Eingangsfeatures bis zur Vorhersage kann ein ML System recht komplex werden

  • In Produktion muss das ganze System genauso deployed werden, wie es trainiert wurde.
  • Wir wollen das System weiterentwickeln und leicht modifizieren können.

Sklearn hat hierfür das Konzept von Pipelines

  • Enthält alle Schritte von rohen Features bis zur Vorhersage.
  • Kann als eine Einheit serializiert (gepickled) werden.

Meta Daten

Wenn wir ein ML System speicher, sollten wir immer auch mindestens folgende Informationen dazu speichern:

  • Verwendetes Modell
  • Hyperparameter
  • Trainingszeitpunkt / Datum
  • Performance auf Trainings- / Testset
  • Verwendetes Trainings- / Testset
  • Code Version (semantic versioning)

Jupyter