1
0
Files
ANN-route-predition/experiments/ML Example.ipynb

1.3 MiB
Raw Blame History

image.png

Kurzfassung

Das Spritzgießen ist ein häufig in der Kunststoffverarbeitung eingesetztes Verfahren und ist deshalb von großer ökologischer und ökonomischer Bedeutung. Ziel dieser Arbeit war es, die üblicherweise von Spritzgussmaschinen bereitgestellten Daten zu nutzen, um Fehlteile also Teile mit unzulässigen Qualitätsmängeln unmittelbar zu erkennen und damit aussortieren zu können. Es hat sich gezeigt, dass dies für die untersuchten Qualitätsmängel mit einer Genauigkeit von 98,0 - 99,0 % unter Anwendung linearer Machine-Learning-Modelle möglich ist. Darüber hinaus konnte gezeigt werden, dass durch die Auswahl repräsentativer Datenpunkte der dafür erforderliche Aufwand beim Labeling auf einen Bruchteil des ursprünglichen Aufwands reduziert werden kann. Diese repräsentative Auswahl erfolgte auf der Basis unüberwachter Clustering-Algorithmen.

Inhaltsverzeichnis

  1. Einleitung
  2. Vorbereitung
  3. Einführung des vorliegenden Datensatzes
  4. Klassifizierung anhand eines Merkmals
  5. Klassifizierung anhand mehrerer Merkmale
  6. Teilüberwachtes Lernen
  7. Ergebnisse und Evaluation
  8. Ausblick

1. Einleitung

Das Spritzgießen ist ein Verfahren aus der Kunststoffverarbeitung, um Rohmaterial (Kunststoffgranulat) in eine gewünschte Form zu bringen (sog. Urformverfahren). Technisch handelt es sich dabei um einen komplexen Prozess, dessen Resultat von zahlreichen Variablen abhängt. Aus diesem Grund kommt es hin und wieder vor, dass die gespritzten Teile nicht den Qualitätsstandards eines Herstellers entsprechen und aussortiert werden müssen.

Ziel der vorliegenden Arbeit ist es, diese fehlerhaften Teile anhand der internen Messwerte der Spritzgussmaschine (sog. Prozessdaten) automatisch auszusortieren. Grundlage dafür ist ein Datensatz, welcher in einer vorherigen Hausarbeit [1] erarbeitet wurde. Im Zuge dessen sollen auch Pipelines erarbeitet und Methoden gefunden werden, sodass eine Übertragung der Ergebnisse auf andere Fehler und Produkte erleichtert wird.

Motiviert wird diese Zielsetzung aus verschiedenen Richtungen. Die untersuchten Produkte werden nach ihrer Fertigung vollautomatisch weiterverarbeitet und gehen anschließend direkt in den Verkauf. Es existiert bisher kein System, welches fehlerhafte Teile automatisch aussortiert. Aufgrund der vollautomatischen Abläufe fallen diese Teile auch den Mitarbeitern nicht immer auf und erreichen somit teilweise den Endkunden. Dies sorgt für Unzufriedenheit und unter Umständen einen Imageschaden. Außerdem entsteht sowohl beim Kunden als auch Hersteller ein Mehraufwand für den Austausch des Produkts. Hinzu kommt die zeitliche Verzögerung für den Endkunden.

Des Weiteren sind fehlerhafte und damit unbrauchbare Teile für ein Unternehmen sowohl aus ökologischer als auch ökonomischer Sicht zu vermeiden. Insbesondere für die Fertigungsplanung ist es außerdem wichtig, fehlerhafte Teile unmittelbar zu erkennen, damit die geplante Anzahl an (fehlerfreien) Teilen produziert werden kann.

Im nachfolgenden Kapitel 3 wird zunächst der vorliegende Datensatz eingeführt. Der Hauptteil beginnt in Kapitel 4 mit dem Versuch, den Datensatz anhand eines einzigen Merkmals linear zu separieren. Im anschließenden Kapitel 5 werden komplexerere Algorithmen untersucht, welche mehrere Merkmale gleichzeitig berücksichtigen können.

Kapitel 6 konzentriert sich darauf, wie die Berücksichtigung weiterer Fehler und Produkte vereinfacht werden kann. Dazu wird der Ansatz des teilüberwachten Lernens verfolgt. Dieser erfordert zunächst eine Dimensionsreduktion der Daten. Anschließend können mit Hilfe von Clustering-Algorithmen repräsentative Datenpunkte ausgewählt und gelabelt werden. Zum Abschluss wird die Qualität der Klassifikatoren untersucht, welche auf daraus resultierenden Daten trainiert wurden.

Im Schlussteil der Arbeit werden die Ergebnisse zusammengefasst und kritisch bewertet. Außerdem wird ein Ausblick gegeben.

2. Vorbereitung

Zunächst müssen einige allgemeine Vorbereitungen getroffen werden, um nachfolgend die Daten verarbeiten zu können. Grundlage dieser Arbeit bildet die Programmiersprache Python und insb. die Module Numpy, Pandas, SciKit-Learn sowie Matplotlib.

In [1]:
# Kontrolle der Python-Version
import sys

assert sys.version_info >= (3, 5)

# Import von Scikit-Learn und Kontrolle der Version
import sklearn

assert sklearn.__version__ >= "0.20"

# Weitere Imports
import pandas as pd
import numpy as np
import os

# Imports und Einstellungen um Abbildungen mit matplotlib erzeugen und im
# Notebook darstellen zu können
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt

mpl.rc("axes", labelsize=14)
mpl.rc("xtick", labelsize=12)
mpl.rc("ytick", labelsize=12)

# Dictionary zur Abspeicherung der Zwischenergebnisse für den Ergebnis-Teil
results = []

Damit die Ausgaben des Notebooks vergleichbar sind wird außerdem der entsprechende Seed gesetzt.

In [2]:
np.random.seed(42)

Im nächsten Schritt kann der Datensatz eingelesen werden. Dieser kann entweder im aktuellen Verzeichnis liegen oder über einen entsprechenden Link aus Google Drive geladen werden.

In [3]:
# Datei via Link aus Google Drive laden
# Alternativ können Sie die Datei 'df.pkl' auch manuell dem aktuellen Unterordner
# hinzufügen
!gdown --id 1r5OzQmxj2TIZUMm3UwKOA-9znGQoe31j

# Daten einlesen
import pickle

with open("df.pkl", "rb") as file:
    df = pickle.load(file)

# Kontrolle
assert len(df.columns) == 107
assert len(df.index) == 4548
print("Anzahl Spalten:", len(df.columns))
print("Anzahl Zeilen:", len(df.index))
Downloading...
From: https://drive.google.com/uc?id=1r5OzQmxj2TIZUMm3UwKOA-9znGQoe31j
To: /content/df.pkl

0.00B [00:00, ?B/s]
3.91MB [00:00, 61.7MB/s]
Anzahl Spalten: 107
Anzahl Zeilen: 4548

3. Einführung des vorliegenden Datensatzes

3.1 Überblick

Wie bereits in der Einleitung erwähnt, wird in dieser Arbeit ein Datensatz untersucht, welcher in einer vorherigen Hausarbeit [1] erarbeitet wurde. Er umfasst die nachfolgende Anzahl an Datenpunkten, Merkmalen und Zielwerten:

In [4]:
print("Übersicht")
print("- Anzahl Datenpunkte:", len(df.index) - 1)
print("- Anzahl Merkmale:", len(df.drop(["Labels"], axis=1).columns))
print("- Anzahl Zielwerte:", len(df["Labels"].columns))
Übersicht
- Anzahl Datenpunkte: 4547
- Anzahl Merkmale: 104
- Anzahl Zielwerte: 3

Jeder Datenpunkt beschreibt ein gespritztes Teil. Konkret handelt es sich dabei um das Unterteil des Kabelabzweigkastens DK 0200 G der Gustav Hensel GmbH & Co. KG. Abbildung 1 zeigt ein Exemplar:

_Abbildung 1 - DK 0200 G.jpg

Abbildung 1: DK 0200 G nach [2]

Die nachfolgende Abbildung 2 zeigt exemplarisch ein Fotos eines fehlerfreien DK 0200 G.

Exemplarisches Gutteil.jpg

Abbildung 2: Foto eines fehlerfreien DK 0200 G

3.2 Merkmale

Da moderne Spritzgussmaschinen eine Vielzahl an Daten bereitstellen, wird jeder Datenpunkt durch mehr als 100 Merkmale beschrieben. Es wurde bewusst darauf verzichtet, auf Grundlage domänenspezifischen Wissens bereits vorab Merkmale auszusortieren. Es wird zunächst davon ausgegangen, dass sämtliche Merkmale potenziell relevant sind.

Alle Merkmale im Detail zu beschreiben wäre nicht zielführend. Stattdessen wird auf die relevanten Merkmale an den entsprechenden Stelle der Arbeit eingegangen. Für das Arbeiten mit einer solchen Vielzahl an Merkmalen ist jedoch eine Gruppierung hilfreich. Diese kann auf Grundlage des Fertigungsprozesses erfolgen. Der DK 0200 G wird aus zwei Komponenten also zwei unterschiedlichen Kunststoffen gespritzt. Zunächst wird der Grundkörper aus Polypropylen gespritzt. In einem zweiten Fertigungsschritt werden die Membranen zur Einführung von Kabeln aus TPE (Thermoplastischen Elastomeren) ergänzt. Beide Fertigungsschritte laufen prinzipiell ähnlich ab und werden deshalb durch dieselben Merkmale beschrieben. Insgesamt ergeben sich die nachfolgenden Gruppen an Merkmalen:

  1. Internal: komponentenunabhängige Messwerte der Spritzgussmaschine (z.B. Zykluszeit)

  2. Internal_C1: Messwerte der Spritzgussmaschine an Komponente 1 (z.B. Einspritzvolumen)

  3. Internal_C2: Messwerte der Spritzgussmaschine an Komponente 2 (z.B. Einspritzvolumen)

  4. External: Messwerte externer Sensoren (z.B. Umgebungstemperatur)

  5. Time related: Abgeleitete Merkmale aus den Zeitstempeln der Teile (z.B. Zeit seit letzter Wartung)

Für eine detaillierte Beschreibung des Spritzgussprozesses und der einzelnen Merkmale siehe [1]. Die Merkmale teilen sich folgendermaßen auf die Gruppen auf:

In [5]:
# Im DataFrame wurde diese Gruppierung mit Hilfe eines MultiIndex umgesetzt
pd.DataFrame(df.drop(["Labels"], axis=1).droplevel(1, axis=1).columns).value_counts()
Out[5]:
Group       
Internal        59
Internal_C2     21
Internal_C1     20
Time related     2
External         2
dtype: int64

Die meisten Merkmale sind interne Messwerte der Spritzgussmaschine, wobei jeweils ca. 20 % einer einzelnen Komponente zugeordnet werden können. Um die Daten nachfolgend einheitlich darzustellen, ist es sinnvoll, zunächst eine entsprechende Funktion zu definieren:

In [6]:
def formatForPlotting(df):
    for number in range(10):
        df.columns = df.columns.str.replace(r" " + str(number), "_" + str(number))
    return df

Die ersten Daten der Gruppe Internal sehen dann bspw. so aus:

In [7]:
formatForPlotting(df["Internal"]).head(3)
Out[7]:
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
Name Ausschuss total [ASZ] Ausschussursache [ASU] Düse [H27x] Düse [H2x] Düse [Pakt_27] Entformzeit [ZEx] Flansch_1 [H28x] Flansch_1 [Pakt_28] Flansch_2 [H29x] Flansch_2 [Pakt_29] Formschutzzeit Istwert [ZFx] Formöffnungshub Spitzenwert [SFs] Schließkraft Spitzenwert [SKs] Schließkraft gespeichert [SKg] Schuss Gutteile [SZGx] Schusszähler Istwert [SZx] Stillstandszeit vor Zyklusstart [ZUaxs] Traverse [H34x] Traverse [H6x] Traverse [Pakt_34] Traverse [Pakt_6] Trockenlauf [ZDry] Werkzeug_1 [H7x] Werkzeug_1 [Pakt_7] Werkzeug_2 [H8x] Werkzeug_2 [Pakt_8] Werkzeug_3 [H9x] Werkzeug_3 [Pakt_9] Werkzeug_4 [H13x] Werkzeug_4 [Pakt_13] Werkzeug_5 [H14x] Werkzeug_5 [Pakt_14] Werkzeug_6 [H15x] Werkzeug_6 [Pakt_15] Werkzeug_7 [H16x] Werkzeug_7 [Pakt_16] Werkzeug_8 [H17x] Werkzeug_8 [Pakt_17] Werkzeug_9 [H18x] Werkzeug_9 [Pakt_18] Zeit Schließkraftaufbau [ZSKa] Zyklus Kühlzeit [Z4x] Zykluszeit Formschließen [ZSchl] Zykluszeit Formöffnen [ZOeff] Zykluszeit Schließen [ZEsch] Zykluszeit bis Ende Entformen [ZUs] Zykluszeit Öffnen [ZEoef] Zylinderzone keramisch_1 [H30x] Zylinderzone keramisch_1 [H3x] Zylinderzone keramisch_1 [Pakt_30] Zylinderzone keramisch_1 [Pakt_3] Zylinderzone keramisch_2 [H31x] Zylinderzone keramisch_2 [H4x] Zylinderzone keramisch_2 [Pakt_31] Zylinderzone keramisch_2 [Pakt_4] Zylinderzone keramisch_3 [H32x] Zylinderzone keramisch_3 [H5x] Zylinderzone keramisch_3 [Pakt_32] Zylinderzone keramisch_3 [Pakt_5]
2021-01-07 17:38:11 73.0 - 214.9 219.9 13.1 10.77 215.0 31.2 210.0 36.3 0.94 575.1 1222.7 1214.3 18489.0 18562.0 0.0 35.4 39.8 -100.0 0.0 4.06 215.0 8.9 215.0 16.8 215.0 21.1 200.0 13.4 199.9 13.8 199.5 15.2 199.5 16.6 220.9 22.4 200.0 20.6 0.76 19.01 2.58 4.27 1.8 36.06 1.48 200.1 219.9 2.4 5.1 185.0 209.9 2.5 5.6 170.0 199.9 7.4 15.1
2021-01-07 17:38:47 73.0 - 214.9 220.1 13.0 10.82 215.0 31.2 210.1 37.1 0.94 575.0 1221.8 1213.2 18490.0 18563.0 0.0 35.4 40.0 -100.0 0.0 4.06 215.0 9.1 215.0 16.5 215.0 20.9 200.0 15.7 199.7 12.6 199.5 17.5 199.5 15.0 221.0 22.7 200.0 16.2 0.76 19.01 2.59 4.25 1.8 36.04 1.48 200.0 219.9 2.3 4.5 185.0 210.1 3.0 3.9 170.0 200.1 8.0 14.6
2021-01-07 17:39:23 73.0 - 215.0 219.9 12.2 10.78 214.8 37.4 209.9 40.6 0.94 575.1 1222.7 1214.0 18491.0 18564.0 0.0 35.3 40.0 -100.0 -100.0 4.06 215.0 10.0 215.0 18.5 214.9 27.1 200.0 15.7 199.6 14.6 199.4 17.6 199.4 17.3 220.9 23.6 200.0 16.2 0.76 19.01 2.59 4.26 1.8 36.06 1.48 200.0 220.1 2.0 1.4 185.0 210.2 3.2 3.7 170.0 200.2 7.7 14.2

Die Merkmale der Gruppe Internal_C1 sind wie bereits erwähnt ähnlich der Gruppe Internal_C2 und sehen so aus:

In [8]:
formatForPlotting(df["Internal_C1"]).head(3)
Out[8]:
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
Name Dosierleistung [iwdls_1] Dosiervolumen Istwert [ASSx_1] Dosierzeit Istwert [ZDx_1] Drehmoment Mittelwert laufender Zyklus [Mm_1] Drehmoment Spitzenwert laufender Zyklus [Ms_1] Drehzahl Spitzenwert [DZs_1] Einspritzarbeit [EA_1] Integral Überwachung_1 Micrograph [IDKi1_Mic_1] Massepolster Ende Nachdruck [ACPv_1] Massepolster kleinster Wert [ACPx_1] Massepolster nach Nachdruck [ACPn_1] Schussvolumen [Svo_1] Spezifischer Druck beim Umschalten [APHu_1] Spezifischer Einspritzdruck Spitzenwert [APVs_1] Spezifischer Nachdruck Spitzenwert [APNs_1] Spezifischer Staudruck Spitzenwert [APSs_1] Spritzzeit Istwert [ZSx_1] Umschaltvolumen [AC3u_1] Zykluszeit Düse vor [ZDvo_1] Zykluszeit Nachdruck [ZNach_1]
2021-01-07 17:38:11 7.01 70.68 7.40 166.5 177.0 0.294 1.002 50534.37 6.01 4.32 6.23 62.77 511.5 875.3 620.9 94.0 1.21 12.49 1.15 2.0
2021-01-07 17:38:47 6.80 70.61 7.65 163.5 175.5 0.294 0.994 50484.74 5.60 3.92 5.81 63.19 503.0 877.6 611.2 93.3 1.21 12.49 1.16 2.0
2021-01-07 17:39:23 6.82 70.61 7.69 165.6 177.6 0.294 1.003 50598.79 5.91 4.21 6.11 62.89 508.2 884.4 618.1 93.3 1.21 12.49 1.15 2.0

Die restlichen Merkmale werden nachfolgend bei Bedarf dargestellt.

3.3 Zielwerte

Der Datensatz ist gelabelt und umfasst somit Zielwerte:

In [9]:
# Die Zielwerte bilden eine eigene Gruppe im MultiIndex
formatForPlotting(df["Labels"]["2021-01-13 17"]).head(3)
Out[9]:
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
Name 0_leak_corner_tl 0_leak_corner_tr 1_hole_bottom
2021-01-13 17:00:28 2 3 0
2021-01-13 17:01:04 1 3 0
2021-01-13 17:01:40 1 3 0

Jedes Label beschreibt einen Fehler, welcher im beobachteten Zeitraum aufgetreten ist. Die nachfolgende Abbildung 3 zeigt ein Teil, welches alle diese Fehler gleichzeitig aufweist. Dies muss nicht zwingend der Fall sein.

![Exemplarisches Schlechtteil - markiert - Kopie.jpg](data:image/jpeg;base64,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)

Abbildung 3: Beobachtete Fehler am DK 0200 G

Die Fehler 0_leak_corner_tl und 0_leak_corner_tr sind links bzw. rechts oben zu sehen. An diesen Stellen wird zu viel Material der Komponente 2 (TPE) in das Innere des Gehäuses gesprizt. Der Fehler 1_hole_bottom ist unten zu beobachten: Hier fehlt das entsprechende Material. Die Häufigkeit dieser Fehler ist sehr unterschiedlich:

In [10]:
print("Anzahl Datenpunkte:", len(df))
print("Anzahl Fehler:")
# Wenn der Wert einer Zielvariable nicht 0 ist lag ein Fehler vor
print(df["Labels"].astype(bool).sum(axis=0))
# Quelle: https://stackoverflow.com/questions/26053849/counting-non-zero-values-in-each-column-of-a-dataframe-in-python
Anzahl Datenpunkte: 4548
Anzahl Fehler:
Name
0_leak_corner_tl    2103
0_leak_corner_tr    2138
1_hole_bottom          5
dtype: int64

*) Anmerkung: Diese Zahlen wirken auf den ersten Blick sehr hoch. Allerdings wurde, um einen vollständigen Datensatz zu erhalten, jegliche Abweichung vom Optimum als Fehler eingestuft. Dem Endkunden würden diese in der Regel nicht auffallen. Außerdem wurde bewusst ein extrem fehlerlastiger Zeitraum gewählt. In anderen Zeiträumen treten wochenlang quasi gar keine Fehler auf. Bei diesen hohen Zahlen handelt es sich deshalb wahrscheinlich um einen zumindest im Sinne dieser Arbeit "glücklichen" Zufall.

Die Fehler 0_leak_corner_tl und 0_leak_corner_tr sind mit Abstand am häufigsten aufgetreten und stehen deshalb im Fokus dieser Arbeit. Im Datensatz werden die Fehler als eine Ganzzahl zwischen 0 bis 3 codiert. Die Zahlen haben nachfolgende Bedeutungen:

  • 0: kein Fehler
  • 1: schwacher Fehler
  • 2: mittlerer Fehler
  • 3: starker Fehler

Für eine exakte Beschreibung, wie diese Einteilung erfolgt ist, siehe [1].

In der Regel lag entweder kein Fehler vor oder dieser war sehr stark:

In [11]:
def plotLabelHist(labels):
    fig, ax = plt.subplots()

    # Daten
    bins = [0 - 0.5, 1 - 0.5, 2 - 0.5, 3 - 0.5, 4 - 0.5]
    ax.hist(labels.to_numpy(), bins=bins, label=labels.columns, edgecolor="black")

    # Achsen
    plt.xlabel("Stärke der Ausprägung", size=18)
    plt.ylabel("Anzahl", size=18)
    plt.xticks([0, 1, 2, 3])

    # Titel und Legende
    plt.title("Übersicht der beobachteten Fehler", size=18, pad=10)
    plt.legend(prop={"size": 10})

    fig.set_size_inches(8, 6)
    fig.tight_layout()
In [12]:
plotLabelHist(df["Labels"])
plt.show()
No description has been provided for this image

Zusammenfassend kann festgehalten werden, dass der Datensatz ca. 4500 Teile umfasst welche durch ca. 100 Merkmale beschrieben werden. Diese Merkmale ergeben sich überwiegend aus den internen Messungen der Spritzgussmaschine. Interessant sind vor Allem die Zielwerte 0_leak_corner_tl und 0_leak_corner_tr, welche in der Regel entweder gar nicht oder sehr stark auftreten.

3.4 Aufteilen der Daten

Zunächst wird der Datensatz in Trainings- und Testdaten unterteilt. Wie im vorherigen Unterkapitel gezeigt können manche Fehler sehr selten sein. Deshalb wird eine stratifizierte anstatt einer rein zufälligen Stichprobe gezogen, vgl. [3].

In [13]:
from sklearn.model_selection import StratifiedShuffleSplit

split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
for train_idx, test_idx in split.split(df, df["Labels"]["0_leak_corner_tr"]):
    df_train = df.iloc[train_idx]
    df_test = df.iloc[test_idx]

print("Anzahl Datenpunkte:")
print("Trainingsdaten:", len(df_train))
print("Testdaten:", len(df_test))
Anzahl Datenpunkte:
Trainingsdaten: 3638
Testdaten: 910

Im nächsten Schritt werden die Merkmale und Zielwerte voneinander getrennt:

In [14]:
# Merkmale
X_train = df_train.drop("Labels", axis=1)
X_test = df_test.drop("Labels", axis=1)

# Zielwerte
y_train = df_train["Labels"].copy()
y_test = df_test["Labels"].copy()

3.5 Erkunden der Daten

Nun können die Trainingsdaten erkundet werden. Ein gängiges Hilfsmittel dazu ist die sog. Korrelationsmatrix. Diese enthält den Pearson-Korrelationskoeffizienten für jedes einzelne Merkmal mit jedem anderen. Um einen Überblick zu bekommen wird diese zunächst grafisch dargestellt:

In [15]:
def plotCorrMatrix(df):
    fig = plt.figure(figsize=(7, 7))

    # Korrelationsmatrix
    ax = fig.add_subplot(111)
    cax = ax.matshow(df.corr())
    fig.colorbar(cax)

    # Titel und Achsenbeschriftung
    ax.set_title("Korrelationsmatrix", size=18, pad=18)
    ax.set_xlabel("Merkmale", labelpad=20)
    ax.set_ylabel("Merkmale", labelpad=20)
In [16]:
plotCorrMatrix(X_train)
plt.show()
No description has been provided for this image

In der Grafik sind sowohl stark positive (nahe 1) als auch stark negative (nahe -1) Korrelationen zu erkennen. Insbesondere rechts unten sind zusammenhängende Bereiche stark korrelierender Merkmale sichtbar. Diese Beobachtungen deuten darauf hin, dass eine Dimensionsreduktion nachfolgend ein hilfreicher Zwischenschritt sein könnte.

Interessant können auch die Korrelationen der Merkmale mit den Zielwerten sein. Nachfolgend werden die am stärksten mit dem Fehler 0_leak_corner_tr korrelierenden Merkmale aufgelistet.

In [17]:
fault_corr = df.corr()["Labels"]["0_leak_corner_tr"].sort_values(ascending=False)

# Korrelationen der Fehler untereinander entfernen
fault_corr = fault_corr.drop("Labels", level=0, axis=0)

Diese 5 Merkmale besitzen die stärkste positive Korrelation mit dem Fehler:

In [18]:
fault_corr.head(5)
Out[18]:
Group        Name                                            
Internal_C2  Spezifischer Einspritzdruck Spitzenwert [APVs 2]    0.936937
             Einspritzarbeit [EA 2]                              0.920485
             Schussvolumen [Svo 2]                               0.857009
             Spezifischer Druck beim Umschalten [APHu 2]         0.818221
             Integral Überwachung 1 Micrograph [IDKi1_Mic 2]     0.812907
Name: 0_leak_corner_tr, dtype: float64

Diese 5 Merkmale besitzen die stärkste negative Korrelation:

In [19]:
fault_corr.tail(5)
Out[19]:
Group        Name                                
Internal     Werkzeug 8 [Pakt 17]                   -0.373270
Internal_C2  Spritzzeit Istwert [ZSx 2]             -0.466767
             Massepolster kleinster Wert [ACPx 2]   -0.620924
             Massepolster Ende Nachdruck [ACPv 2]   -0.851165
             Massepolster nach Nachdruck [ACPn 2]   -0.857009
Name: 0_leak_corner_tr, dtype: float64

Grundsätzlich existieren stark korrelierende Merkmale (> 0,8). Diese entstammen größtenteils der Gruppe Internal_C2. Nachfolgend werden die Histogramme der beiden am stärksten korrelierenden Merkmale dargestellt:

In [20]:
fig, axes = plt.subplots(1, 2)
fig.set_size_inches(14, 6)
fig.suptitle("Histogramme der am stärksten korrelierenden Merkmale", fontsize=16)

# Histogramme
df.hist(fault_corr.index[0], bins=50, ax=axes[0])
df.hist(fault_corr.index[1], bins=50, ax=axes[1])
axes[0].set_title(fault_corr.index[0][1], pad=8)
axes[1].set_title(fault_corr.index[1][1], pad=8)

plt.show()
No description has been provided for this image

In beiden Histogramm sind zwei klar getrennte Cluster erkennbar. Es liegt die Vermutung nahe, dass es sich dabei um die fehlerfreien und fehlerhaften Teile handelt. Möglicherweise können diese bereits anhand eines einzigen Merkmals separiert werden.

Das Erkunden der Daten hat gezeigt, dass relativ starke lineare Zusammenhänge im Datensatz existieren sowie Cluster erkennbar sind. Diese Erkenntnisse können nachfolgend bspw. bei der Auswahl von Algorithmen für bestimmte Probleme hilfreich sein.

4. Klassifizierung anhand eines Merkmals

Am einfachsten könnten fehlerhafte Teile mit Hilfe der vorhandenen Funktionen der Spritzgussmaschine aussortiert werden. Bei diesen Maschinen können üblicherweise Grenzwerte für einzelne interne Messwerte vorgegeben werden. Werden diese Grenzwerte über- bzw. unterschritten sortiert das sog. Handling (der "Roboterarm") das Teil automatisch aus. Das Finden passender Grenzwerte ist dabei die größte Herausforderung.

Um diese Aufgabe zu automatisieren, bietet sich der CART (Classification and Regression Trees)-Algorithmus an. Dieser wird genutzt um Entscheidungsbäume zu generieren. Wichtig dabei ist, dass er ausschließlich Binärbäume erzeugt. Bei jeder Abzweigungen von einem Knoten versucht der Algorithmus, den gewichteten Informationsgehalt der nachfolgenden Knoten zu maximieren. Je höher dieser Informationsgehalt, desto genauer können die Datenpunkte in der nachfolgenden Ebene klassifiziert werden, vgl. [4]. Der Algorithmus arbeitet dabei in jedem Schritt "greedy". Das bedeutet, er versucht in jedem einzelnen Schritt das optimale Ergebnis zu erzielen. Ein größerer Kontext wird nicht beachtet. Aufgrund dieser Eigenschaften (binär und "greedy") eignet sich der CART optimal für das Finden der Grenzwerte der Spritzgussmaschine.

Die Spritzgussmaschine kann ein Teil entweder aussortieren oder nicht. Folglich müssen zunächst die Zielwerte angepasst werden. Nach Rücksprache mit dem Fachpersonal werden die Fehlerausprägungen 0 und 1 als fehlerfreies sowie 2 und 3 als fehlerhaftes Teil eingestuft:

In [21]:
def convertLabelsToBinary(labels):
    labels_bin = labels.copy()
    labels_bin.replace(1, 0, inplace=True)
    labels_bin.replace(2, 3, inplace=True)

    # Zur besseren Lesbarkeit wird die Stufe 3 abschließend in 1 "umbenannt"
    labels_bin.replace(3, 1, inplace=True)

    return labels_bin
In [22]:
y_train_01 = convertLabelsToBinary(y_train)
y_test_01 = convertLabelsToBinary(y_test)

Außerdem kann der CART (wie auch die Spritzgussmaschine) nur mit numerischen Merkmalen umgehen. Die text-basierten Merkmale werden nachfolgend entfernt.

In [23]:
X_train_num = X_train.drop(X_train.select_dtypes(exclude=np.number), axis=1)
X_test_num = X_test.drop(X_train.select_dtypes(exclude=np.number), axis=1)

Da für den CART keine Skalierung der Merkmale erforderlich ist kann der Algorithmus unmittelbar trainiert werden:

In [24]:
from sklearn.tree import DecisionTreeClassifier

# max_depth = 1 da nur der beste Grenzwert gesucht ist
tree_clf = DecisionTreeClassifier(max_depth=1, random_state=42)
tree_clf.fit(X_train_num, y_train_01["0_leak_corner_tr"])
Out[24]:
DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
                       max_depth=1, max_features=None, max_leaf_nodes=None,
                       min_impurity_decrease=0.0, min_impurity_split=None,
                       min_samples_leaf=1, min_samples_split=2,
                       min_weight_fraction_leaf=0.0, presort='deprecated',
                       random_state=42, splitter='best')

Um das Ergebnis darzustellen kann das Modul graphviz genutzt werden:

In [25]:
from sklearn.tree import export_graphviz
from graphviz import Source

# .dot-Datei exportieren
export_graphviz(
    tree_clf,
    out_file="tree_clf.dot",
    feature_names=X_train_num.droplevel(0, axis=1).columns,
    class_names=["Gut", "Schlecht"],
    rounded=True,
    filled=True,
)

# .dot-Datei in Graph umwandeln und darstellen
Source.from_file("tree_clf.dot")
Out[25]:
No description has been provided for this image

Das Ergebnis sieht vielversprechend aus: In nur einem Schritt wurden zwei Gruppen gebildet, welche zu einem sehr großen Teil entweder nur aus Gut- oder nur aus Schlechtteilen bestehen. Der Informationsgehalt wurde somit stark erhöht.

An dieser Stelle offenbart sich ein weiterer großer Vorteil des CART. Bei ihm handelt es sich im Gegensatz zu vielen anderen ML-Algorithmen um einen sog. White-Box-Algorithmus. Das bedeutet, dass seine Entscheidungsfindung sehr einfach nachvollzogen werden kann. In diesem Fall scheint der Spezifische Einspritzdruck Spitzenwert entscheidend zu sein. Übersteigt dieser einen Wert von ca. 400, werden fehlerhafte Teile produziert. Hieraus könnten vom Fachpersonal weitere Erkenntnisse abgeleitet werden.

Um für die quantitative Beurteilung noch nicht auf die Testdaten zurückgreifen zu müssen wird zur Bewertung eine Kreuzvalidierung, implementiert durch die Klasse cross_val_score, durchgeführt. Da fehlerhafte Teile nicht selten sind kann die Genauigkeit als Bewertungskriterium genutzt werden:

In [26]:
from sklearn.model_selection import cross_val_score

tree_cv = cross_val_score(
    tree_clf, X_train_num, y_train_01["0_leak_corner_tr"], cv=10, scoring="accuracy"
)
In [27]:
def outputCVResults(cv):
    print("Genauigkeit bei der Kreuzvalidierung")
    print("- Mittelwert:", "{:.2f}".format(100 * cv.mean()), "%")
    print("- Standardabw.:", "{:.2f}".format(100 * cv.std()), "%")
In [28]:
outputCVResults(tree_cv)
results.append(("Tree_cv", 100 * tree_cv.mean()))
Genauigkeit bei der Kreuzvalidierung
- Mittelwert: 98.93 %
- Standardabw.: 0.52 %

Tatsächlich lassen sich die Trainingsdaten mit einer Genauigkeit von ca. 98,9 % anhand eines einzigen Merkmals klassifizieren. Auf den Testdaten sieht das Ergebnis ähnlich aus, es scheint kein Overfitting vorzuliegen:

In [29]:
tree_cv = cross_val_score(
    tree_clf, X_test_num, y_test_01["0_leak_corner_tr"], cv=10, scoring="accuracy"
)
In [30]:
outputCVResults(tree_cv)
results.append(("Tree_test", 100 * tree_cv.mean()))
Genauigkeit bei der Kreuzvalidierung
- Mittelwert: 98.90 %
- Standardabw.: 0.98 %

Diese Lösung kann weiter verbessert werden, indem auch die Grenzwerte für das 2., 3. usw. beste Merkmale ermittelt und in die Spritzgussmaschine eingetragen werden:

In [31]:
# Einstellungen
n_features = 10
label = "0_leak_corner_tr"

# Kopie der Daten erstellen da in jedem Durchlauf das "beste" Merkmal entfernt wird
X_train_cpy = X_train_num.copy()
X_test_cpy = X_test_num.copy()

# Initialisierungen
tree_clf_tmp = DecisionTreeClassifier(max_depth=1, random_state=42)
features, train_scores, test_scores = [], [], []
for _ in range(n_features):
    # Entscheidungsbaum trainieren
    tree_clf_tmp.fit(X_train_cpy, y_train_01[label])

    # Ergebnis abspeichern
    features.append(X_train_cpy.columns[tree_clf_tmp.feature_importances_.argmax()][1])
    train_scores.append(
        100
        * cross_val_score(
            tree_clf_tmp, X_train_cpy, y_train_01[label], cv=5, scoring="accuracy"
        ).mean()
    )
    test_scores.append(
        100
        * cross_val_score(
            tree_clf_tmp, X_test_cpy, y_test_01[label], cv=5, scoring="accuracy"
        ).mean()
    )

    # Bestes Merkmal für den nächsten Durchlauf entfernen
    X_train_cpy = X_train_cpy.drop(
        X_train_cpy.columns[tree_clf_tmp.feature_importances_.argmax()], axis=1
    )
    X_test_cpy = X_test_cpy.drop(
        X_test_cpy.columns[tree_clf_tmp.feature_importances_.argmax()], axis=1
    )
In [32]:
# Zur besseren Darstellung in DataFrame umwandeln
data = {"Merkmal": features, "Training [%]": train_scores, "Test [%]": test_scores}
df_features = pd.DataFrame(data)
style = df_features.style
style = style.format({"Training [%]": "{:.2f}"})
style = style.format({"Test [%]": "{:.2f}"})
style = style.background_gradient(cmap="viridis")
style = style.set_properties(**{"text-align": "right"})
style = style.set_properties(**{"text-align": "left"}, subset=["Merkmal"])
style = style.hide_index()
style
Out[32]:
<style type="text/css"> #T_5b664334_f214_11eb_a746_0242ac1c0002row0_col0,#T_5b664334_f214_11eb_a746_0242ac1c0002row1_col0,#T_5b664334_f214_11eb_a746_0242ac1c0002row2_col0,#T_5b664334_f214_11eb_a746_0242ac1c0002row3_col0,#T_5b664334_f214_11eb_a746_0242ac1c0002row4_col0,#T_5b664334_f214_11eb_a746_0242ac1c0002row5_col0,#T_5b664334_f214_11eb_a746_0242ac1c0002row6_col0,#T_5b664334_f214_11eb_a746_0242ac1c0002row7_col0,#T_5b664334_f214_11eb_a746_0242ac1c0002row8_col0,#T_5b664334_f214_11eb_a746_0242ac1c0002row9_col0{ text-align: right; text-align: left; }#T_5b664334_f214_11eb_a746_0242ac1c0002row0_col1,#T_5b664334_f214_11eb_a746_0242ac1c0002row0_col2{ background-color: #fde725; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row1_col1,#T_5b664334_f214_11eb_a746_0242ac1c0002row2_col1,#T_5b664334_f214_11eb_a746_0242ac1c0002row3_col1{ background-color: #c8e020; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row1_col2,#T_5b664334_f214_11eb_a746_0242ac1c0002row2_col2,#T_5b664334_f214_11eb_a746_0242ac1c0002row3_col2{ background-color: #81d34d; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row4_col1{ background-color: #b2dd2d; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row4_col2{ background-color: #93d741; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row5_col1{ background-color: #a2da37; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row5_col2{ background-color: #73d056; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row6_col1{ background-color: #5cc863; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row6_col2{ background-color: #42be71; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row7_col1{ background-color: #20a486; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row7_col2{ background-color: #21918c; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row8_col1{ background-color: #1f988b; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row8_col2{ background-color: #21a585; color: #000000; text-align: right; }#T_5b664334_f214_11eb_a746_0242ac1c0002row9_col1,#T_5b664334_f214_11eb_a746_0242ac1c0002row9_col2{ background-color: #440154; color: #f1f1f1; text-align: right; }</style>
Merkmal Training [%] Test [%]
Spezifischer Einspritzdruck Spitzenwert [APVs 2] 98.93 98.90
Massepolster Ende Nachdruck [ACPv 2] 97.36 96.04
Schussvolumen [Svo 2] 97.39 96.04
Massepolster nach Nachdruck [ACPn 2] 97.39 96.04
Spezifischer Druck beim Umschalten [APHu 2] 96.78 96.48
Einspritzarbeit [EA 2] 96.32 95.71
Integral Überwachung 1 Micrograph [IDKi1_Mic 2] 94.25 94.40
Integral Überwachung 1 Micrograph [IDKi1_Mic 1] 91.23 91.43
Spezifischer Nachdruck Spitzenwert [APNs 2] 90.27 92.75
Schusszähler Istwert [SZx] 80.35 83.96

Neben dem Spezifischen Einspritzdruck Spitzenwert erzielen fünf weitere Merkmale eine Genauigkeit von über 95 % auf den Testdaten. Wenn das beste Merkmal nicht mehr ausreichen sollte könnten aus diesen Merkmalen zukünftig weitere Grenzwerte abgeleitet werden. Dazu muss der entsprechende Entscheidungsbaum betrachtet werden. Durch eine Verschiebung der ermittelten Grenzwerte in Richtung der Gut- bzw. Schlechtteile kann außerdem entweder die Sensitivität oder die Präzision des tems entsprechend der spezifischen Anforderungen angepasst werden.

5. Klassifizierung anhand mehrerer Merkmale

Die bei der Firma Gustav Hensel GmbH & Co. KG verwendeten Spritzgussmaschinen stellen ihre internen Messwerte unmittelbar nach Fertigstellung eines Teils über einen USB-Anschluss zur Verfügung. Dies eröffnet die Möglichkeit, auf externer Hardware einen komplexeren Klassifikator laufen zu lassen. Die Ausgabe des Klassifikators kann von den Maschinen über einen digitalen Eingang eingelesen und das gespritzte Teil bei Bedarf aussortiert werden.

Die meisten dieser "komplexeren" Klassifikatoren erfordern eine Vorverarbeitung der Daten. Deshalb wird im nachfolgenden Unterkapitel zunächst eine Pipeline zur Datenvorverarbeitung aufgebaut.

5.1 Pipeline

Grundsätzlich haben die Merkmale sehr unterschiedliche Wertebereiche:

In [33]:
formatForPlotting(X_train["Internal_C1"].describe()).iloc[[1, 3, 7]]
Out[33]:
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
Name Dosierleistung [iwdls_1] Dosiervolumen Istwert [ASSx_1] Dosierzeit Istwert [ZDx_1] Drehmoment Mittelwert laufender Zyklus [Mm_1] Drehmoment Spitzenwert laufender Zyklus [Ms_1] Drehzahl Spitzenwert [DZs_1] Einspritzarbeit [EA_1] Integral Überwachung_1 Micrograph [IDKi1_Mic_1] Massepolster Ende Nachdruck [ACPv_1] Massepolster kleinster Wert [ACPx_1] Massepolster nach Nachdruck [ACPn_1] Schussvolumen [Svo_1] Spezifischer Druck beim Umschalten [APHu_1] Spezifischer Einspritzdruck Spitzenwert [APVs_1] Spezifischer Nachdruck Spitzenwert [APNs_1] Spezifischer Staudruck Spitzenwert [APSs_1] Spritzzeit Istwert [ZSx_1] Umschaltvolumen [AC3u_1] Zykluszeit Düse vor [ZDvo_1] Zykluszeit Nachdruck [ZNach_1]
mean 6.786638 70.598395 7.644107 166.944667 178.081253 0.293926 1.02861 51273.154137 6.200066 4.421671 6.405632 62.594368 528.619351 904.122787 628.062177 93.642386 1.174428 12.568419 1.155214 1.995052
min 5.990000 70.370000 1.990000 84.500000 133.500000 0.292000 0.97000 46882.560000 3.700000 2.140000 3.910000 59.690000 500.000000 768.300000 595.000000 7.400000 1.120000 12.480000 0.000000 0.000000
max 26.980000 70.770000 8.510000 178.700000 192.200000 0.298000 1.11600 55403.390000 9.110000 6.160000 9.310000 65.090000 605.700000 1042.300000 672.800000 95.700000 1.230000 12.690000 3.570000 2.000000

Außerdem sind alle bis auf ein Merkmal numerisch. Das einzige text-basierte Merkmal ist dabei nicht sehr aussagekräftig, da es fast immer einen Bindestrich enthält:

In [34]:
X_train.select_dtypes(exclude=[np.number]).value_counts()
Out[34]:
(Internal, Ausschussursache [ASU])              
-                                                   3615
3- Polster 2 zu klein  (3/2/0/0/0)                    11
3- Polster 1 zu klein  (3/1/0/0/0)                     8
4- Durchwärmungsprüfung 2 war aktiv  (4/2/0/0/0)       4
dtype: int64

Deshalb wird dieses Merkmal von der nachfolgend aufgebauten Pipeline aussortiert.

Zunächst wird eine Pipeline für die numerischen Merkmale aufgebaut. Diese übernimmt im Wesentlichen die Skalierung der Merkmale. Der Datensatz besitzt einige Ausreißer. Aus diesem Grund wird der StandardScaler verwendet, welcher wesentlich robuster gegenüber Ausreißern ist als der MinMaxScaler.

In [35]:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

num_pipeline = Pipeline([("scaler", StandardScaler())])

Im nächsten Schritt wird die vollständige Pipeline definiert. Diese sortiert das text-basierte Merkmal aus. Durch die Verwendung der Klasse ColumnTransformer können diese Merkmale zukünftig sehr einfach mit Hilfe einer eigenen Pipeline vorverarbeitet werden.

In [36]:
from sklearn.compose import ColumnTransformer

num_features = list(X_train.select_dtypes(include=[np.number]))
text_features = list(X_train.select_dtypes(exclude=[np.number]))

pipeline = ColumnTransformer(
    [("num", num_pipeline, num_features), ("text", "drop", text_features)]
)

Nun kann die Pipeline an die Trainingsdaten angepasst und anschließend auf alle Daten angewendet werden:

In [37]:
# Anpassen an die Trainingsdaten
pipeline.fit(X_train)

# Transformation der Trainings- und Testdaten
X_train_tr = pipeline.transform(X_train)
X_test_tr = pipeline.transform(X_test)

# Wiederherstellung der DataFrames
X_train_tr = pd.DataFrame(
    X_train_tr, X_train[num_features].index, X_train[num_features].columns
)
X_test_tr = pd.DataFrame(
    X_test_tr, X_test[num_features].index, X_test[num_features].columns
)

Die vorverarbeiteten Daten können im nächsten Schritt zum Trainieren der Klassifikatioren genutzt werden.

5.2 Klassifikatoren

Wie bereits in den vorherigen Kapitel wird stellvertretend der häufigste Fehler 0_leak_corner_tr untersucht.

In [38]:
label = "0_leak_corner_tr"

5.3 Logistische Regression

In der Regel ist es sinnvoll, mit möglichst wenigen Annahmen zu starten. Deshalb wird im ersten Versuch ein lineares Modell trainiert. Dieses wird durch die Klasse LogisticRegeression implementiert.

In [39]:
from sklearn.linear_model import LogisticRegression

log_clf = LogisticRegression(random_state=42)
log_clf.fit(X_train_tr, y_train_01[label])
Out[39]:
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                   intercept_scaling=1, l1_ratio=None, max_iter=100,
                   multi_class='auto', n_jobs=None, penalty='l2',
                   random_state=42, solver='lbfgs', tol=0.0001, verbose=0,
                   warm_start=False)

Auch an dieser Stelle wird wieder auf die Kreuzvalidierung mit der Genauigkeit als Bewertungskritierium zurückgegriffen, siehe Kapitel 4.

In [40]:
log_clf_cv = cross_val_score(
    log_clf, X_train_tr, y_train_01[label], cv=10, scoring="accuracy"
)
In [41]:
outputCVResults(log_clf_cv)
results.append(("Log_reg_cv", 100 * log_clf_cv.mean()))
Genauigkeit bei der Kreuzvalidierung
- Mittelwert: 99.20 %
- Standardabw.: 0.48 %

Das Ergebnis ist im Durchschnitt mit 99,2 % nur etwas besser als mit einem sehr einfachen Entscheidungsbaum mit ca. 98,9 %.

5.4 Random Forest

Möglicherweise ist ein komplexeres Modell erforderlich. Aufgrund des Erfolgs des einfachen Entscheidungsbaums wirkt ein Random Forest-Modell vielversprechend. Ein Random Forest besteht aus mehreren - möglichst unkorrelierten - Entscheidungsbäumen und kann sowohl für die Klassifikation als auch Regression eingesetzt werden. Die Klassifikation erfolgt durch einen Mehrheitsentscheid der einzelnen Bäume. Um unkorrelierte Entscheidungsbäume zu erhalten werden diese bspw. auf zufällig aufgewählten Teilmengen der Merkmale trainiert, vgl. [5]. In Scikit-Learn wird dieses Modell durch die Klasse RandomForestRegressor implementiert.

In [42]:
from sklearn.ensemble import RandomForestClassifier

forest_clf = RandomForestClassifier(random_state=42)
forest_clf.fit(X_train_tr, y_train_01[label])
Out[42]:
RandomForestClassifier(bootstrap=True, ccp_alpha=0.0, class_weight=None,
                       criterion='gini', max_depth=None, max_features='auto',
                       max_leaf_nodes=None, max_samples=None,
                       min_impurity_decrease=0.0, min_impurity_split=None,
                       min_samples_leaf=1, min_samples_split=2,
                       min_weight_fraction_leaf=0.0, n_estimators=100,
                       n_jobs=None, oob_score=False, random_state=42, verbose=0,
                       warm_start=False)

Wie zuvor kann nun die Kreuzvalidierung zur Bewertung genutzt werden:

In [43]:
forest_clf_cv = cross_val_score(
    forest_clf, X_train_tr, y_train_01[label], cv=10, scoring="accuracy"
)
In [44]:
outputCVResults(forest_clf_cv)
results.append(("Forest_cv", 100 * forest_clf_cv.mean()))
Genauigkeit bei der Kreuzvalidierung
- Mittelwert: 99.26 %
- Standardabw.: 0.37 %

Mit 99,26 % ist der Random Forest nur minimal besser als die Logistische Regression mit 99,20 %.

5.5 Analyse der Fehler

Dies ist ein guter Zeitpunkt um die Fehler des Modells genauer zu untersuchen. Dazu sind die "ehrlichen" Schätzungen des Klassifikators erforderlich. Das sind Schätzungen, bei denen der Klassifikator den zu klassifizierenden Datenpunkt noch nicht gesehen hat, also nicht auf diesem trainiert wurde. Auch hier bietet Scikit-Learn mit der Klasse cross_val_predict eine passende Implementierung, welche auf der Kreuzvalidierung aufbaut:

In [45]:
from sklearn.model_selection import cross_val_predict

y_train_01_pred = cross_val_predict(forest_clf, X_train_tr, y_train_01[label])

Die Fehler können im nächsten Schritt als Konfusionsmatrix dargestellt werden:

In [46]:
from sklearn.metrics import confusion_matrix

print("Konfusionsmatrix")
print(confusion_matrix(y_train_01[label], y_train_01_pred))
Konfusionsmatrix
[[1952   26]
 [   6 1654]]

Die allermeisten Teile wurden entweder korrekt positiv (1952) oder korrekt negativ (1654) klassifiziert. Allerdings wurden einige fehlerfreie Teile als fehlerhaft klassifiziert (26) und ein paar fehlerhafte Teile als fehlerfrei (6). Um diese fehlerhaften Klassifizierungen zu erklären werden nachfolgend die ursprünglichen Zielwerte (0 - 3) für ein paar dieser Teile dargestellt.

Fehlerfreie Teile die als fehlerhaft klassifiziert wurden:

In [47]:
y_train[
    np.logical_and(y_train_01[label] == 0, y_train_01_pred == 1)
].sort_index().head()
Out[47]:
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
Name 0_leak_corner_tl 0_leak_corner_tr 1_hole_bottom
2021-01-11 15:10:02 1 1 0
2021-01-11 16:11:52 3 1 0
2021-01-11 16:30:29 2 1 0
2021-01-11 16:32:17 3 1 0
2021-01-11 16:41:53 1 1 0

Fehlerhafte Teile die als fehlerfrei klassifiziert wurden:

In [48]:
y_train[
    np.logical_and(y_train_01[label] == 1, y_train_01_pred == 0)
].sort_index().head()
Out[48]:
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
Name 0_leak_corner_tl 0_leak_corner_tr 1_hole_bottom
2021-01-11 14:53:13 1 2 0
2021-01-11 14:58:01 1 2 0
2021-01-11 16:12:29 1 2 0
2021-01-12 05:57:11 1 2 0
2021-01-12 12:55:29 1 2 0

In der Spalte 0_leak_corner_tr beider Tabellen ist erkennbar, dass die falsch klassifizierten Teile mit einer Fehlerstärke von 1 bzw. 2 jeweils am Rand der binären Entscheidungsgrenze (zwischen 1 und 2) liegen. Vermutlich handelt es sich bei diesen Teilen um Grenzfälle, welche sowohl der Fehlerstärke 1 als auch 2 hätten zugeordnet werden können. Die Fotos zweier dieser Teile - dargestellt in Abbildung 4 - unterstützen diese Vermutung:

Grenzwertig.jpg

Abbildung 4: Ein falsch positiv (links) und ein falsch negativ (rechts) klassifiziertes Teil

Im Vergleich zu den übrigen Teilen sind beide dargestellten Fehler weder besonders schwach noch besonders stark.

Auf Grundlage dieser Erkenntnis könnte im nächsten Schritt der Grenzwert des Klassifikators so festgelegt werden, dass dessen Sensitivität und Präzision für den vorliegenden Anwendungsfall optimal sind. Da die positive Kategorie bei diesem Datensatz nicht selten ist, bietet sich in diesem Fall die Verwendung einer ROC-Kurve an, um dieses Ziel zu erreichen, vgl. [3].

5.3 Zusammenfassung

Die Genauigkeit der beiden trainierten Klassifikatoren ist mit über 99,00 % bei der Kreuzvalidierung ausreichend hoch. Die fehlerhaft klassifizierten Teile liegen vermutlich nahe der binären Entscheidungsgrenze. Diese Fehler sind bei einem binären Klassifikator auf Basis analoger Merkmale zu erwarten. Abschließend werden die Klassifikatoren anhand der Testdaten überprüft:

In [49]:
print("Genauigkeit auf den Testdaten")

# Logistische Regression
log_clf_test = log_clf.score(X_test_tr, y_test_01[label])
print("- Logistische Regression:", "{:.2f}".format(100 * log_clf_test), "%")
results.append(("Log_reg_test", 100 * log_clf_test))

# Random Forest
forest_clf_test = forest_clf.score(X_test_tr, y_test_01[label])
print("- Random Forest:", "{:.2f}".format(100 * forest_clf_test), "%")
results.append(("Forest_test", 100 * forest_clf_test))
Genauigkeit auf den Testdaten
- Logistische Regression: 99.23 %
- Random Forest: 99.34 %

Auch die Genauigkeit auf den Testdaten ist mit jeweils über 99,2 % ausreichend hoch und sehr ähnlich zur Genauigkeit bei der Kreuzvalidierung. Von einem Under- oder Overfitting ist deshalb nicht auszugehen. Aufgrund der hohen Genauigkeit und der erklärbaren Fehler wird kein zusätzlicher Aufwand in die Optimierung der Hyperparamter investiert.

Zusammenfassend hat dieses Kapitel gezeigt, dass mit Klassifikatoren auf Basis mehrerer Merkmale sehr gute Ergebnisse erzielt werden können. Der große Nachteil dabei ist, dass dafür ca. 3600 Fotos manuell gelabelt werden mussten. Im nachfolgenden Kapitel wird deshalb untersucht, ob der Ansatz des teilüberwachten Lernens genutzt werden kann, um diesen Aufwand zu minimieren.

6. Teilüberwachtes Lernen

Die vorherigen Kapitel haben gezeigt, dass ML-Algorithmen mit Hilfe gelabelter Daten fehlerhafte Teile sehr gut erkennen können. Ziel dieses Kapitel ist, den Aufwand zu minimieren, um einen solchen Algorithmus zu trainieren. Dieser Aufwand besteht hauptsächlich im Labeln der Fotos. Beim Erkunden der Daten hat sich bereits gezeigt, dass diese eine Cluster-Struktur aufweisen. Ein vielversprechender Ansatz zur Minimierung des Label-Aufwands ist deshalb das teilüberwachte Lernen.

Beim teilüberwachten Lernen wird nur ein geringer Teil der Datenpunkte gelabelt. Es wird versucht, dafür repräsentative Datenpunkte zu finden. Dies könnten bspw. die Mittelpunkte der beobachteten Cluster sein. Die Label der repräsentativen Datenpunkte können auch auf andere z.B. demselben Cluster angehörige Datenpunkte übertragen werden, bevor ein ML-Algorithmus trainiert wird, vgl. [3]. In diesem Fall soll die Auswahl der repräsentativen Datenpunkte auf Basis der beobachteten Cluster erfolgen. Wie diese erfasst werden beschreibt das nachfolgende Unterkapitel.

6.1 Clustering der Daten

6.1.1 Auswahl relevanter Merkmale

In einem hochdimensionalen Merkmalsraum sind Datenpunkte relativ weit voneinander entfernt, wodurch deren Clustering erschwert wird, vgl. [3]. Eine einfache Möglichkeit diesen Merkmalsraum zu verkleinern ist das Entfernen von Merkmalen, welche für das untersuchte Problem wenig relevant erscheinen. Dies könnte z.B. auf Grundlage von Fachwissen erfolgen. In diesem Fall eröffnet jedoch der in Kap. 5 trainierte RandomForestClassifier eine einfachere Möglichkeit. Dieser besitzt das Attribut feature_importances_, welches Aufschluss über diejenigen Merkmale gibt, welche bei seinen Entscheidungen am wichtigsten sind. Nachfolgend die 10 wichtigsten Merkmale:

In [50]:
feature_importances = forest_clf.feature_importances_
features_df = pd.DataFrame(
    feature_importances.T, X_train_tr.columns, ["Feature importance"]
)
features_df["Feature importance"].sort_values(ascending=False).head(10)
Out[50]:
Group        Name                                            
Internal_C2  Spezifischer Einspritzdruck Spitzenwert [APVs 2]    0.135442
             Spezifischer Druck beim Umschalten [APHu 2]         0.128987
             Massepolster Ende Nachdruck [ACPv 2]                0.126340
             Schussvolumen [Svo 2]                               0.102903
             Massepolster nach Nachdruck [ACPn 2]                0.095072
             Integral Überwachung 1 Micrograph [IDKi1_Mic 2]     0.072568
             Einspritzarbeit [EA 2]                              0.068275
             Spezifischer Nachdruck Spitzenwert [APNs 2]         0.043516
Internal     Schusszähler Istwert [SZx]                          0.034663
Internal_C2  Dosierzeit Istwert [ZDx 2]                          0.028120
Name: Feature importance, dtype: float64

Noch aufschlussreicher ist ein Graph, welche die sortierten Wichtigkeiten der Merkmale über deren Indizes darstellt:

In [51]:
plt.figure(figsize=(8, 6))
plt.plot(features_df["Feature importance"].sort_values(ascending=False).to_numpy())

# Horizontale Linie
xticks = range(0, 101, 5)
hline = 0.01
plt.plot(xticks, np.array([hline for tick in xticks]), "r--", label="1 %")

# Formatierung
plt.title("Wichtigkeit der Merkmale im Random Forest", fontsize=16, pad=10)
plt.xlabel("Merkmale")
plt.ylabel("Relative Wichtigkeit [%]")
plt.xlim(0, 100)
plt.ylim(0, 0.15)
plt.xticks(xticks)
plt.legend()
plt.show()
No description has been provided for this image

Der Graph zeigt, dass ca. ab dem 15. Merkmal die relative Wichtigkeit unter 1 % sinkt. Deshalb werden nachfolgend nur die ersten 15 Merkmale betrachtet. An dieser Stelle kann selbstverständlich auch domänenspezifisches Wissen berücksichtigt werden.

In [52]:
n_features = 15
X_train_cl = X_train_tr.iloc[:, feature_importances.argsort()[-n_features:]]
X_test_cl = X_test_tr.iloc[:, feature_importances.argsort()[-n_features:]]

# Reihenfolge der Spaltennamen wiederherstellen
X_train_cl = X_train_cl.sort_index(axis=1)
X_test_cl = X_test_cl.sort_index(axis=1)

6.1.2 Dimensionsreduktion

Über das Entfernen der unwichtigen Merkmale hinaus kann die Dimension des Merkmalsraums weiter reduziert werden. Dies erleichtert das Clustering und ermöglicht eine visuelle Darstellung der Cluster.

Häufig wird dafür die Hauptkomponentenanalyse (Principal Component Analysis, PCA) eingesetzt. Bei dieser handelt sich um ein mathematisches Verfahren, bei dem der ursprüngliche Merkmalsraum unter Beibehaltung einer möglichst großen Varianz auf einen niedriger dimensionalen Unterraum projiziert wird, vgl. [6]. Die Dimension des Unterraums kann dabei beliebig gewählt werden.

Die Achsen des Unterraums werden als Hauptkomponenten bezeichnet und ergeben sich aus Linearkombinationen der ursprünglchen Merkmale. Beim Erkunden der Daten in Kap. 3.5 konnten starke lineare Korrelationen im Datensatz beobachtet werden. Aus diesem Grund wird nachfolgend die PCA zur Dimensionreduktion genutzt. Auch für dieses Verfahren liefert SciKit-Learn mit der Klasse PCA eine Implementierung. Der nach nachfolgende Programmcode reduziert die Dimension der 15 wichtigsten Merkmale auf 3:

In [53]:
from sklearn.decomposition import PCA

pca_3D = PCA(n_components=3)
X3D_train = pca_3D.fit_transform(X_train_cl)
X3D_test = pca_3D.fit_transform(X_test_cl)

Die erklärte Varianz der reduzierten Daten beträgt:

In [54]:
print(
    "Anteil erklärter Varianz (3D):",
    "{:.2f}".format(100 * pca_3D.explained_variance_ratio_.sum()),
    "%",
)
Anteil erklärter Varianz (3D): 95.03 %

Bei der Reduktion von 15 auf 3 Dimensionen sind folglich nur ca. 5 % der Varianz verloren gegangen. Deshalb wird nachfolgend eine Reduktion auf 2 Dimensionen ausprobiert:

In [55]:
pca_2D = PCA(n_components=2)
X2D_train = pca_2D.fit_transform(X_train_cl)
X2D_test = pca_2D.fit_transform(X_test_cl)

Die erklärte Varianz beträgt in diesem Fall:

In [56]:
print(
    "Anteil erklärter Varianz (2D):",
    "{:.2f}".format(100 * pca_2D.explained_variance_ratio_.sum()),
    "%",
)
Anteil erklärter Varianz (2D): 86.50 %

Auch wenn in 2 Dimensionen mit ca. 13,5 % deutlich mehr Informationen verloren gegangen sind ist der zweidimensionale Datensatz für das Clustering potenziell noch sehr gut geeignet. Die nachfolgenden Visualisierungen sollen bei der Auswahl der Anzahl an Dimensionen unterstützen. Zunächst wird der dreidimensionale Datensatz dargestellt.

In [57]:
from mpl_toolkits.mplot3d import Axes3D


def plotX3D(X3D, color, anomalies=None):
    # X3D bei Bedarf in np.ndarray umwandeln
    if isinstance(X3D, pd.DataFrame):
        X3D = X3D.to_numpy()

    # Initialisierung
    fig = plt.figure(figsize=(14, 11))
    ax = fig.add_subplot(111, projection="3d")

    # Über alle Fehlerausprägungen (0 - 3) iterieren
    colors = {0: "green", 1: "yellow", 2: "orange", 3: "red"}
    labels = {
        0: "kein Fehler",
        1: "schwacher Fehler",
        2: "mittlerer Fehler",
        3: "starker Fehler",
    }
    for c in np.sort(np.unique(color)):
        ax.plot(
            X3D_train[color == c, 0],
            X3D_train[color == c, 1],
            X3D_train[color == c, 2],
            ".",
            label=labels[c],
            c=colors[c],
            alpha=0.2,
        )

    # Formatierung
    ax.legend()
    ax.set_xlabel("Hauptkomponente $x_1$", fontsize=14, labelpad=10)
    ax.set_ylabel("Hauptkomponente $x_2$", fontsize=14, labelpad=10)
    ax.set_zlabel("Hauptkomponente $x_3$", fontsize=14, labelpad=10)
    ax.set_zlim(-6, 6)
    ax.view_init(50, 145)

    # Optional können Anomalien dargestellt werden
    if isinstance(anomalies, np.ndarray):
        ax.scatter(
            anomalies[:, 0], anomalies[:, 1], anomalies[:, 2], marker="x", s=80, c="red"
        )
In [58]:
plotX3D(X3D_train, y_train[label])
plt.show()
No description has been provided for this image

Es sind eindeutig Cluster zu erkennen. Sowohl für die Gut- als auch Schlechtteile existieren mehrere Cluster. Die Cluster der Schlechtteile (rot) sind deutlich weniger kompakt und länglicher gezogen als die Cluster der Gutteile (grün). Um zu überprüfen ob diese Informationen auch im zweidimensionalen Datensatz erhalten geblieben sind wird dieser als nächstes dargestellt.

In [59]:
def plotX2D(X2D, color, anomalies=None):
    # X2D bei Bedarf in np.ndarray umwandeln
    if isinstance(X2D, pd.DataFrame):
        X2D = X2D.to_numpy()

    # Initialisierung
    fig = plt.figure(figsize=(12, 8))
    ax = fig.add_subplot(111)

    # Über alle Fehlerausprägungen (0 - 3) iterieren
    colors = {0: "green", 1: "yellow", 2: "orange", 3: "red"}
    labels = {
        0: "kein Fehler",
        1: "schwacher Fehler",
        2: "mittlerer Fehler",
        3: "starker Fehler",
    }
    for c in np.sort(np.unique(color)):
        ax.plot(
            X2D[color == c, 0],
            X2D[color == c, 1],
            ".",
            label=labels[c],
            c=colors[c],
            alpha=0.2,
        )

    # Formatierung
    ax.legend()
    ax.set_xlabel("Hauptkomponente $x_1$", fontsize=14, labelpad=10)
    ax.set_ylabel("Hauptkomponente $x_2$", fontsize=14, labelpad=10)

    # Optional können Anomalien dargestellt werden
    if isinstance(anomalies, np.ndarray):
        ax.scatter(anomalies[:, 0], anomalies[:, 1], marker="x", s=80, c="red")
In [60]:
plotX2D(X2D_train, y_train[label])
plt.show()
No description has been provided for this image

Aus dieser Darstellung lassen sich sehr ähnliche Erkenntnisse ableiten wie aus der dreidimensionalen. Für das teilüberwachte Lernen wird aus Gründen der Einfachheit der zweidimensionale Datensatz verwendet.

6.1.3 Durchführung des Clustering

Auf Basis des zweidimensionalen Datensatz X2D_train kann im nächsten Schritt das Clustering durchgeführt werden. Die Darstellungen im vorherigen Unterkapitel haben gezeigt, dass die Cluster typischerweise elliptisch sind und in ihrer Dichte stark variieren können. Der Algorithmus K-Means kommt deshalb nicht in Frage, vgl. [3]. Stattdessen wird ein Gaußsches Mischverteilungsmodell (Gaussian Mixture Model, GMM) genutzt, welches diese Art von Clustern sehr gut erzeugen kann. Das Modell versucht, die Datenpunkte im Datensatz durch eine Mischung verschiedener gaußscher Verteilungen zu erzeugen, vgl. [7] Die entsprechende Klasse SciKit-Learn heißt GaussianMixture:

In [61]:
from sklearn.mixture import GaussianMixture

# n_components = 7 auf Grundlage der Darstellungen im vorherigen Unterkapitel
gaus_mix = GaussianMixture(n_components=7, random_state=42).fit(X2D_train)
y_pred_cluster = gaus_mix.predict(X2D_train)

Es ist hilfreich, diese Cluster darstellen zu können.

In [62]:
def plotX2DClustered(X2D, cluster, anomalies=None, cluster_centers=[]):
    # X2D bei Bedarf in np.ndarray umwandeln
    if isinstance(X2D, pd.DataFrame):
        X2D = X2D.to_numpy()

    # Initialisierung
    fig = plt.figure(figsize=(12, 8))
    ax = fig.add_subplot(111)

    # Über alle Cluster iterieren
    for c in np.sort(np.unique(cluster)):
        ax.plot(X2D[cluster == c, 0], X2D[cluster == c, 1], ".", label=c, alpha=0.2)

    # Formatierung
    ax.legend()
    ax.set_xlabel("Hauptkomponente $x_1$", fontsize=14, labelpad=10)
    ax.set_ylabel("Hauptkomponente $x_2$", fontsize=14, labelpad=10)

    # Optional können Anomalien dargestellt werden
    if isinstance(anomalies, np.ndarray):
        ax.scatter(anomalies[:, 0], anomalies[:, 1], marker="x", s=80, c="red")

    # Optional können die Zentren der Cluster dargestellt werden
    if len(cluster_centers) > 0:
        ax.plot(
            cluster_centers[:, 0],
            cluster_centers[:, 1],
            "o",
            c="red",
            markersize=8,
            markeredgecolor="black",
        )
In [63]:
plotX2DClustered(X2D_train, y_pred_cluster, cluster_centers=gaus_mix.means_)
No description has been provided for this image

Der Algorithmus hat die Cluster sehr gut erkannt. Die jeweiligen Mittelwerte werden als roter Punkt dargestellt. Das Gaußsche Mischverteilungsmodell wird nachfolgend die Grundlage für das teilüberwachte Lernen bilden.

6.2 Durchführung des teilüberwachten Lernens

Auf Basis des Clustering kann nun der Einfluss des teilüberwachten Lernens auf die Genauigkeit eines Klassifikators ermittelt werden. Stellvertretend wird nachfolgend der Klassifikator LogisticRegression eingesetzt, welcher in Kap. 5.3 bereits eine Genauigkeit von ca. 99,0 % auf dem gesamten Datensatz erreicht hat.

6.2.1 Referenz

Für den späteren Vergleich ist zunächst eine Referenzgenauigkeit mit allen Labeln zu ermitteln:

In [64]:
from sklearn.linear_model import LogisticRegression

log_clf_full = LogisticRegression(random_state=42)
log_clf_full.fit(X2D_train, y_train_01[label])
Out[64]:
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                   intercept_scaling=1, l1_ratio=None, max_iter=100,
                   multi_class='auto', n_jobs=None, penalty='l2',
                   random_state=42, solver='lbfgs', tol=0.0001, verbose=0,
                   warm_start=False)

Um noch nicht auf die Testdaten zurückgreifen zu müssen wird zur Bewertung eine Kreuzvalidierung durchgeführt:

In [65]:
from sklearn.model_selection import cross_val_score

log_full_cv = cross_val_score(
    log_clf_full, X2D_train, y_train_01[label], cv=10, scoring="accuracy"
)
In [66]:
def outputResults(scores):
    print("Genauigkeit bei der Kreuzvalidierung")
    print("- Mittelwert:", "{:.2f}".format(100 * scores.mean()), "%")
    print("- Standardabw.:", "{:.2f}".format(100 * scores.std()), "%")
    print("- 10. Perzentil:", "{:.2f}".format(100 * np.percentile(scores, 10), "%"))
In [67]:
outputResults(log_full_cv)
results.append(("Log_reg_full_cv", 100 * log_full_cv.mean()))
Genauigkeit bei der Kreuzvalidierung
- Mittelwert: 98.82 %
- Standardabw.: 0.51 %
- 10. Perzentil: 98.04

Interessanterweise hat dieser Klassifikator mit ca. 98,8 % auf dem zweidimensionalen Datensatz eine quasi identische Genauigkeit wie auf dem gesamten Datensatz mit über 100 Merkmalen.

Eine weitere Referenz ist die Genauigkeit mit rein zufällig ausgewählten Datenpunkten. Um diese zu ermitteln werden nachfolgend mehrfach Datenpunkte zufällig ausgewählt, das Modell mit ihnen trainiert und abschließend anhand der gesamten Trainingsdaten bewertet.

In [68]:
n_labeled = 10
In [69]:
def randomSemisupervisedLearning(X, y, n_labeled, runs=1000):
    scores = []

    # Initialisierung des Klassifikators
    clf = LogisticRegression(random_state=42)

    for i in range(runs):
        # Auswahl zufälliger Datenpunkte
        idx_rnd = pd.DataFrame(X).sample(n=n_labeled, random_state=i).index

        # Kontrolle ob sowohl Gut- als auch Schlechtteile ausgewählt wurden
        if y[idx_rnd].nunique() > 1:
            # Trainieren des Modells
            clf.fit(pd.DataFrame(X).iloc[idx_rnd], y.iloc[idx_rnd])

            # Genauigkeit des Modells abspeichern
            scores.append(clf.score(pd.DataFrame(X), y))

    outputResults(np.array(scores))
    return np.array(scores)
In [70]:
scores = randomSemisupervisedLearning(X2D_train, y_train_01[label], n_labeled=n_labeled)
results.append(("Log_reg_rnd", 100 * scores.mean()))
Genauigkeit bei der Kreuzvalidierung
- Mittelwert: 97.40 %
- Standardabw.: 2.46 %
- 10. Perzentil: 95.93

Auch mit nur 10 zufällig ausgewählten Datenpunkten erreicht der Klassifikator im Durchschnitt eine Genauigkeit von immerhin 97,4 %. Allerdings liegen 10 % der Klassifikatoren mit ihrer Genauigkeit unter 96,0 %. Folglich ist das Ziel des nachfolgenden Kapitels, mit 10 repräsentativ ausgewählten Datenpunkten eine Genauigkeit von min. 97,4 % und im Idealfall 99,0 % zu erreichen.

6.2.2 Auswahl durch Clustering

Nun kann das teilüberwachte Lernen durchgeführt werden. Zunächst werden durch den Clustering-Algorithmus die Cluster und deren Mittelpunkte bestimmt:

In [71]:
from sklearn.mixture import GaussianMixture

# Genauso viele Cluster wie Datenpunkte gelabelt werden sollen
gaus_mix = GaussianMixture(n_components=n_labeled, random_state=42)
gaus_mix.fit(X2D_train)
y_pred_cluster = gaus_mix.predict(X2D_train)

Als nächstes werden die Datenpunkte ausgewählt, welche den Mittelpunkten der Cluster am nächsten liegen:

In [72]:
from sklearn.metrics import pairwise_distances_argmin_min

closest, _ = pairwise_distances_argmin_min(gaus_mix.means_, X2D_train)
X2D_train_repr = X2D_train[closest]

Das Ergebnis stellt die nachfolgende Abbildung dar. Die gefundenen Datenpunkte sind als rote Punkte eingezeichnet:

In [73]:
plotX2DClustered(X2D_train, y_pred_cluster, cluster_centers=X2D_train_repr)
plt.show()
No description has been provided for this image

Im nächsten Schritt kann der Klassifikator mit diesen Datenpunkten trainiert und ausgewertet werden.

In [74]:
log_clf_repr = LogisticRegression(random_state=42)
log_clf_repr.fit(X2D_train[closest], y_train_01[label].iloc[closest])
Out[74]:
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                   intercept_scaling=1, l1_ratio=None, max_iter=100,
                   multi_class='auto', n_jobs=None, penalty='l2',
                   random_state=42, solver='lbfgs', tol=0.0001, verbose=0,
                   warm_start=False)
In [75]:
print("Genauigkeit nach Auswahl durch Clustering")
print("-", "{:.2f}".format(100 * log_clf_repr.score(X2D_train, y_train_01[label])), "%")
results.append(("Log_reg_repr", 100 * log_clf_repr.score(X2D_train, y_train_01[label])))
Genauigkeit nach Auswahl durch Clustering
- 98.52 %

Das Ergebnis ist mit 98,5 % deutlich besser als bei der rein zufälligen Auswahl mit 97,4 %, erreicht jedoch nicht die 99,0 %. Ein Propagieren der repräsentativen Label auf die anderen Datenpunkte im Cluster könnte eine weitere Verbesserung bringen:

In [76]:
y_train_01_prop = np.empty(len(y_train_01), dtype=np.int32)
for c in range(n_labeled):
    y_train_01_prop[y_pred_cluster == c] = y_train_01[label].iloc[closest][c]

Die aus den 10 repräsentativen Datenpunkten für den gesamten Datensatz abgeleiteten Label zeigt die nachfolgende Abbildung:

In [77]:
plotX2DClustered(X2D_train, y_train_01_prop, cluster_centers=X2D_train_repr)
No description has been provided for this image

Nun kann erneut ein Klassifikator trainiert und ausgewertet werden:

In [78]:
log_clf_prop = LogisticRegression(random_state=42)
log_clf_prop.fit(X2D_train, y_train_01_prop)

print("Genauigkeit nach Auswahl durch Clustering und Propagieren")
print("-", "{:.2f}".format(100 * log_clf_prop.score(X2D_train, y_train_01[label])), "%")
results.append(("Log_reg_prop", 100 * log_clf_prop.score(X2D_train, y_train_01[label])))
Genauigkeit nach Auswahl durch Clustering und Propagieren
- 98.65 %

Das Propagieren hat eine geringfügige Verbesserung auf 98,65 % gebracht, was nun beinahe der Referenz von 98,82 % entspricht. Abschließend wird dieses Ergebnis anhand der Testdaten überprüft:

In [79]:
print("Genauigkeit auf den Testdaten")
print(
    "- Überwachtes Lernen:",
    "{:.2f}".format(100 * log_clf_full.score(X2D_test, y_test_01[label])),
    "%",
)
print(
    "- Teilüberwachtes Lernen:",
    "{:.2f}".format(100 * log_clf_prop.score(X2D_test, y_test_01[label])),
    "%",
)

results.append(
    ("Log_reg_prop_test", 100 * log_clf_prop.score(X2D_test, y_test_01[label]))
)
Genauigkeit auf den Testdaten
- Überwachtes Lernen: 98.79 %
- Teilüberwachtes Lernen: 98.57 %

Die Genauigkeit auf den Testdaten ist beim überwachten und teilüberwachten ähnlich hoch und mit jeweils über 98,5 % ausreichend. Grundsätzlich stellt das teilüberwachte Lernen somit einen vielversprechenden Ansatz für Aufgaben dieser Art dar, denn in diesem Fall musste nur ca. 0,3 % (10 / 3600) des ursprünglichen Aufwands für das Labeln investiert werden.

6.2.3 Analyse der Fehler

Abschließend werden die Teile analysiert, welche beim Propagieren innerhalb der Cluster ein falsches Label erhalten haben:

In [80]:
false_pos = np.logical_and(y_train_01[label] == 0, y_train_01_prop == 1)
false_neg = np.logical_and(y_train_01[label] == 1, y_train_01_prop == 0)
In [81]:
plotX2D(X2D_train, y_train[label])

# Falsch positiv bzw. negativ klassifizierte Datenpunkte darstellen
plt.plot(
    X2D_train[false_pos][:, 0],
    X2D_train[false_pos][:, 1],
    "o",
    c="red",
    markeredgecolor="black",
    label="Falsch positiv",
)
plt.plot(
    X2D_train[false_neg][:, 0],
    X2D_train[false_neg][:, 1],
    "o",
    c="green",
    markeredgecolor="black",
    label="Falsch negativ",
)

plt.legend()
plt.show()
No description has been provided for this image

In der Abbildung sind als schwarz umrandete Punkte diejenigen Teile markiert, welche beim propagieren der repräsentativen Label ein falsches Label erhalten haben. Falsch positive Teile sind dabei rot, falsch negative Teile grün ausgefüllt. Grundsätzliche liegen diese Teile wie erwartet im Grenzbereich zwischen Gut- und Schlechtteilen. Auf den ersten Blick wirkt die dargestellte Klassifizierung nachvollziehbar. Bspw. erscheint es sinnvoll, dass das große Cluster der falsch positiven Teile (untere Hälfte der Abbildung) scheinbar dem rechten unteren Cluster an Fehlteilen zugeordnet wurde. Interessant ist das originale Label (0 - 3) dieser falsch klassifizierten Teile:

In [82]:
print("Ursprüngliches Label der falsch positiven Klassifizierungen")
print(y_train[label][false_pos].value_counts())
Ursprüngliches Label der falsch positiven Klassifizierungen
1    34
0     7
Name: 0_leak_corner_tr, dtype: int64

Die meisten dieser Teile hatten einen leichten Fehler (Stufe 1). Es ist nachvollziehbar, dass diese ähnlich wie die anderen Fehlteile (Stufe 2 und 3) eingeschätzt wurden. Teile mit einem leichten Fehler unterscheiden sich grundsätzlich von den vollständig fehlerfreien Teilen. Dies deuten auch die Cluster in der Abbildung an. Nachfolgend wird der Klassifikator aus dem teilüberwachten nochmal ausgewertet, diesmal werden jedoch auch leichte Fehler der positiven Kategorie zugeordnet:

In [83]:
y_train_01_alt = y_train.copy()
y_train_01_alt.replace(1, 1, inplace=True)
y_train_01_alt.replace(2, 1, inplace=True)
y_train_01_alt.replace(3, 1, inplace=True)
In [84]:
print("Genauigkeit mit alternativem Label:")
print(
    "-",
    "{:.2f}".format(100 * log_clf_prop.score(X2D_train, y_train_01_alt[label])),
    "%",
)
results.append(
    ("Log_reg_prop_1-3", 100 * log_clf_prop.score(X2D_train, y_train_01_alt[label]))
)
Genauigkeit mit alternativem Label:
- 99.15 %

Auf den Testdaten ist das Ergebnis ebenfalls besser:

In [85]:
y_test_01_alt = y_test.copy()
y_test_01_alt.replace(1, 1, inplace=True)
y_test_01_alt.replace(2, 1, inplace=True)
y_test_01_alt.replace(3, 1, inplace=True)
In [86]:
print("Genauigkeit mit alternativem Label:")
print(
    "-", "{:.2f}".format(100 * log_clf_prop.score(X2D_test, y_test_01_alt[label])), "%"
)
results.append(
    ("Log_reg_prop_1-3_test", 100 * log_clf_prop.score(X2D_test, y_test_01_alt[label]))
)
Genauigkeit mit alternativem Label:
- 98.90 %

Je nach Problemstellung sollte somit gut abgewogen werden, ob bei einer binären Klassifikation Teile mit einem leichten Fehler als fehlerfrei oder fehlerhaft eingestuft werden.

7. Ergebnisse und Evaluation

Abschließend können die Ergebnisse zusammengefasst und kritisch bewertet werden. Dazu werden nachfolgend die Genauigkeiten der im Rahmen dieser Arbeit trainierten Klassifikatoren dargestellt:

In [87]:
# Für die Darstellung in DataFrame umwandeln
results_data = {
    "Klassifikator": np.array(results)[:, 0],
    "Genauigkeit [%]": np.array(results)[:, 1].astype(float),
}
results_df = pd.DataFrame(results_data).set_index("Klassifikator")

# Spalte für das Ergebnis auf den Testdaten hinzufügen
results_test = results_df[results_df.index.str.contains("_test")]
results_test.index = results_test.index.str.replace("_test", "")
results_test.columns = ["Test [%]"]

# Spalte für das Ergebnis auf den Trainingsdaten anpassen
results_training = results_df[np.invert(results_df.index.str.contains("_test"))]
results_training.index = results_training.index.str.replace("_cv", "")
results_training.columns = ["Training [%]"]

# Spalten kombinieren
results_df = pd.concat([results_training, results_test], axis=1)
results_df = results_df.reset_index()
results_df = results_df.rename(columns={"index": "Klassifikator"})

# Formatierung
style = results_df.style
style = style.format({"Test [%]": "{:.1f}"})
style = style.format({"Training [%]": "{:.1f}"})
style = style.set_properties(**{"text-align": "left"})
style = style.set_properties(**{"text-align": "right"}, subset=["Test [%]"])
style = style.set_properties(**{"text-align": "right"}, subset=["Training [%]"])
style = style.background_gradient(cmap="plasma", subset=["Training [%]"])
style = style.hide_index()
style
Out[87]:
<style type="text/css"> #T_68f82ce2_f214_11eb_a746_0242ac1c0002row0_col0,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row1_col0,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row2_col0,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row3_col0,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row4_col0,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row5_col0,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row6_col0,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row7_col0{ text-align: left; }#T_68f82ce2_f214_11eb_a746_0242ac1c0002row0_col1{ text-align: left; text-align: right; background-color: #fdaf31; color: #000000; }#T_68f82ce2_f214_11eb_a746_0242ac1c0002row0_col2,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row1_col2,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row2_col2,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row3_col2,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row4_col2,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row5_col2,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row6_col2,#T_68f82ce2_f214_11eb_a746_0242ac1c0002row7_col2{ text-align: left; text-align: right; }#T_68f82ce2_f214_11eb_a746_0242ac1c0002row1_col1{ text-align: left; text-align: right; background-color: #f4ed27; color: #000000; }#T_68f82ce2_f214_11eb_a746_0242ac1c0002row2_col1{ text-align: left; text-align: right; background-color: #f0f921; color: #000000; }#T_68f82ce2_f214_11eb_a746_0242ac1c0002row3_col1{ text-align: left; text-align: right; background-color: #f99a3e; color: #000000; }#T_68f82ce2_f214_11eb_a746_0242ac1c0002row4_col1{ text-align: left; text-align: right; background-color: #0d0887; color: #f1f1f1; }#T_68f82ce2_f214_11eb_a746_0242ac1c0002row5_col1{ text-align: left; text-align: right; background-color: #e16462; color: #000000; }#T_68f82ce2_f214_11eb_a746_0242ac1c0002row6_col1{ text-align: left; text-align: right; background-color: #ee7b51; color: #000000; }#T_68f82ce2_f214_11eb_a746_0242ac1c0002row7_col1{ text-align: left; text-align: right; background-color: #f8df25; color: #000000; }</style>
Klassifikator Training [%] Test [%]
Tree 98.9 98.9
Log_reg 99.2 99.2
Forest 99.3 99.3
Log_reg_full 98.8 nan
Log_reg_rnd 97.4 nan
Log_reg_repr 98.5 nan
Log_reg_prop 98.7 98.6
Log_reg_prop_1-3 99.1 98.9

Die Genauigkeit auf den Trainingsdaten wurde mittels Kreuzvalidierung bestimmt und ist deshalb stets ähnlich hoch wie die Genauigkeit auf den Testdaten. Grundsätzlich erreichen alle Klassifikatoren mit über 97,0 % eine relativ hohe Genauigkeit. Die untersuchten Fehler lassen sich sehr gut durch ML-Algorithmen erkennen.

Bereits ein Entscheidungsbaum (Tree, Kap. 4) erreicht mit einer einzigen Aufteilung eine Genauigkeit von 98,9 % auf den Testdaten. Mit Hilfe logistischer Regression (Log_reg, Kap. 5.3) bzw. eines Random Forests (Forest, Kap. 5.4) lässt sich diese Genauigkeit auf über 99,2 % steigern. Problematisch waren dabei vor allen diejenigen Teile, welche sich am Rand der binären Entscheidungsgrenze zwichen Gut- und Schlechtteil befanden.

In Kap. 6.1 hat sich gezeigt, dass sich die Dimension des Merkmalsraums für diesen Datensatz unter Beibehaltung eines Großteils seiner Varianz auf zwei oder drei reduzieren lässt. Auch in diesem reduzierten Merkmalsraum erzielte die logistische Regression (Log_reg_full) noch eine Genauigkeit von 98,8 %. Mit Hilfe eines Gaußschen Mischverteilungsmodells ließen sich anschließend die zuvor beobachteten Cluster gut erkennen und für das teilüberwachte Lernen nutzen.

Das Kapitel 6.2 zum teilüberwachten Lernen hat gezeigt, dass es für diese Art von Daten nicht notwendig ist, sämtliche Datenpunkte zu labeln. So erreicht eine logistische Regression, welche auf 10 zufällig ausgewählten Datenpunkten trainiert wurde (Log_reg_rnd) im Mittel eine Genauigkeit von 97,4 %. Werden auf Basis der erkannten Cluster 10 repräsentative Datenpunkte gelabelt (Log_reg_repr), steigt diese Genauigkeit auf 98,2 %. Ein Propagieren der Label auf alle weiteren Datenpunkte im jeweiligen Cluster (Log_reg_prop) erhöhte die Genauigkeit weiter auf 98,6 %. Dieses Ergebnis liegt nur noch minimal unter den Ergebnissen der auf dem gesamten Datensatz trainierten Klassifikatoren.

Zusammenfassend kann festgehalten werden, dass sich die untersuchten Fehler durch teilüberwachtes Lernen mit einem sehr geringen Aufwand und einer dennoch sehr hohen Genauigkeit von über 98,5 % erkennen lassen. Dafür waren relativ einfache lineare Machine-Learning-Modelle ausreichend.

Die Untersuchung hat jedoch auch gezeigt, dass sowohl mehrere Cluster mit Gut- als auch mit Schlechtteilen entstehen können. Es ist ungewiss, ob auch komplett neue Cluster den Regeln folgen, welche die im Rahmen dieser Arbeit trainierten Algorithmen gelernet haben. Allerdings stellt auch bei diesem Problem das teilüberwachte Lernen einen vielversprechenden Lösungsansatz dar.

Ungewiss ist ebenfalls, wie gut sich diese Vorgehensweise auf andere Fehler übertragen lässt. Die untersuchten Fehler traten relativ häufig und in Clustern auf. Seltene Fehler, welche darüber hinaus sehr stark verstreut sind, würden vom Clustering und damit vom teilüberwachten Lernen nicht möglicherweise nicht erfasst. Ein Beispiel ist der Fehler 1_hole_bottom im Datensatz, welcher nur ein paar Mal aufgetreten ist.

Eine Herausforderung für den beschriebenen Lösungsansatz wäre es außerdem, wenn ein neuer Datensatz sich nicht auf relativ wenige Dimensionen reduzieren lässt, ohne einen zu großen Anteil seiner Varianz zu verlieren. Die resultierende geringe Dichte an Datenpunkten im Merkmalsraum könnte das Clustering erschweren. Zu demselben Problem würde eine zu geringe Anzahl an Datenpunkten führen. Dies ist im Spritzguss jedoch in der Regel kein Problem.

8. Ausblick

Grundsätzlich bildet diese Arbeit die Grundlage für eine Vielzahl möglicher Weiterentwicklungen. Mit einem System, welches die Prozessdaten regelmäßig auf neue Cluster untersucht und Fotos repräsentativer Teile zur Beurteilung an das Fachpersonal schickt, könnte der in dieser Arbeit beschriebenen Lösungsansatz in die Praxis überführt werden. Dabei könnten auch Aspekte des aktiven Lernens berücksichtigt werden. Im Zuge dessen könnte das System ebenfalls auf weitere Fehlertypen und Produkte übertragen werden. Es sind jedoch die in der kritischen Auseinandersetzung beschriebenen Aspekte zu berücksichtigen.

In der kritischen Auseinandersetzung wurde ebenfalls das Problem angesprochen, dass andere Fehlertypen selten und weit verstreut sein könnten. Um auch diese zu erkennen könnte die erarbeitete Lösung um eine Anomalieerkennung ergänzt werden. Das bereits implementierte Clustering mittels Gaußschem Mischverteilungsmodell bietet durch die bereitgestellten Wahrscheinlichkeitsdichtefunktionen eine sehr gute Grundlage dafür.

Des Weiteren könnten Zeitreihenanalysen auf dem vorliegenden Datensatz durchgeführt werden, um den Ursprung der Fehler zu finden und diese gar nicht erst entstehen zu lassen.

Literaturverzeichnis

[1] L. Schauerte, Vorstudie zum Potenzial des Data Mining im Spritzguss zur Verringerung von Produktionsfehlern, 2021

[2] Gustav Hensel GmbH & Co. KG, Available: https://www.hensel-electric.de, 2021

[3] Aurélien Géron, Praxiseinstieg Machine Learning mit Scikit-Learn und TensorFlow, 2018, O'Reilly Verlag

[4] L. Breiman, J. H. Friedman, R. A. Olshen, C. J. Stone: CART: Classification and Regression Trees, 1984.

[5] L. Breiman, Random forests. In: Machine Learning, 2001, Seite 532

[6] G. H. Dunteman: Principal Component Analysis, 1989, Sage Publications

[7] Ch. Fraley, A. Raftery, Normal Mixture Modeling and Model-Based Clustering, 2015

image.png