Klassifikation#

Praxisbeispiel: Texte klassifizieren#

Schritt 1+2: Daten#

Wir benutzen einen Teil des “20 Newsgroups”-Korpus. Es handelt sich um Diskussionsforen zu einem bestimmten Thema, eine Art prähistorisches Reddit. Es gibt insgesamt knapp 19k Datenpunkte, dabei sind aber nicht alle Gruppen gleich stark vertreten. Die Daten wurden Mitte der 90er Jahre gesammelt und werden seitdem als Beispieldatensatz für die Textklassifizierung genutzt.

Die Aufgabe ist, die Posts ihren Newsgroups zuzuordnen.

Wir betrachten vier gut gegen einander abgrenzbare Gruppen: alt.atheism, talk.religion.misc, comp.graphics und sci.space. Der Use Case ist inspiriert von einem sklearn-Beispiel.

# Schritt 1: Daten aufbereiten
# -- wir verwenden ein Standardcorpus und wählen einen Teil davon aus.
# Wir möchten die Daten zusätzlich um Text bereinigen, der nicht zur Diskussion gehört (wie headers und footers)
# oder der schon anderweitig belegt ist (quotes aus vorherigen Nachrichten).

categories = [
        'alt.atheism',
        'talk.religion.misc',
        'comp.graphics',
        'sci.space',
    ]

remove = ('headers', 'footers', 'quotes')
# Schritt 2: Daten in Training und Test teilen
# -- das Korpus ist schon entsprechend unterteilt; wir laden train und test getrennt herunter.

from sklearn.datasets import fetch_20newsgroups


data_train = fetch_20newsgroups(subset='train', categories=categories,
                                shuffle=True, random_state=42,
                                remove=remove)

data_test = fetch_20newsgroups(subset='test', categories=categories,
                               shuffle=True, random_state=42,
                               remove=remove)
# Wenn die Daten noch (weiter) aufgeteilt werden müssen, geht das am besten mit der 
# Methode sklearn.model_selection.train_test_split
# Sie liefert Features und Zielklassen für test und train zurück und lässt sich umfassend parametrisieren.

# Wir können also noch Entwicklungsdaten erzeugen, die 20% der Trainingsdaten umfassen und alle vier Zielklassen 
# gleichermaßen berücksichtigen (stratifizieren):
from sklearn.model_selection import train_test_split

X_train, X_dev, y_train, y_dev = train_test_split(data_train['data'], data_train['target'], 
                                                    test_size=0.2, 
                                                    random_state=42,
                                                    stratify=data_train['target'])

Schritt 3a: Geeignete Features berechnen#

from sklearn.feature_extraction.text import TfidfVectorizer

# Vektorisierer-Objekt anlegen

vectorizer = TfidfVectorizer(max_df=0.5, analyzer='word')

# andere mögliche Parameter wären max_df= 0.75 oder 1.0, analyzer = 'char'

Schritt 3b: Geeignete Features auswählen#

# Strategie 3: Linear SVC (lineare Support Vector Classification) gibt die Feature-Wichtigkeit aus. Parameter des
# modellbasierten Auswahlansatzes ist der Schwellwert, ab dem Features akzeptiert werden.

from sklearn.feature_selection import SelectFromModel
from sklearn.svm import LinearSVC

feature_selection = SelectFromModel(LinearSVC(penalty="l1", dual=False), threshold='mean')

# alternativer Parameter: threshold=None, es wird ein absoluter default-Schwellwert verwendet 

Schritt 4: Parameter des Algorithmus setzen#

from sklearn.pipeline import Pipeline
from sklearn.svm import SVC

# Lerner
classifier = SVC(kernel='linear')

# alternativer Parameter: kernel='rbf'


# Pipeline definieren -- die oben festgelegten Parameter werden verwendet

pipeline = Pipeline([('vectorizer', vectorizer), ('feature_selection', feature_selection),
                     ('classifier', classifier)])

# Pipeline auf 80% der Trainingsdaten laufen lassen
pipeline.fit(X_train, y_train)

# Vorhersage für 20% der Trainingsdaten (development-Daten) machen
dev_labels = pipeline.predict(X_dev)

# Evaluieren
#...

# noch 11x für die anderen Parameterkombinationen durchführen; Evaluationsergebnisse vergleichen

Dieser Ansatz funktioniert und ist sinnvoll, wenn Sie viele Trainingsdaten haben und wenig Parameter setzen müssen. Wenn wir aber einen Algorithmus austauschen oder neue Parameter(werte) bei den alten Ansätzen hinzufügen wollen, ist das aufwändig und fehleranfällig.

Wir verwenden deshalb stattdessen eine Pipeline und führen Grid Search auf allen Parameterkombinationen durch. Die Pipeline sorgt dafür, dass eine Reihe von Datentransformationen (Feature-Berechnung/Auswahl) automatisch durchgeführt und an einen Estimator (unseren Lerner) weitergegeben wird. Der Grid Search-Schritt führt eine Kreuzvalidierung auf den Trainingsdaten aus, die die Trainingsdaten (anders als unsere harte Aufteilung oben) optimal ausnutzt und genauso dafür sorgt, dass die Testdaten unangetastet bleiben können.

from sklearn.model_selection import GridSearchCV

# Pipeline neu definieren - ohne Parametersetzen 

vectorizer = TfidfVectorizer()
feature_selection=SelectFromModel(LinearSVC(penalty="l1", dual=False))
classifier=SVC()

pipeline = Pipeline([('vectorizer', vectorizer), ('feature_selection', feature_selection),
                     ('classifier', classifier)])

# Parameterraum definieren: key ist schrittname__parametername, value die zu prüfenden Werte

parameters = {
    'vectorizer__max_df': (0.5, 0.75, 1.0), 
    'vectorizer__analyzer': ('word', 'char'),  
    'feature_selection__threshold': (None, 'mean'), 
    'classifier__kernel': ('linear','rbf')
}

# Suche über den gesamten Parameterraum (cross validation über die Trainingsdaten)
grid_search = GridSearchCV(pipeline, param_grid=parameters, verbose=10)

grid_search.fit(data_train['data'], data_train['target'])
Fitting 5 folds for each of 24 candidates, totalling 120 fits
[CV 1/5; 1/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.5
[CV 1/5; 1/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.5;, score=0.781 total time=   0.9s
[CV 2/5; 1/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.5
[CV 2/5; 1/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.5;, score=0.744 total time=   0.9s
[CV 3/5; 1/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.5
[CV 3/5; 1/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.5;, score=0.779 total time=   1.0s
[CV 4/5; 1/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.5
[CV 4/5; 1/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.5;, score=0.771 total time=   1.2s
[CV 5/5; 1/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.5
[CV 5/5; 1/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.5;, score=0.766 total time=   1.1s
[CV 1/5; 2/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.75
[CV 1/5; 2/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.75;, score=0.786 total time=   1.3s
[CV 2/5; 2/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.75
[CV 2/5; 2/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.75;, score=0.737 total time=   1.2s
[CV 3/5; 2/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.75
[CV 3/5; 2/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.75;, score=0.767 total time=   1.3s
[CV 4/5; 2/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.75
[CV 4/5; 2/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.75;, score=0.769 total time=   1.3s
[CV 5/5; 2/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.75
[CV 5/5; 2/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=0.75;, score=0.766 total time=   1.1s
[CV 1/5; 3/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=1.0
[CV 1/5; 3/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=1.0;, score=0.791 total time=   1.0s
[CV 2/5; 3/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=1.0
[CV 2/5; 3/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=1.0;, score=0.752 total time=   1.2s
[CV 3/5; 3/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=1.0
[CV 3/5; 3/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=1.0;, score=0.764 total time=   1.3s
[CV 4/5; 3/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=1.0
[CV 4/5; 3/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=1.0;, score=0.762 total time=   1.3s
[CV 5/5; 3/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=1.0
[CV 5/5; 3/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=word, vectorizer__max_df=1.0;, score=0.773 total time=   1.3s
[CV 1/5; 4/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.5
[CV 1/5; 4/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.5;, score=0.455 total time=   0.6s
[CV 2/5; 4/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.5
[CV 2/5; 4/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.5;, score=0.425 total time=   0.6s
[CV 3/5; 4/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.5
[CV 3/5; 4/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.5;, score=0.428 total time=   0.6s
[CV 4/5; 4/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.5
[CV 4/5; 4/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.5;, score=0.420 total time=   0.6s
[CV 5/5; 4/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.5
[CV 5/5; 4/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.5;, score=0.448 total time=   0.6s
[CV 1/5; 5/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.75
[CV 1/5; 5/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.75;, score=0.464 total time=   0.6s
[CV 2/5; 5/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.75
[CV 2/5; 5/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.75;, score=0.432 total time=   0.6s
[CV 3/5; 5/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.75
[CV 3/5; 5/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.75;, score=0.415 total time=   0.6s
[CV 4/5; 5/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.75
[CV 4/5; 5/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.75;, score=0.425 total time=   0.6s
[CV 5/5; 5/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.75
[CV 5/5; 5/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=0.75;, score=0.458 total time=   0.6s
[CV 1/5; 6/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=1.0
[CV 1/5; 6/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=1.0;, score=0.474 total time=   1.0s
[CV 2/5; 6/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=1.0
[CV 2/5; 6/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=1.0;, score=0.486 total time=   1.0s
[CV 3/5; 6/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=1.0
[CV 3/5; 6/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=1.0;, score=0.491 total time=   1.0s
[CV 4/5; 6/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=1.0
[CV 4/5; 6/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=1.0;, score=0.479 total time=   1.0s
[CV 5/5; 6/24] START classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=1.0
[CV 5/5; 6/24] END classifier__kernel=linear, feature_selection__threshold=None, vectorizer__analyzer=char, vectorizer__max_df=1.0;, score=0.441 total time=   1.0s
[CV 1/5; 7/24] START classifier__kernel=linear, feature_selection__threshold=mean, vectorizer__analyzer=word, vectorizer__max_df=0.5
[CV 1/5; 7/24] END classifier__kernel=linear, feature_selection__threshold=mean, vectorizer__analyzer=word, vectorizer__max_df=0.5;, score=0.784 total time=   1.2s
[CV 2/5; 7/24] START classifier__kernel=linear, feature_selection__threshold=mean, vectorizer__analyzer=word, vectorizer__max_df=0.5
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
/tmp/ipykernel_880/2912650220.py in <module>
     22 grid_search = GridSearchCV(pipeline, param_grid=parameters, verbose=10)
     23 
---> 24 grid_search.fit(data_train['data'], data_train['target'])

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/model_selection/_search.py in fit(self, X, y, groups, **fit_params)
    889                 return results
    890 
--> 891             self._run_search(evaluate_candidates)
    892 
    893             # multimetric is determined here because in the case of a callable

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/model_selection/_search.py in _run_search(self, evaluate_candidates)
   1390     def _run_search(self, evaluate_candidates):
   1391         """Search all candidates in param_grid"""
-> 1392         evaluate_candidates(ParameterGrid(self.param_grid))
   1393 
   1394 

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/model_selection/_search.py in evaluate_candidates(candidate_params, cv, more_results)
    849                     )
    850                     for (cand_idx, parameters), (split_idx, (train, test)) in product(
--> 851                         enumerate(candidate_params), enumerate(cv.split(X, y, groups))
    852                     )
    853                 )

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/joblib/parallel.py in __call__(self, iterable)
   1861             output = self._get_sequential_output(iterable)
   1862             next(output)
-> 1863             return output if self.return_generator else list(output)
   1864 
   1865         # Let's create an ID that uniquely identifies the current call. If the

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/joblib/parallel.py in _get_sequential_output(self, iterable)
   1790                 self.n_dispatched_batches += 1
   1791                 self.n_dispatched_tasks += 1
-> 1792                 res = func(*args, **kwargs)
   1793                 self.n_completed_tasks += 1
   1794                 self.print_progress()

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/utils/fixes.py in __call__(self, *args, **kwargs)
    214     def __call__(self, *args, **kwargs):
    215         with config_context(**self.config):
--> 216             return self.function(*args, **kwargs)
    217 
    218 

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/model_selection/_validation.py in _fit_and_score(estimator, X, y, scorer, train, test, verbose, parameters, fit_params, return_train_score, return_parameters, return_n_test_samples, return_times, return_estimator, split_progress, candidate_progress, error_score)
    678             estimator.fit(X_train, **fit_params)
    679         else:
--> 680             estimator.fit(X_train, y_train, **fit_params)
    681 
    682     except Exception:

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/pipeline.py in fit(self, X, y, **fit_params)
    388         """
    389         fit_params_steps = self._check_fit_params(**fit_params)
--> 390         Xt = self._fit(X, y, **fit_params_steps)
    391         with _print_elapsed_time("Pipeline", self._log_message(len(self.steps) - 1)):
    392             if self._final_estimator != "passthrough":

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/pipeline.py in _fit(self, X, y, **fit_params_steps)
    353                 message_clsname="Pipeline",
    354                 message=self._log_message(step_idx),
--> 355                 **fit_params_steps[name],
    356             )
    357             # Replace the transformer of the step with the fitted

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/joblib/memory.py in __call__(self, *args, **kwargs)
    351 
    352     def __call__(self, *args, **kwargs):
--> 353         return self.func(*args, **kwargs)
    354 
    355     def call_and_shelve(self, *args, **kwargs):

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/pipeline.py in _fit_transform_one(transformer, X, y, weight, message_clsname, message, **fit_params)
    891     with _print_elapsed_time(message_clsname, message):
    892         if hasattr(transformer, "fit_transform"):
--> 893             res = transformer.fit_transform(X, y, **fit_params)
    894         else:
    895             res = transformer.fit(X, y, **fit_params).transform(X)

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/feature_extraction/text.py in fit_transform(self, raw_documents, y)
   2075         """
   2076         self._check_params()
-> 2077         X = super().fit_transform(raw_documents)
   2078         self._tfidf.fit(X)
   2079         # X is already a transformed view of raw_documents so

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/feature_extraction/text.py in fit_transform(self, raw_documents, y)
   1328                     break
   1329 
-> 1330         vocabulary, X = self._count_vocab(raw_documents, self.fixed_vocabulary_)
   1331 
   1332         if self.binary:

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/sklearn/feature_extraction/text.py in _count_vocab(self, raw_documents, fixed_vocab)
   1244             dtype=self.dtype,
   1245         )
-> 1246         X.sort_indices()
   1247         return vocabulary, X
   1248 

/builds/speiser/vl-data-analytics/venv/lib/python3.7/site-packages/scipy/sparse/compressed.py in sort_indices(self)
   1151         if not self.has_sorted_indices:
   1152             _sparsetools.csr_sort_indices(len(self.indptr) - 1, self.indptr,
-> 1153                                           self.indices, self.data)
   1154             self.has_sorted_indices = True
   1155 

KeyboardInterrupt: 

Aufgabe: Warum führt das Grid Search 120 Läufe aus? Wir hatten doch 12 Parameterkombinationen ausgerechnet?

# Welche Parameterkombination ist die beste?

print(grid_search.best_estimator_)

# Wenn kein expliziter Parameter angegeben ist, hat der default am besten funktioniert.
# Wir wählen also 
#'vectorizer__max_df': 0.5 
# 'vectorizer__analyzer': 'word',  
# 'feature_selection__threshold': None, 
# 'classifier__kernel': 'rbf'
Pipeline(steps=[('vectorizer', TfidfVectorizer(max_df=0.5)),
                ('feature_selection',
                 SelectFromModel(estimator=LinearSVC(dual=False, penalty='l1'),
                                 threshold='mean')),
                ('classifier', SVC())])
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.model_selection import cross_val_predict

# Pipeline für die beste Feature-Kombination definieren
final_pipeline = Pipeline(steps=[('vectorizer', TfidfVectorizer(max_df=0.5)),
                ('feature_selection',
                 SelectFromModel(estimator=LinearSVC(dual=False,
                                                     penalty='l1'),threshold='mean')),
                ('classifier', SVC())])

# Wie gut ist der fertige Lerner auf den Trainingsdaten? 
# Evaluation per Crossvalidation (analog zur Parametersuche)
# Mit cross_val_predict merken wir uns die Vorhersage für jeden Datenpunkt, die gemacht wird, wenn er zum Testset 
# gehört; die Vorhersagen sind also ungesehen und liegen für den gesamten Datensatz vor.

train_labels = cross_val_predict(final_pipeline, data_train['data'], data_train['target'], cv=10)

# Precision/Recall/F-Wert berechnen

print(classification_report(data_train['target'], train_labels))
              precision    recall  f1-score   support

           0       0.73      0.77      0.75       480
           1       0.90      0.89      0.90       584
           2       0.76      0.89      0.82       593
           3       0.80      0.54      0.64       377

    accuracy                           0.80      2034
   macro avg       0.80      0.77      0.78      2034
weighted avg       0.80      0.80      0.79      2034

Schritt 5: Vorhersagen auf Testdaten machen und evaluieren#

from sklearn.metrics import classification_report, confusion_matrix

# Jetzt den Lerner ein letztes Mal auf allen Trainingsdaten trainieren und dann auf den Testdaten evaluieren

# Lerner auf den gesamten Trainingsdaten trainieren
final_pipeline.fit(data_train['data'], data_train['target'])

# Lerner auf den Testdaten evaluieren

# Mit dem default score des Lerners: (durchschnittliche Accuracy bei SVC)

print("Default-Score des Klassifizierers: Accuracy=",final_pipeline.score(data_test['data'], data_test['target']), "\n")

# Labels vorhersagen lassen und dann Precision/Recall/F-Wert berechnen
test_labels = final_pipeline.predict(data_test['data'])

print(classification_report(data_test['target'], test_labels))
Default-Score des Klassifizierers: Accuracy= 0.738359201773836 

              precision    recall  f1-score   support

           0       0.64      0.63      0.64       319
           1       0.86      0.84      0.85       389
           2       0.72      0.88      0.79       394
           3       0.69      0.50      0.58       251

    accuracy                           0.74      1353
   macro avg       0.73      0.71      0.71      1353
weighted avg       0.74      0.74      0.73      1353

Aufgabe: Interpretieren Sie die Ausgabe des Classification Report im Hinblick auf Precision, Recall und F-Score. Sie können die Konfusionsmatrix berechnen und zu Hilfe nehmen.

  • Welche Zielklasse ist am einfachsten zu lernen?

  • Wie hat sich das Ergebnis gegenüber den Trainingsdaten verändert?

  • Was bedeutet es, wenn die Precision höher ist als der Recall, oder umgekehrt?

  • Wenn Sie die Pipeline auf äquivalenten Daten produktiv einsetzen würden, wie viel Prozent falsche Vorhersagen sind zu erwarten?

Aufgabe:

  1. Recherchieren Sie eine weitere Strategie zur Featurauswahl samt Parametern und setzen Sie sie in die Grid-Search-Pipeline ein. Vergleichen Sie dann unser bisheriges bestes Vorgehen und das neue beste Vorgehen. Sie dürfen auch gern mit anderen Pipeline-Schritten experimentieren.

  2. Welches Risiko bringt es mit sich, wenn Sie Ihre Ergebnisse immer wieder auf den Testdaten vergleichen?