Evalml: Ein Hot Encoder: Lassen Sie standardmĂ€ĂŸig ein redundantes Feature fĂŒr Features mit zwei Kategorien fallen

Erstellt am 5. MĂ€rz 2021  Â·  14Kommentare  Â·  Quelle: alteryx/evalml

Unser One-Hot-Encoder erstellt ein Feature fĂŒr jede Ebene des ursprĂŒnglichen kategorialen Features:

from evalml.pipelines import OneHotEncoder
import pandas as pd
df = pd.DataFrame({"category": ["a", "b"], "number": [4,5 ]})
OneHotEncoder().fit_transform(df).to_dataframe()

image

Die Spalten category_a und category_b sind vollstĂ€ndig kollinear, was eine ĂŒberflĂŒssig macht. Dies könnte nachteilige Auswirkungen auf die Anpassung des SchĂ€tzers haben. Ich denke, wir sollten standardmĂ€ĂŸig einen löschen.

Zur Info @rpeck

enhancement

Hilfreichster Kommentar

Drittes Gesetz des Codes: Du sollst nicht machen == Vergleiche mit Floats

Alle 14 Kommentare

💯 % sollten wir die Negativ-Case-Spalte weglassen.

Wenn wir die OHE zuerst selbst machen, dann wird sklearn sie hoffentlich nicht erweitern. Wie Freddy sagte, können Sie sich dies so vorstellen, als wĂŒrden Sie zwei Spalten erzeugen, die eine perfekte KollinearitĂ€t aufweisen.

Es gibt zwei Probleme, die ich beim Erweitern einer BinÀrdatei in zwei Spalten statt in eine sehe:

  1. Wie andere Formen der MerkmalskollinearitĂ€t bringt es viele Dinge in Bezug auf die Interpretierbarkeit durcheinander, da der Effekt der einen ursprĂŒnglichen Quellspalte auf die beiden OHE-Spalten aufgeteilt wird. Freddys neue SHAP-Rollups beheben dies offensichtlich, aber Dinge wie Feature Importance und Partial Dependence Plots werden das Problem weiterhin haben.
  2. Baummodelle wie Random Forest und GBM sampeln ihre Eingabemerkmale nach dem Zufallsprinzip. Die Quellspalte wird in diesem Fall doppelt so oft zufĂ€llig ausgewĂ€hlt, wie es eigentlich sein sollte, sodass sie einen ĂŒbergroßen Einfluss auf das Modell haben kann.

@freddyaboulton F: Der obige Datenrahmen fĂŒr die OHE-Spalten zeigt sie als Floats an. Ist das wirklich wahr?

@rpeck Ja!

@freddyaboulton Was? Das ist seltsam. Ich habe noch nie etwas anderes als echte boolesche Werte oder 0/1-Ganzzahlen gesehen. Ich frage mich, wie die Baummodelle eigentlich damit umgehen. FĂŒr mich riecht es unangenehm.

Drittes Gesetz des Codes: Du sollst nicht machen == Vergleiche mit Floats

(ok, es sei denn, es ist mit Math.NaN )

Hmm, ich dachte, wir machen das!

Ich stimme zu, wir sollten. Ich dachte, es wĂ€re nur ein Flag, das wir im zugrunde liegenden Impl setzen mĂŒssen.

@dsherry @freddyaboulton Es sieht so aus, als hĂ€tten wir UnterstĂŒtzung dafĂŒr ĂŒber unseren Parameter drop , aber berĂŒcksichtigt nur Benutzereingaben und wird von unserem Impl nicht verwendet, daher verfolgt dieses Problem nur die Einstellung der Standardeinstellung fĂŒr drop zu etwas anderem als None?

https://github.com/alteryx/evalml/blob/91775ffc26c47205adc0fb255832d828ead6e7c9/evalml/pipelines/components/transformers/encoders/onehot_encoder.py#L28

https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html

Wir könnten entweder first oder if_binary wÀhlen, sind uns nicht sicher, was der richtige Anruf ist.

@angela97lin Sie haben Recht, dass es ausreichen wĂŒrde, den Standardwert zu Ă€ndern! Ich denke, first ist der richtige Weg, da wir perfekt kollineare Merkmale vermeiden sollten, selbst wenn die Anzahl der Kategorien > 2 ist. Was denkst du

Habe ein bisschen hineingelesen und diesen Link gefunden: https://inmachineswetrust.com/posts/drop-first-columns/

Die zentralen Thesen:

  • Das Löschen von Spalten ist nur erforderlich, wenn ein OLS-Modell ohne Regularisierung erstellt wird (ich glaube, der lineare Regressor fĂ€llt in diese Kategorie: https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html, https:// scikit-learn.org/stable/modules/linear_model.html#ordinary-least-squares)
  • Das Löschen von One-Hot-codierten Spalten Ă€ndert die Parameter und Vorhersagen eines linearen Regressionsmodells, was sich auf das zurĂŒckgegebene Modell auswirkt. Es ist jedoch schwierig fĂŒr mich festzustellen, ob dies zum Besseren oder nicht.

Der erste Kommentar von RE durcheinander , weil der Effekt der einen ursprĂŒnglichen Quellspalte auf die beiden OHE-Spalten aufgeteilt wird. Freddys neue SHAP-Rollups gehen dies offensichtlich an. Aber Dinge wie Feature Importance und Partial Dependence Plots werden das Problem immer noch haben."

Dies ist fĂŒr binĂ€re FĂ€lle sinnvoll, aber in dem Fall, in dem wir mehrere Kategorien haben, wird das Löschen einer Spalte immer noch dieses Problem haben.

Vielleicht sollten wir dies nicht standardmĂ€ĂŸig tun, sondern make_pipeline aktualisieren, um einen OHE mit first als Parameter zu erstellen, wenn der SchĂ€tzer ein linearer Regressor ist?

Leider habe ich kein starkes VerstĂ€ndnis fĂŒr die zugrunde liegende Mathematik, um ein Urteil zu fĂ€llen, also wĂŒrde ich gerne Ihre Gedanken hören, @freddyaboulton @rpeck @dsherry

NachgesprÀch mit @rpeck @dsherry @chukarsten @jeremyliweishih

  • Wir werden dies nur fĂŒr binĂ€re FĂ€lle tun.
  • Ein "nice-to-have" ist zu verwenden, im binĂ€ren Fall ist die Minderheitsklasse, aber ansonsten sollte nur die Auswahl einer der beiden Kategorien ausreichen.

@angela97lin klingt nach einem guten RE-Standardverhalten. Ein weiterer Vorteil: Möglichkeit, dieses Standardverhalten ĂŒber die Komponentenparameter zu ĂŒberschreiben

@dsherry Wenn ich das richtig verstehe, haben Benutzer die Möglichkeit, dies zu ĂŒberschreiben, indem sie den Komponentenparameter manuell drop (einem Parameter) aktualisieren.

Habe herumgegraben, um zu sehen, was notwendig war, um dies zu implementieren. Insbesondere war ich neugierig, wie schwierig es sein wĂŒrde, die Minderheitsklasse im binĂ€ren Fall immer zu entfernen.

Das Ergebnis dieses Grabens ist:

  • Bei scikit-learn ist es ziemlich schwierig auszuwĂ€hlen, welche Kategorie entfernt werden soll. Aus der Dokumentation scheint dies ĂŒber die Array-Option fĂŒr den Parameter drop (https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html) machbar zu sein. Nach dem Ausprobieren muss jedoch fĂŒr jede Spalte ein Indexwert angegeben werden. Daher der folgende Fehler, der versucht, die bei Index 0 angegebene Kategorie fĂŒr Spalte 0 und keine anderen Werte fĂŒr die Spalten 1 und 2 zu entfernen:
import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder

X = pd.DataFrame({'col_1': ["a", "b", "b", "a", "b"],
                      'col_2': ["a", "b", "a", "c", "b"],
                      'col_3': ["a", "a", "a", "a", "a"]})

indices_to_drop = np.array([0, None, None])

ohe = OneHotEncoder(drop=indices_to_drop)
ohe.fit(X)
ValueError                                Traceback (most recent call last)
<ipython-input-4-a099fa2fc4a7> in <module>
----> 1 ohe.fit(X)

~/Desktop/venv/lib/python3.7/site-packages/sklearn/preprocessing/_encoders.py in fit(self, X, y)
    417         self._fit(X, handle_unknown=self.handle_unknown,
    418                   force_all_finite='allow-nan')
--> 419         self.drop_idx_ = self._compute_drop_idx()
    420         return self
    421 

~/Desktop/venv/lib/python3.7/site-packages/sklearn/preprocessing/_encoders.py in _compute_drop_idx(self)
    394                                 ["Category: {}, Feature: {}".format(c, v)
    395                                     for c, v in missing_drops])))
--> 396                 raise ValueError(msg)
    397             return np.array(drop_indices, dtype=object)
    398 

ValueError: The following categories were supposed to be dropped, but were not found in the training data.
Category: 0, Feature: 0
Category: 1, Feature: None
Category: 2, Feature: None

Ich glaube, dies ist auch die HĂ€lfte dessen, was in dieser Ausgabe herausgestellt wird: https://github.com/scikit-learn/scikit-learn/issues/16511

Eine Alternative, die wir tun können, um dies zu unterstĂŒtzen, besteht darin, manuell zu verfolgen, welche Spalten und welche Werte wir wĂ€hrend der Anpassung löschen möchten. Übergeben Sie die Daten an scikit-learn. Beschneiden Sie dann die Spalten, die wir gespeichert und angegeben haben, dass wir sie löschen möchten. Dies erfordert jedoch einige logische Handhabung, um das Original (Merkmal, Wert) aus dem transformierten Spaltennamen zu ermitteln. (Wir haben diese Logik in get_feature_names aber das hilft uns, die Spaltennamen zu verbinden, vorausgesetzt, dass nichts weggelassen werden sollte ...)

All dies soll sagen, dass vielleicht nur die Verwendung des Standard-Scikit-Learn if_binary fĂŒr den Moment ausreicht, und wir können ein separates Problem einreichen, um immer die Minderheitsklasse zu verwenden. Ehrlich gesagt auch dafĂŒr, dass wir uns von der OHE-Implementierung von scikit-learn abwenden, da wir so viel daran arbeiten mussten.

NĂŒtzliche Ressourcen:
OHE-Dokument: https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html
Code in scikit-learn verursacht InflexibilitÀt: https://github.com/scikit-learn/scikit-learn/blob/95119c13af77c76e150b753485c662b7c52a41a2/sklearn/preprocessing/_encoders.py#L338
Verwandtes Problem: https://github.com/scikit-learn/scikit-learn/issues/16511


Um if_binary : scikit-learn erfordert, dass handle_unknown error . Dies passt nicht gut zu unseren top_n Parametern, die alles außer den Top N Kategorien fallen lassen, weil die zu transformierenden Daten nicht wissen, was sie mit den neuen Kategorien anfangen sollen. Wie Becca in https://github.com/alteryx/evalml/pull/830 feststellte, mĂŒssten wir top_n auf None setzen, damit diese Parameter funktionieren.

In diesem Sinne ist es vielleicht am besten, einfach unser eigenes Impl zu rollen đŸ€”

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen