Column Transformer mit heterogenen Datenquellen#

Datensätze können oft Komponenten enthalten, die unterschiedliche Feature-Extraktions- und Verarbeitungspipelines erfordern. Dieses Szenario kann auftreten, wenn

  1. Ihr Datensatz aus heterogenen Datentypen besteht (z. B. Rasterbilder und Textbeschreibungen),

  2. Ihr Datensatz in einem pandas.DataFrame gespeichert ist und unterschiedliche Spalten unterschiedliche Verarbeitungspipelines erfordern.

Dieses Beispiel zeigt, wie ColumnTransformer auf einem Datensatz mit unterschiedlichen Feature-Typen verwendet wird. Die Wahl der Features ist nicht besonders hilfreich, dient aber zur Veranschaulichung der Technik.

# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause

import numpy as np

from sklearn.compose import ColumnTransformer
from sklearn.datasets import fetch_20newsgroups
from sklearn.decomposition import PCA
from sklearn.feature_extraction import DictVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import classification_report
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import FunctionTransformer
from sklearn.svm import LinearSVC

20 Newsgroups Dataset#

Wir verwenden das 20 Newsgroups Dataset, das Beiträge aus Newsgroups zu 20 Themen umfasst. Dieses Dataset ist in Trainings- und Test-Subsets unterteilt, basierend auf Nachrichten, die vor und nach einem bestimmten Datum gepostet wurden. Wir werden nur Beiträge aus 2 Kategorien verwenden, um die Laufzeit zu verkürzen.

categories = ["sci.med", "sci.space"]
X_train, y_train = fetch_20newsgroups(
    random_state=1,
    subset="train",
    categories=categories,
    remove=("footers", "quotes"),
    return_X_y=True,
)
X_test, y_test = fetch_20newsgroups(
    random_state=1,
    subset="test",
    categories=categories,
    remove=("footers", "quotes"),
    return_X_y=True,
)

Jedes Feature umfasst Meta-Informationen zu diesem Beitrag, wie z. B. den Betreff und den Inhalt des Newsgroup-Beitrags.

print(X_train[0])
From: mccall@mksol.dseg.ti.com (fred j mccall 575-3539)
Subject: Re: Metric vs English
Article-I.D.: mksol.1993Apr6.131900.8407
Organization: Texas Instruments Inc
Lines: 31




American, perhaps, but nothing military about it.  I learned (mostly)
slugs when we talked English units in high school physics and while
the teacher was an ex-Navy fighter jock the book certainly wasn't
produced by the military.

[Poundals were just too flinking small and made the math come out
funny; sort of the same reason proponents of SI give for using that.]

--
"Insisting on perfect safety is for people who don't have the balls to live
 in the real world."   -- Mary Shafer, NASA Ames Dryden

Erstellen von Transformern#

Zuerst wünschen wir uns einen Transformer, der den Betreff und den Inhalt jedes Beitrags extrahiert. Da dies eine zustandslose Transformation ist (keine Zustandsinformationen aus Trainingsdaten benötigt), können wir eine Funktion definieren, die die Datentransformation durchführt, und dann FunctionTransformer verwenden, um einen scikit-learn-Transformer zu erstellen.

def subject_body_extractor(posts):
    # construct object dtype array with two columns
    # first column = 'subject' and second column = 'body'
    features = np.empty(shape=(len(posts), 2), dtype=object)
    for i, text in enumerate(posts):
        # temporary variable `_` stores '\n\n'
        headers, _, body = text.partition("\n\n")
        # store body text in second column
        features[i, 1] = body

        prefix = "Subject:"
        sub = ""
        # save text after 'Subject:' in first column
        for line in headers.split("\n"):
            if line.startswith(prefix):
                sub = line[len(prefix) :]
                break
        features[i, 0] = sub

    return features


subject_body_transformer = FunctionTransformer(subject_body_extractor)

Wir erstellen auch einen Transformer, der die Länge des Textes und die Anzahl der Sätze extrahiert.

def text_stats(posts):
    return [{"length": len(text), "num_sentences": text.count(".")} for text in posts]


text_stats_transformer = FunctionTransformer(text_stats)

Klassifikationspipeline#

Die folgende Pipeline extrahiert den Betreff und den Inhalt jedes Beitrags mit SubjectBodyExtractor und erzeugt ein Array der Größe (n_samples, 2). Dieses Array wird dann verwendet, um Standard-Bag-of-Words-Features für den Betreff und den Inhalt sowie Textlänge und Satzanzahl im Inhalt mit ColumnTransformer zu berechnen. Wir kombinieren diese mit Gewichten und trainieren dann einen Klassifikator auf dem kombinierten Feature-Set.

pipeline = Pipeline(
    [
        # Extract subject & body
        ("subjectbody", subject_body_transformer),
        # Use ColumnTransformer to combine the subject and body features
        (
            "union",
            ColumnTransformer(
                [
                    # bag-of-words for subject (col 0)
                    ("subject", TfidfVectorizer(min_df=50), 0),
                    # bag-of-words with decomposition for body (col 1)
                    (
                        "body_bow",
                        Pipeline(
                            [
                                ("tfidf", TfidfVectorizer()),
                                ("best", PCA(n_components=50, svd_solver="arpack")),
                            ]
                        ),
                        1,
                    ),
                    # Pipeline for pulling text stats from post's body
                    (
                        "body_stats",
                        Pipeline(
                            [
                                (
                                    "stats",
                                    text_stats_transformer,
                                ),  # returns a list of dicts
                                (
                                    "vect",
                                    DictVectorizer(),
                                ),  # list of dicts -> feature matrix
                            ]
                        ),
                        1,
                    ),
                ],
                # weight above ColumnTransformer features
                transformer_weights={
                    "subject": 0.8,
                    "body_bow": 0.5,
                    "body_stats": 1.0,
                },
            ),
        ),
        # Use an SVC classifier on the combined features
        ("svc", LinearSVC(dual=False)),
    ],
    verbose=True,
)

Schließlich passen wir unsere Pipeline an die Trainingsdaten an und verwenden sie, um Themen für X_test vorherzusagen. Die Leistungskennzahlen unserer Pipeline werden dann ausgegeben.

pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
print("Classification report:\n\n{}".format(classification_report(y_test, y_pred)))
[Pipeline] ....... (step 1 of 3) Processing subjectbody, total=   0.0s
[Pipeline] ............. (step 2 of 3) Processing union, total=   0.3s
[Pipeline] ............... (step 3 of 3) Processing svc, total=   0.0s
Classification report:

              precision    recall  f1-score   support

           0       0.84      0.87      0.86       396
           1       0.87      0.84      0.85       394

    accuracy                           0.86       790
   macro avg       0.86      0.86      0.86       790
weighted avg       0.86      0.86      0.86       790

Gesamtlaufzeit des Skripts: (0 Minuten 2,417 Sekunden)

Verwandte Beispiele

Klassifikation von Textdokumenten mit spärlichen Merkmalen

Klassifikation von Textdokumenten mit spärlichen Merkmalen

Biclustering von Dokumenten mit dem Spectral Co-Clustering Algorithmus

Biclustering von Dokumenten mit dem Spectral Co-Clustering Algorithmus

FeatureHasher und DictVectorizer Vergleich

FeatureHasher und DictVectorizer Vergleich

Column Transformer mit gemischten Typen

Column Transformer mit gemischten Typen

Galerie generiert von Sphinx-Gallery