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:
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.
Welches Risiko bringt es mit sich, wenn Sie Ihre Ergebnisse immer wieder auf den Testdaten vergleichen?