Scikit-learn: Pandas rein, Pandas raus?

Erstellt am 22. Okt. 2015  ·  59Kommentare  ·  Quelle: scikit-learn/scikit-learn

Im Moment ist es möglich, einen Pandas-Datenrahmen als Eingabe für die meisten Sklearn-Fit/Predict/Transform-Methoden zu verwenden, aber Sie erhalten ein numpy-Array. Es wäre wirklich schön, die Daten im gleichen Format ausgeben zu können, in das Sie sie eingegeben haben.

Dies ist nicht ganz einfach, denn wenn Ihr Datenrahmen Spalten enthält, die nicht numerisch sind, führen die dazwischenliegenden numpy-Arrays dazu, dass sklearn fehlschlägt, da sie dtype=object anstelle von dtype=float lauten. Dies kann durch einen Dataframe->ndarray-Transformer gelöst werden, der die nicht numerischen Daten auf numerische Daten abbildet (zB ganze Zahlen, die Klassen/Kategorien darstellen). sklearn-pandas macht dies bereits, obwohl es derzeit kein inverse_transform , aber das sollte nicht schwer sein, hinzuzufügen.

Ich habe das Gefühl, dass eine solche Transformation in sklearn _wirklich_ nützlich wäre - es ist die Art von Sache, die jeder, der mit Datensätzen mit mehreren Datentypen arbeitet, nützlich finden würde. Was braucht es, um so etwas in sklearn zu bekommen?

Hilfreichster Kommentar

Alle meine Transformatoren geben DataFrame s zurück, wenn DataFrame s gegeben wird.
Wenn ich DataFrame 300 Spalten in Pipeline und ein 500-Spalte ndarray erhalte, kann ich nicht viel daraus lernen, z. B. feature_selection , da ich die Spaltennamen nicht mehr habe. Wenn mir beispielsweise mutual_info_classif sagt, dass nur die Spalten 30 und 75 wichtig sind, kann ich nicht herausfinden, wie ich mein ursprüngliches Pipeline für die Produktion vereinfachen kann.
Daher ist es für meinen Anwendungsfall entscheidend, meine Daten in einem DataFrame speichern.
Dankeschön.

Alle 59 Kommentare

Scikit-learn wurde entwickelt, um mit einem sehr generischen Eingabeformat zu arbeiten. Vielleicht hat sich die Welt rund um scikit-learn seitdem stark verändert, was die Integration von Pandas wichtiger macht. Es könnte noch weitgehend von Wrappern von Drittanbietern geliefert werden.

Aber abgesehen von der allgemeineren Frage sollten Sie meiner Meinung nach versuchen, Beispiele dafür zu geben, wie sich die Pandas-freundliche Ausgabe von Standardschätzern unterscheidet und sich auf die Benutzerfreundlichkeit auswirkt. Beispiele die mir einfallen:

  • alle Methoden könnten den Index aus der Eingabe kopieren
  • Transformatoren sollten entsprechend benannte Spalten ausgeben
  • multiclass Predict_proba kann Spalten mit Klassennamen beschriften

Ja, aus dem Kopf:

  • der Index kann sehr nützlich sein, z. B. um zeitlich verzögerte Variablen zu erstellen (z. B. Verzögerung 1 Tag, bei täglichen Daten mit einigen fehlenden Tagen)
  • sklearn-Regressoren könnten transparent mit kategorialen Daten verwendet werden (gemischten Datenrahmen übergeben, kategoriale Spalten mit LabelBinarizer transformieren, inverse_transform it back).
  • sklearn-pandas bietet bereits eine nette Schnittstelle, die es Ihnen ermöglicht, einen Datenrahmen zu übergeben und nur eine Teilmenge der Daten zu verwenden und einzelne Spalten willkürlich zu transformieren.

Wenn dies alles in einer Transformation ist, hat dies keinen Einfluss auf die standardmäßige Funktionsweise von sklearn.

Ich glaube nicht, dass es gut als Transformator implementiert werden kann. Es wäre
ein oder mehrere Metaschätzer oder Mixins. Ich denke, sie sollten anfangs sein
extern implementiert und als nützlich erwiesen

Am 22. Oktober 2015 um 17:40 Uhr schrieb naught101 [email protected] :

Ja, aus dem Kopf:

  • der Index kann sehr nützlich sein, zB um zeitversetzt zu erstellen
    Variablen (zB Verzögerung 1 Tag, bei täglichen Daten mit einigen fehlenden Tagen)
  • sklearn-Regressoren könnten transparent mit kategorialen Daten verwendet werden
    (übergeben Sie gemischten Datenrahmen, transformieren Sie kategoriale Spalten mit LabelBinarizer,
    die inverse_transformiere es zurück).
  • sklearn-pandas bietet bereits eine nette Benutzeroberfläche, mit der Sie
    einen Datenrahmen übergeben und nur eine Teilmenge der Daten verwenden, und zwar willkürlich
    einzelne Spalten umwandeln.

Wenn dies alles in einer Transformation ist, dann beeinflusst es nicht wirklich, wie sklearn
funktioniert standardmäßig.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/scikit-learn/scikit-learn/issues/5523#issuecomment -150123228
.

"Pandas in" besser zu machen war eine Art Idee hinter dem Säulentransformator PR #3886. Vielleicht hätte ich mir genauer anschauen sollen, was sklearn-pandas schon macht. Ich bin mir nicht ganz sicher, was da der beste Weg ist.

Die andere Sache, die schön wäre, wäre, Spaltennamen in Transformationen beizubehalten / sie bei der Feature-Auswahl auszuwählen. Ich finde das Problem nicht, wo wir das gerade besprochen haben. Vielleicht erinnert sich @jnothman . Das würde mir wirklich gefallen, obwohl es einen größeren Eingriff bei der Eingabevalidierung erfordern würde, um die Spaltennamen zu erhalten :-/

Verbunden mit #4196

obwohl es einen größeren chirurgischen Eingriff mit der Eingabevalidierung erfordern würde, um
Bewahre die Spaltennamen auf :-/

Nicht nur Eingabevalidierung: Jede Transformation müsste beschreiben, was sie ist
auf die Eingabespalten.

Stimmt, aber das finde ich schön ;)

Eine Frage ist vielleicht, ob wir das nur in Pipelines oder überall wollen. Wenn wir es auf Pipelines beschränken, wäre die Eingabevalidierungsoperation weniger groß. Aber ich bin mir nicht sicher, wie nützlich es wäre.

Sie können immer eine Pipeline mit nur einer Sache erstellen, oder? Also behandeln wir _irgendwie_ alle Fälle (obwohl es in der Grenze von 1 Objekt hackig ist), indem wir uns zunächst auf die Pipeline beschränken ...

+1. Mit der Pipeline zu beginnen klingt gut, und decken Sie im nächsten Schritt alle Transformatoren ab.

Ich habe auch ein Impl mit Pandas- und Sklearn-Integration, das Spalteninformationen über inverse_transform zurücksetzen kann (allerdings schmutziger Hack ...)

http://pandas-ml.readthedocs.org/en/latest/sklearn.html

• der Index kann sehr nützlich sein, zB um zeitlich verzögerte Variablen zu erstellen
(zB Verzögerung 1 Tag, bei täglichen Daten mit einigen fehlenden Tagen)

Ich bin ein bisschen blöd, rede aber nicht über etwas in der Probe
Richtung hier, anstatt die Feature-Richtung?

• sklearn-Regressoren könnten transparent mit kategorialen Daten verwendet werden (pass
gemischter Datenrahmen, transformieren kategoriale Spalten mit LabelBinarizer, dem
inverse_transform it back).

• sklearn-pandas bietet bereits eine nette Schnittstelle, die es Ihnen ermöglicht, ein
Datenrahmen, und verwenden Sie nur eine Teilmenge der Daten und transformieren Sie willkürlich
einzelne Spalten.

OK, aber das ist alles auf der Ebene eines Transformators, der Pandas aufnimmt,
und gibt eine Datenmatrix aus, nicht wahr? Anstatt zu versuchen,
Modifikation an allen Objekten von Scikit-Learn (was ein riskantes
Bemühung), könnten wir zuerst diesen Transformator implementieren (ich glaube das
@amueller hat das im Kopf).

Sample-Richtung hier und nicht die Feature-Richtung?

Ja.

OK, aber das ist alles auf der Ebene eines Transformators, der Pandas aufnimmt und eine Datenmatrix ausgibt, nicht wahr?

Ja, daran dachte ich am Anfang. Ich wäre mehr als zufrieden mit einem Wrapper, der X und y als Datenrahmen behandelt. Ich sehe keinen offensichtlichen Grund, an den Interna von sklearn zu schrauben.

OK, but that's all at the level of one transformer that takes Pandas in,
and gives a data matrix out, isn't it?

Ja, daran dachte ich am Anfang. Ich wäre mehr als zufrieden damit
ein Wrapper, der X und y als Datenrahmen behandelt. Ich sehe keinen offensichtlichen Grund
mit sklearns Einbauten zu schrauben.

Dann sind wir auf der gleichen Seite. Ich glaube, @amueller hat Ideen zu
dies, und wir könnten einige Diskussionen und vielleicht bald Code sehen.

Die andere Sache, die schön wäre, wäre, Spaltennamen in Transformationen beizubehalten / sie bei der Feature-Auswahl auszuwählen. Ich finde das Problem nicht, wo wir das gerade besprochen haben.

5172

Eine Anmerkung: Ich hatte mich gefragt, ob man nur den äußersten Schätzer in ein Ensemble einschließen möchte, um einem Benutzer diese Funktionalität bereitzustellen. Ich denke, die Antwort lautet: Nein, man möchte auch atomare Transformatoren einwickeln, um Datenrahmen-fähige Transformatoren innerhalb einer Pipeline zu ermöglichen (warum nicht?). Ohne dies als Mixin zu implementieren, werden Sie meiner Meinung nach Probleme mit unnötigen Parameterpräfixen oder Problemen beim Klonen bekommen (wie in #5080).

:+1:

Wollte nur die Lösung wegwerfen, die ich verwende:

def check_output(X, ensure_index=None, ensure_columns=None):
    """
    Joins X with ensure_index's index or ensure_columns's columns when avaialble
    """
    if ensure_index is not None:
        if ensure_columns is not None:
            if type(ensure_index) is pd.DataFrame and type(ensure_columns) is pd.DataFrame:
                X = pd.DataFrame(X, index=ensure_index.index, columns=ensure_columns.columns)
        else:
            if type(ensure_index) is pd.DataFrame:
                X = pd.DataFrame(X, index=ensure_index.index)
    return X

Ich erstelle dann Wrapper um die Schätzer von sklearn, die diese Funktion in der Ausgabe von transform aufrufen, z.

from sklearn.preprocessing import StandardScaler as _StandardScaler 
class StandardScaler(_StandardScaler):
    def transform(self, X):
        Xt = super(StandardScaler, self).transform(X)
        return check_output(Xt, ensure_index=X, ensure_columns=X)

Klassifizierer, die den Index des Eingabedatenrahmens X verwenden müssen, können einfach seinen Index verwenden (nützlich für Zeitreihen, wie bereits erwähnt).

Dieser Ansatz hat den Vorteil, dass er vollständig mit dem bestehenden sklearn-Design kompatibel ist und gleichzeitig die Berechnungsgeschwindigkeit beibehält (mathematische Operationen und die Indizierung von Datenrahmen sind bis zu 10x langsamer als numpy-Arrays, http://penandpants.com/2014/09/05 /performance-of-pandas-series-vs-numpy-arrays/). Leider ist es eine Menge mühsamer Arbeit, jedem Schätzer hinzuzufügen, der ihn verwenden könnte.

Vielleicht ist es nur notwendig, mit dieser Magie eine Pipeline-Variante zu erstellen ...

Am 15. Januar 2016 um 02:30 Uhr schrieb Dean Wyatte [email protected] :

Wollte nur die Lösung wegwerfen, die ich verwende:

def check_output(X, secure_index=None, secure_columns=None):
"""
Verbindet X mit dem Index von secure_index oder den Spalten von secure_columns, wenn verfügbar
"""
wenn secure_index nicht None ist:
wenn secure_columns nicht None ist:
if type(ensure_index) ist pd.DataFrame und type(ensure_columns) ist pd.DataFrame:
X = pd.DataFrame(X, index=ensure_index.index, column=ensure_columns.columns)
anders:
if type(ensure_index) ist pd.DataFrame:
X = pd.DataFrame(X, index=ensure_index.index)
zurück X

Ich erstelle dann Wrapper um die Schätzer von sklearn, die diese Funktion aufrufen
auf der Ausgabe von transform zB,

from sklearn.preprocessing import StandardScaler als _StandardScaler
Klasse MinMaxScaler(_MinMaxScaler):
def transform(selbst, X):
Xt = super(MinMaxScaler, self).transform(X)
return check_output(Xt, sichere_index=X, sichere_spalten=X)

Klassifikatoren, die den Index des Eingabedatenrahmens X verwenden müssen, können einfach
seinen Index verwenden (nützlich für Zeitreihen, wie bereits erwähnt).

Dieser Ansatz hat den Vorteil, dass er vollständig kompatibel mit den
vorhandenes Sklearn-Design bei gleichzeitiger Beibehaltung der Rechengeschwindigkeit
(Mathematische Operationen und Indizierung auf Datenrahmen sind bis zu 10x langsamer als numpy
Arrays). Leider ist es eine Menge mühsamer Arbeit, jeden Schätzer hinzuzufügen
das könnte es gebrauchen.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/scikit-learn/scikit-learn/issues/5523#issuecomment -171674105
.

Oder einfach nur etwas, das eine Pipeline/einen Schätzer umschließt, nicht wahr?

Ich verstehe nicht wirklich, warum Sie eine Funktion wie diese "check_*" aufrufen, wenn sie viel mehr tut, als nur zu überprüfen ...

Am 14. Januar 2016 10:45:44 CST schrieb Joel Nothman [email protected] :

Vielleicht ist es nur notwendig, mit dieser Magie eine Pipeline-Variante zu erstellen ...

Am 15. Januar 2016 um 02:30 Uhr, Dean Wyatte [email protected]
schrieb:

Wollte nur die Lösung wegwerfen, die ich verwende:

def check_output(X, secure_index=None, secure_columns=None):
"""
Verbindet X mit dem Index von secure_index oder den Spalten von secure_columns
wenn verfügbar
"""
wenn secure_index nicht None ist:
wenn secure_columns nicht None ist:
if type(ensure_index) ist pd.DataFrame und
type(ensure_columns) ist pd.DataFrame:
X = pd.DataFrame(X, index=ensure_index.index,
Spalten=ensure_columns.columns)
anders:
if type(ensure_index) ist pd.DataFrame:
X = pd.DataFrame(X, index=ensure_index.index)
zurück X

Ich erstelle dann Wrapper um die Schätzer von sklearn, die dies nennen
Funktion
auf der Ausgabe von transform zB,

from sklearn.preprocessing import StandardScaler als _StandardScaler
Klasse MinMaxScaler(_MinMaxScaler):
def transform(selbst, X):
Xt = super(MinMaxScaler, self).transform(X)
return check_output(Xt, sichere_index=X, sichere_spalten=X)

Klassifizierer, die den Index des Eingabedatenrahmens X benötigen, können
nur
seinen Index verwenden (nützlich für Zeitreihen, wie bereits erwähnt).

Dieser Ansatz hat den Vorteil, dass er vollständig kompatibel mit den
vorhandenes Sklearn-Design bei gleichzeitiger Beibehaltung der Geschwindigkeit von
Berechnung
(Mathematische Operationen und Indizierung von Datenrahmen sind bis zu 10x langsamer als
numpy
Arrays). Leider ist es eine Menge mühsamer Arbeit, sie zu jedem hinzuzufügen
Schätzer
das könnte es gebrauchen.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an

https://github.com/scikit-learn/scikit-learn/issues/5523#issuecomment -171674105
.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an:
https://github.com/scikit-learn/scikit-learn/issues/5523#issuecomment -171697542

Gesendet von meinem Android-Gerät mit K-9 Mail. Bitte entschuldigen Sie meine Kürze.

Ich bin mir nicht sicher, ob Pipeline der richtige Ausgangspunkt ist, da die gesamte Vererbung von Spaltennamen schätzerspezifisch ist, z. B. sollten Skalierer die Spaltennamen des Eingabedatenrahmens erben, während Modelle wie PCA dies nicht sollten. Schätzer für die Featureauswahl sollten bestimmte Spaltennamen erben, aber das ist ein anderes Problem, das wahrscheinlich eher mit #2007 zusammenhängt.

Ist es immer so, dass n_rows aller Arrays während der Transformation erhalten bleiben? Wenn ja, scheint es sicher zu sein, nur den Index der Eingabe zu erben (sofern vorhanden), aber ich bin mir nicht sicher, ob das Abrufen eines Datenrahmens mit Standardspaltennamen (z. B. [0, 1, 2, 3, ...]) möglich ist besser als das aktuelle Verhalten aus der Sicht des Endbenutzers, aber wenn ein expliziter Wrapper/Meta-Schätzer verwendet wird, weiß der Benutzer zumindest, was ihn erwartet.

Ich stimmte auch zu, dass check_* ein schlechter Name ist - ich habe in meiner Funktion einiges mehr überprüft und nur die Datenrahmenlogik entfernt, um sie hier zu posten.

Ich denke, die Pipeline wäre der Anfang, obwohl wir allen Schätzern etwas hinzufügen müssten, das die Spaltennamen entsprechend zuordnet.

Transformatoren sollten entsprechend benannte Spalten @naught101 ausgeben

obwohl es eine größere Operation mit der Eingabevalidierung erfordern würde, um die Spaltennamen zu erhalten :-/ @amueller

Nicht nur Eingabevalidierung: Jede Transformation müsste beschreiben, was sie mit den Eingabespalten macht. @GaelVaroquaux

Hat jemand darüber nachgedacht, wie man die Namen von Transformator zu Transformator weitergibt und vielleicht die Herkunft verfolgt? Wo würde man das aufbewahren?

Ein Freund von mir, @cbrummitt , hat ein ähnliches Problem, bei dem jede Spalte seiner Entwurfsmatrix eine funktionale Form ist (zB x^2, x^3, x_1^3x_2^2, dargestellt als Sympy-Ausdrücke), und er hat Transformatoren die ähnlich agieren wie PolynomialFeatures, die funktionale Formen annehmen und darauf basierend weitere generieren können. Aber er verwendet sympy, um die alten Ausdrücke zu verwenden und neue zu generieren, und das Speichern der Ausdrücke als Zeichenfolgenlabels reicht nicht aus und wird kompliziert, wenn Sie die Funktionstransformationen überlagern. Er könnte all dies außerhalb der Pipeline tun, aber dann profitiert er nicht von GridSearch usw.

Ich denke, die allgemeinere Version unserer Frage lautet: Wie haben Sie einige Informationen, die von Transformator zu Transformator weitergegeben werden und die NICHT die Daten selbst sind? Ich kann mir keinen großartigen Weg einfallen lassen, ohne einen Pipeline-globalen Zustand zu haben oder jeden Transformator / Schätzer über die vorherigen wissen zu lassen oder jeden Schritt mehrere Dinge zurückzugeben oder so etwas.

Wir kamen dann auch auf die Idee, die Pipeline zu modifizieren, um den Überblick zu behalten, Sie müssten _fit() und _transform() ändern und vielleicht noch ein paar andere Dinge. Das scheint unsere beste Option zu sein.

Das klingt verrückt, aber es fühlt sich so an, dass wir wirklich wollen, dass unsere Datenmatrix Sympy-Ausdrücke ist und jede Transformation neue Ausdrücke erzeugt? Das ist eklig, check_array() verhindert, dass es passiert, und es würde andere Schritte in der Pipeline verärgern.

siehe #6425 für die aktuelle Idee.

Alles, was Sie wollen, ist eine Zuordnung für jeden Transformator (einschließlich einer Pipeline von
Transformatoren), von Eingabe-Feature-Namen bis zu Ausgabe-Feature-Namen (oder einigen
strukturierte Darstellung der Transformationen, was ich eher vermute
Engineering, als wir bekommen werden). Das bietet #6425.

Am 8. Oktober 2016 um 03:42 Uhr Andreas Mueller [email protected]
schrieb:

siehe #6425 https://github.com/scikit-learn/scikit-learn/issues/6425 für
die aktuelle Idee.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/scikit-learn/scikit-learn/issues/5523#issuecomment -252301608,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAEz65fBsMwqmkDq3DEjMSUC-W-nfn9zks5qxnZxgaJpZM4GThGc
.

Wir werden das prüfen, danke!

Kann jemand ein allgemeines Update zum Zustand der Welt in Bezug auf dieses Problem bereitstellen?

Wird die Unterstützung von Pandas DataFrame immer eine YMMV-Sache sein?
Eine Anleitung, was für die Verwendung mit einem Panda DataFrame anstelle von nur einem ndarray als sicher angesehen wird/ist, wäre hilfreich. Vielleicht etwas in der Art des Folgenden (ZUSAMMENGESTELLTE BEISPIELTABELLE):

module/category|kann Pandas DataFrame sicher konsumieren
--|--
sklearn.pipeline|SICHER
sklearn.feature_selection|SICHER
Regressoren|YMMV
sklearn.feature_extraction|NICHT SICHER, keine Implementierung geplant
usw. |...

Im Moment bin ich mir nicht sicher, ob es einen anderen Ansatz gibt als "versuchen Sie es einfach und sehen Sie, ob es Ausnahmen auslöst".

Wir haben eine Handvoll handcodierter Beispiele getestet, die anscheinend gut funktionieren, wenn sie einen Pandas-DataFrame akzeptieren, aber wir können nicht umhin zu denken, dass dies unweigerlich nicht mehr funktioniert, wenn wir entscheiden, dass wir einen scheinbar trivialen Pipeline-Komponententausch vornehmen müssen ... an diesem Punkt fällt alles wie ein Kartenhaus in einer kryptischen Stapelspur zusammen.

Mein erster Gedanke war, ein Ersatz-Pipeline-Objekt zu erstellen, das einen Pandas DataFrame verbrauchen kann, der automatisch Wrapper für Standard-Scikit-Learn-Komponenten generiert, um Eingabe-/Ausgabe- DataFrame Objekte in numpy ndarray umzuwandeln DataFrame Primitive verwenden kann, aber das scheint ein bisschen schwerfällig zu sein. Vor allem dann, wenn wir kurz davor stehen, "offizielle" Unterstützung für sie zu haben.

Ich habe ein paar verschiedene PRs verfolgt, aber es ist schwer ein Gefühl dafür zu bekommen, welche aufgegeben wurden und / oder welche die aktuelle Denkweise widerspiegeln:
Beispiel:

6425 (oben in diesem Thread auf Okt 2016 verwiesen)

9012 (offensichtliche Überschneidungen mit sklearn-pandas, aber als experimentell bezeichnet?)

3886 (ersetzt durch #9012 ?)

Dies hängt entscheidend davon ab, was Sie mit "Kann Pandas DataFrame sicher verbrauchen" meinen. Wenn Sie einen DataFrame meinen, der nur Float-Zahlen enthält, garantieren wir, dass alles funktioniert. Wenn irgendwo auch nur eine einzige Zeichenfolge vorhanden ist, funktioniert nichts.

Ich denke, jeder Scikit-Learn-Schätzer, der einen Datenrahmen für eine nicht-triviale (oder vielleicht sogar triviale) Operation zurückgibt, ist etwas, das möglicherweise nie passieren wird (obwohl es es gerne hätte).

9012 wird passieren und stabil werden, der PR ist eine erste Iteration (oder 10. Iteration, wenn Sie nicht zusammengeführte zählen ;)

6425 wird wahrscheinlich passieren, obwohl es nicht vollständig mit Pandas zusammenhängt.

3886 wird tatsächlich von #9012 abgelöst

Die Funktionalität #6425 ist derzeit implementiert (für einige Transformatoren und
auf andere erweiterbar) per Einzelversand in
https://codecov.io/gh/TeamHG-Memex/eli5 für das, was es wert ist.

Am 21. Juni 2017 um 13:25 Uhr schrieb Andreas Mueller [email protected] :

9012 https://github.com/scikit-learn/scikit-learn/pull/9012 wird

passieren und stabil werden, ist die PR eine erste Iteration.

6425 https://github.com/scikit-learn/scikit-learn/issues/6425 is

wahrscheinlich passieren, obwohl es nicht ausschließlich mit Pandas zusammenhängt.

3886 https://github.com/scikit-learn/scikit-learn/pull/3886 ist in der Tat

ersetzt durch #9012
https://github.com/scikit-learn/scikit-learn/pull/9012


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/scikit-learn/scikit-learn/issues/5523#issuecomment-309952467 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAEz61lgGBW1AoukPm_87elBjF2NGOUwks5sGI0-gaJpZM4GThGc
.

Oh und wenn ich sage "Wenn Sie einen DataFrame meinen, der nur Gleitkommazahlen enthält, garantieren wir, dass alles funktioniert." Ich meine mit standortbasierter Spaltenindizierung. Es wird davon ausgegangen, dass Trainings- und Testsatzspalten nach Position gleich sind.

Dies hängt entscheidend davon ab, was Sie mit "Kann Pandas DataFrame sicher verbrauchen" meinen. Wenn Sie einen DataFrame meinen, der nur Float-Zahlen enthält, garantieren wir, dass alles funktioniert. Wenn irgendwo auch nur eine einzige Zeichenfolge vorhanden ist, funktioniert nichts.

Ich denke, das reicht uns.

Wir verwenden eine Pipeline benutzerdefinierter Komponenten (dünne Wrapper um vorhandene Tools, die nicht Pipeline-freundlich sind), um gemischte Typen (Strings, Floats und Ints) über Codierung/Skalierung in Floats umzuwandeln, bevor wir Scikit-Learn-Komponenten wie Selektoren oder Modelle erreichen.

Alle meine Transformatoren geben DataFrame s zurück, wenn DataFrame s gegeben wird.
Wenn ich DataFrame 300 Spalten in Pipeline und ein 500-Spalte ndarray erhalte, kann ich nicht viel daraus lernen, z. B. feature_selection , da ich die Spaltennamen nicht mehr habe. Wenn mir beispielsweise mutual_info_classif sagt, dass nur die Spalten 30 und 75 wichtig sind, kann ich nicht herausfinden, wie ich mein ursprüngliches Pipeline für die Produktion vereinfachen kann.
Daher ist es für meinen Anwendungsfall entscheidend, meine Daten in einem DataFrame speichern.
Dankeschön.

@sam-s Ich stimme voll und ganz zu. Kurzfristig wird dies von https://github.com/scikit-learn/scikit-learn/pull/13307 und https://github.com/scikit-learn/enhancement_proposals/pull/18 adressiert

Sie erhalten keinen Pandas-Datenrahmen, aber den Spaltennamen, um einen zu erstellen.

Können Sie aber bitte ein konkreteres Beispiel geben? Denn wenn alle Transformer DataFrames zurückgeben, sollten die Dinge funktionieren (oder einfacher als die obigen Vorschläge gemacht werden).

Leichtes Update über https://github.com/pandas-dev/pandas/issues/27211
was meine Hoffnungen dämpft. Es sieht so aus, als ob wir nicht darauf vertrauen können, dass es einen Zero-Copy-Round-Trip gibt, und das Ein- und Auspacken in Pandas wird daher zu erheblichen Kosten führen.

Kleines Update über pandas-dev/pandas#27211, das meine Hoffnungen dämpft. Es sieht so aus, als ob wir nicht darauf vertrauen können, dass es einen Zero-Copy-Round-Trip gibt, und das Ein- und Auspacken in Pandas wird daher zu erheblichen Kosten führen.

ja, aber ich denke, sobald wir die Feature- und Beispiel-Requisiten behandelt haben (Zeilennamen und "Indizes" sind eine Art Beispiel-Requisite), wären die meisten verwandten Anwendungsfälle, die jetzt Pandas brauchen, abgedeckt, oder?

@adrinjalali Ich bin mir nicht sicher, was Sie mit "die meisten verwandten Anwendungsfälle mit Pandas brauchen" meinen. Ich sah dieses Problem nicht in erster Linie darin, Pandas bei der Implementierung von Funktionen in scikit-learn zu unterstützen, sondern darin, dass scikit-learn einfacher in einen Pandas-basierten Workflow integriert werden soll.

Gibt es nur aus Neugierde einen Zeitrahmen, in dem eine verbesserte Pandas-Kompatibilität erwartet wird? Ich interessiere mich speziell für Pandas in -> Pandas out für StandardScaler .

Ich habe einen Anwendungsfall, in dem ich Pandas-Datenrahmen brauche, die bei jedem Schritt in einem Pipeline erhalten bleiben. Zum Beispiel eine Pipeline mit 1) Merkmalsauswahlschritt zum Filtern von Merkmalen basierend auf Daten, 2) Datentransformationsschritt, 3) einem weiteren Merkmalsauswahlschritt, um nach bestimmten Merkmalsspaltennamen oder Originalindizes zu filtern, 4) Standardisierung, 5) Klassifizierung.

Schritt 3) ist meiner Meinung nach derzeit in sklearn nicht möglich, selbst bei einer numpy-Array-Eingabe, da die ursprünglichen Feature-Indizes bedeutungslos sind, wenn die Daten zu 3) gelangen, da in 1) ein Feature-Auswahlschritt durchgeführt wurde. Wenn Pandas-Datenrahmen in der Pipeline beibehalten würden, würde dies funktionieren, da ich in 3) nach Spaltennamen filtern könnte.

Liege ich falsch in der Annahme, dass dies derzeit selbst bei einer numpy-Array-Eingabe nicht möglich ist?

Sie haben Recht, dass es nicht unterstützt wird, und es wäre nicht trivial. In Bezug auf Ihren Anwendungsfall arbeiten wir daran, Feature-Namen entlang der Pipeline zu übergeben (wie Sie in den oben verlinkten PRs und Vorschlägen sehen). Das sollte hoffentlich bei Ihrem Fall helfen, wenn es erledigt ist. Ich bin mir nicht sicher, ob es hilft, aber du könntest auch auf https://github.com/scikit-learn-contrib/sklearn-pandas nachschauen

Sie haben Recht, dass es nicht unterstützt wird, und es wäre nicht trivial. In Bezug auf Ihren Anwendungsfall arbeiten wir daran, Feature-Namen entlang der Pipeline zu übergeben (wie Sie in den oben verlinkten PRs und Vorschlägen sehen). Das sollte hoffentlich bei Ihrem Fall helfen, wenn es erledigt ist.

Vielen Dank für die Bestätigung. Ja, es wäre für diesen Anwendungsfall in Ordnung, Feature-Namen (oder andere Feature-Eigenschaften) an Methoden anzupassen und sie bei jedem Feature-Auswahlschritt richtig zu schneiden.

Ich bin mir nicht sicher, ob es hilft, aber du könntest auch auf https://github.com/scikit-learn-contrib/sklearn-pandas nachschauen

Vorhin habe ich ihre Dokumente durchgelesen und vielleicht sehe ich sie nicht, aber die meisten (oder alle) ihrer Funktionen sind jetzt in scikit-learn 0.21 mit sklearn.compose.ColumnTransformer veraltet? Es scheint auch nicht, dass sie Pandas unterstützen, es sieht nach Transformationen wie numpy Arrays aus.

(Ich frage mich, ob die Unterstützung von Pandas bei der Feature-Auswahl kaputt gehen würde
viel...)

Nur kurz den Code überprüfen, es gibt alle Arten von Überprüfungen, die an vielen Stellen willkürlich stattfinden, beispielsweise mithilfe von https://github.com/scikit-learn/scikit-learn/blob/939fa3cccefe708db7a81c5248db32a1d600bf8d/sklearn/utils/validation.py# L619

Außerdem verwenden viele Operationen die Indizierung auf eine numpy Weise, die von Pandas-Datenrahmen nicht akzeptiert würde.

Pandas in/out zu halten wäre ein Muss für die tägliche Datenwissenschaft IMO, aber scikit-learn scheint so konzipiert zu sein, dass es schwer zu implementieren ist.

Pandas drinnen/draußen zu halten wäre ein Muss für die tägliche Datenwissenschaft IMO, aber
scikit-learn scheint so konzipiert zu sein, dass es schwierig wäre, es zu sein
umgesetzt.

Gute Numerik ist in Pandas-Datenrahmen schwer zu implementieren. Sie sind nur
nicht dafür gedacht, insbesondere für multivariate Operationen (numerisch
Spaltenübergreifende Operationen).

Maschinelles Lernen ist hauptsächlich multivariate Numerik.

Gute Numerik ist in Pandas-Datenrahmen schwer zu implementieren. Dafür sind sie einfach nicht gedacht, insbesondere nicht für multivariate Operationen (numerische Operationen über Spalten hinweg). Maschinelles Lernen ist hauptsächlich multivariate Numerik.

Diese Entscheidung sollte dem Benutzer überlassen bleiben? Nach meiner Erfahrung mit scikit-learn in den letzten zwei Jahren denke ich, dass zwei zentrale und wichtige Funktionen, die fehlen und für viele ML-Anwendungsfälle ein Muss sind, die Unterstützung für die Übergabe von Beispiel- und Feature-Metadaten sind. Die vollständige Unterstützung von Pandas-Datenrahmen ist eine natürliche und elegante Möglichkeit, mit einigen dieser Probleme umzugehen.

Diese Art von Kernfunktionalitäten sind sehr wichtig, um die Benutzerbasis zu halten und neue Benutzer zu gewinnen. Ansonsten sehe ich, dass Bibliotheken wie zB mlr3 irgendwann reifen und Benutzer von sklearn wegziehen, weil ich weiß, dass sie Datenrahmen und Metadaten vollständig unterstützen (oder werden).

Diese Entscheidung sollte dem Benutzer überlassen bleiben?

Nun, der Benutzer implementiert den Algorithmus nicht.

Ansonsten sehe ich Bibliotheken wie zB mlr3 irgendwann reifen und
Benutzer von sklearn weglocken, weil ich weiß, dass sie es tun (oder werden)
Datenrahmen und Metadaten vollständig unterstützen.

mlr3 ist in R, die Datenrahmen unterscheiden sich stark von Pandas-Datenrahmen.
Vielleicht erleichtert dies die Umsetzung.

Ich stimme zu, dass eine bessere Unterstützung für Featurenamen und heterogene Daten
Typen ist wichtig. Wir arbeiten daran, gute technische Lösungen zu finden
die nicht zu Leistungseinbußen und zu kompliziertem Code führen.

Diese Entscheidung sollte dem Benutzer überlassen bleiben?
Nun, der Benutzer implementiert den Algorithmus nicht.
Ansonsten sehe ich, dass Bibliotheken wie zB mlr3 irgendwann reifen und Benutzer von sklearn wegziehen, weil ich weiß, dass sie Datenrahmen und Metadaten vollständig unterstützen (oder werden).
mlr3 ist in R, die Datenrahmen unterscheiden sich stark von Pandas-Datenrahmen. Vielleicht erleichtert dies die Umsetzung. Ich stimme zu, dass eine bessere Unterstützung für Featurenamen und heterogene Datentypen wichtig ist. Wir arbeiten daran, gute technische Lösungen zu finden, die nicht zu Leistungseinbußen und zu kompliziertem Code führen.

Ich denke, Ihr Ansatz, bei numpy Arrays zu bleiben und zumindest die Übergabe von Feature-Namen oder noch besser mehrere Feature-Metadaten zu unterstützen, würde für viele Anwendungsfälle funktionieren. Für das Übergeben von Trainingsbeispiel-Metadaten unterstützen Sie es bereits in **fit_params und ich weiß, dass es Bemühungen gibt, das Design zu verbessern. Aber ich habe in https://github.com/scikit-learn/enhancement_proposals/pull/16 erwähnt, dass es Anwendungsfälle gibt, in denen Sie auch Testbeispiel-Metadaten an transform Methoden übergeben müssen und dies derzeit nicht unterstützt wird .

mlr3 ist in R, die Datenrahmen unterscheiden sich stark von Pandas-Datenrahmen.

Computerwissenschaftler in der Biowissenschaftsforschung sind in der Regel sowohl mit Python als auch mit R sehr vertraut und verwenden beide zusammen (mich eingeschlossen). Ich bin mir ziemlich sicher, dass ein erheblicher Prozentsatz der scikit-learn-Benutzerbasis Biowissenschaftsforscher sind.

Derzeit kommen die verfügbaren ausgereiften ML-Bibliotheken in R IMHO nicht einmal annähernd an Scikit-Learn in Bezug auf die Bereitstellung einer gut gestalteten API und die einfache Gestaltung der nützlichen Teile von ML (Pipelines, Hyperparameter-Suche, Scoring usw.), während in R Bei diesen Bibliotheken müssen Sie sie fast selbst codieren. Aber mlr3 sehe ich als eine zukünftige große Konkurrenz für scikit-learn, da sie es von Grund auf richtig gestalten.

Gute Numerik ist in Pandas-Datenrahmen schwer zu implementieren. Sie sind nur
nicht dafür gedacht, insbesondere für multivariate Operationen (numerisch
Spaltenübergreifende Operationen).

Vielleicht übersehe ich etwas, aber wäre es nicht möglich, den DataFrame zu entpacken (mit df.values ), die Berechnungen durchzuführen und dann in einen neuen DataFrame zurückzukehren?

Das ist im Grunde das, was ich zwischen den Schritten manuell mache, und das einzige, was die Verwendung eines Pipeline .

Vielleicht fehlt mir etwas, aber wäre es nicht möglich, das auszupacken
DataFrame (mit df.values), führen Sie die Berechnungen durch und brechen Sie dann auf ein neues zurück
Datenrahmen ?

Im Allgemeinen nein: es funktioniert möglicherweise nicht (heterogene Spalten), und es wird
führen zu vielen Speicherkopien.

Im Allgemeinen nein: Es funktioniert möglicherweise nicht (heterogene Spalten)

Ich denke, dass Column Transformers und ähnliches damit individuell umgehen können.

es wird zu vielen Speicherkopien führen.

Ich verstehe, dass es schwierige Design- und Implementierungsentscheidungen zu treffen gilt, und das ist ein stichhaltiges Argument.

Ich verstehe jedoch nicht, warum Sie argumentieren, dass es keine gute Idee ist, die Art und Weise, wie sklearn Spaltenmetadaten unterstützt, zu verbessern.

Zum Beispiel eine df mit Funktionen aufzunehmen, eine Spalte dank eines Prädiktors hinzuzufügen, weitere Datenmanipulationen durchzuführen, eine weitere Vorhersage durchzuführen, all dies in einer Pipeline wäre nützlich, da es (zum Beispiel) eine Optimierung der Hyperparameter ermöglichen würde viel besser integriert und elegant.

Es mit oder ohne Pandas zu machen, ist nur ein Vorschlag, da es die gängigste, einfachste und beliebteste Art ist, Daten zu manipulieren, und ich sehe keine Vorteile darin, mehr als das, was sie getan haben, neu zu schreiben.

Es wäre Sache des Benutzers, diesen Workflow bei der Leistungsoptimierung nicht zu verwenden.

Die Entscheidung des Benutzers zu überlassen erfordert eine klare Erklärung der
Wahl für den Benutzer. Die meisten Benutzer lesen die Dokumentation, die dies tun würde, nicht
erklären solche Entscheidungen. Viele würden versuchen, was ihrer Meinung nach funktionieren könnte, und dann
aufgeben, wenn sie es langsam finden, ohne zu merken, dass es ihre Wahl war
daraframe, das es so gemacht hat.

Wir müssen hier also mit etwas Vorsicht vorgehen. Aber wir müssen weiter lösen
dies als hohe Priorität.

Ich denke, die beste Lösung wäre, Pandas-Datenrahmen in und aus für die Sample- und Feature-Eigenschaften zu unterstützen und sie ordnungsgemäß in Train und Test Fit/Transform zu übergeben und zu schneiden. Das würde die meisten Anwendungsfälle lösen und gleichzeitig die Geschwindigkeit der Datenmatrix X als numpy-Arrays beibehalten.

Ein wichtiger Punkt, der in diesen Argumenten fehlt, ist, dass Pandas sich in Richtung einer spaltenförmigen Darstellung der Daten bewegen, sodass np.array(pd.DataFrame(numpy_data)) zwei _garantierte_ Speicherkopien haben wird. Aus diesem Grund ist es nicht so einfach, nur den Datenrahmen zu behalten und values wenn wir Geschwindigkeit benötigen.

Ein wichtiger Punkt, der in diesen Argumenten fehlt, ist, dass Pandas sich in Richtung einer spaltenförmigen Darstellung der Daten bewegen, sodass np.array(pd.DataFrame(numpy_data)) zwei _garantierte_ Speicherkopien haben wird. Aus diesem Grund ist es nicht so einfach, nur den Datenrahmen zu behalten und values wenn wir Geschwindigkeit benötigen.

Ich hoffe, ich war in meinem vorherigen Post klar. Ich glaube, dass scikit-learn derzeit keine Pandas-Datenrahmen für X-Daten unterstützen muss, sondern als schnelle, numpy Arrays beibehalten. Was jedoch viele Anwendungsfälle lösen würde, ist die vollständige Unterstützung durch das Framework für Pandas-Datenrahmen für Metadaten, dh Beispieleigenschaften und Merkmalseigenschaften. Dies sollte selbst für Speicherkopien keine Leistungsbelastung darstellen, da diese beiden Datenstrukturen im Vergleich zu X geringfügig sind und wirklich nur eine Teileinstellung für diese vorgenommen wird.

Ja, diese Änderungen helfen in vielen Anwendungsfällen und wir arbeiten daran. Aber dieses Problem geht darüber hinaus: https://github.com/scikit-learn/scikit-learn/issues/5523#issuecomment -508807755

@hermidalc schlagen Sie vor, dass wir X ein numpy-Array sein lassen und die Metadaten in anderen Datenrahmenobjekten zuweisen?

@hermidalc schlagen Sie vor, dass wir X ein numpy-Array sein lassen und die Metadaten in anderen Datenrahmenobjekten zuweisen?

Ja, volle Unterstützung für Beispieleigenschaften und Feature-Eigenschaften als Pandas-Datenrahmen. In anderen PRs und Ausgaben wird bereits über Beispieleigenschaften und Featurenamen diskutiert, zB hier #9566 und #14315

Ich habe mich über dieses Problem informiert und es sieht so aus, als ob es hier zwei Hauptblocker gibt:

  1. https://github.com/pandas-dev/pandas/issues/27211
  2. Dass Pandas keine ND-Arrays handhabt.

Haben Sie darüber nachgedacht, stattdessen Unterstützung für Xarrays hinzuzufügen? Sie haben nicht diese Einschränkungen von Pandas.

X = np.arange(10).reshape(5, 2)
assert np.asarray(xr.DataArray(X)) is X
assert np.asarray(xr.Dataset({"data": (("samples", "features"), X)}).data).base is X.base

Es gibt ein Paket namens sklearn-xarray : https://phausamann.github.io/sklearn-xarray/content/wrappers.html , das Scikit-Schätzer umschließt, um Xarrays als Eingabe und Ausgabe zu behandeln, aber das scheint nicht gewartet zu werden Jahre. Ich frage mich jedoch, ob Wrapper hier der richtige Weg sind.

xarray wird aktiv in Erwägung gezogen. Es wird hier prototypisiert und bearbeitet: https://github.com/scikit-learn/scikit-learn/pull/16772 Es gibt ein Nutzungsnotizbuch, wie die API in der PR aussehen würde.

(Ich werde darauf zurückkommen, wenn wir mit der Version 0.23 fertig sind)

Ich interessiere mich auch sehr für diese Funktion.
Es würde unendlich viele Probleme lösen. Dies ist derzeit die Lösung, die ich verwende.
Ich habe einen Wrapper um das Modul sklearn.preprocessing , den ich sklearn_wrapper

Anstatt also aus sklearn.preprocessing importieren, importiere ich aus sklearn_wrapper .
Zum Beispiel:

# this
from sklearn.preprocessing import StandardScaler 
# becomes 
from sklearn_wrapper import StandardScaler

Unten die Implementierung dieses Moduls. Probiert es aus und lasst mich wissen, was ihr denkt

from functools import wraps
from itertools import chain

import pandas as pd
from sklearn import preprocessing, compose, feature_selection, decomposition
from sklearn.compose._column_transformer import _get_transformer_list

modules = (preprocessing, feature_selection, decomposition)


def base_wrapper(Parent):
    class Wrapper(Parent):

        def transform(self, X, **kwargs):
            result = super().transform(X, **kwargs)
            check = self.check_out(X, result)
            return check if check is not None else result

        def fit_transform(self, X, y=None, **kwargs):
            result = super().fit_transform(X, y, **kwargs)
            check = self.check_out(X, result)
            return check if check is not None else result

        def check_out(self, X, result):
            if isinstance(X, pd.DataFrame):
                result = pd.DataFrame(result, index=X.index, columns=X.columns)
                result = result.astype(X.dtypes.to_dict())
            return result

        def __repr__(self):
            name = Parent.__name__
            tmp = super().__repr__().split('(')[1]
            return f'{name}({tmp}'

    Wrapper.__name__ = Parent.__name__
    Wrapper.__qualname__ = Parent.__name__

    return Wrapper


def base_pca_wrapper(Parent):
    Parent = base_wrapper(Parent)

    class Wrapper(Parent):
        @wraps(Parent)
        def __init__(self, *args, **kwargs):
            self._prefix_ = kwargs.pop('prefix', 'PCA')
            super().__init__(*args, **kwargs)

        def check_out(self, X, result):
            if isinstance(X, pd.DataFrame):
                columns = [f'{self._prefix_}_{i}' for i in range(1, (self.n_components or X.shape[1]) + 1)]
                result = pd.DataFrame(result, index=X.index, columns=columns)
            return result

    return Wrapper


class ColumnTransformer(base_wrapper(compose.ColumnTransformer)):

    def check_out(self, X, result):
        if isinstance(X, pd.DataFrame):
            return pd.DataFrame(result, index=X.index, columns=self._columns[0]) if self._remainder[1] == 'drop' \
                else pd.DataFrame(result, index=X.index, columns=X.columns). \
                astype(self.dtypes.iloc[self._remainder[-1]].to_dict())


class SelectKBest(base_wrapper(feature_selection.SelectKBest)):

    def check_out(self, X, result):
        if isinstance(X, pd.DataFrame):
            return pd.DataFrame(result, index=X.index, columns=X.columns[self.get_support()]). \
                astype(X.dtypes[self.get_support()].to_dict())


def make_column_transformer(*transformers, **kwargs):
    n_jobs = kwargs.pop('n_jobs', None)
    remainder = kwargs.pop('remainder', 'drop')
    sparse_threshold = kwargs.pop('sparse_threshold', 0.3)
    verbose = kwargs.pop('verbose', False)
    if kwargs:
        raise TypeError('Unknown keyword arguments: "{}"'
                        .format(list(kwargs.keys())[0]))
    transformer_list = _get_transformer_list(transformers)
    return ColumnTransformer(transformer_list, n_jobs=n_jobs,
                             remainder=remainder,
                             sparse_threshold=sparse_threshold,
                             verbose=verbose)


def __getattr__(name):
    if name not in __all__:
        return

    for module in modules:
        Parent = getattr(module, name, None)
        if Parent is not None:
            break

    if Parent is None:
        return

    if module is decomposition:
        Wrapper = base_pca_wrapper(Parent)
    else:
        Wrapper = base_wrapper(Parent)

    return Wrapper


__all__ = [*[c for c in preprocessing.__all__ if c[0].istitle()],
           *[c for c in decomposition.__all__ if c[0].istitle()],
           'SelectKBest']


def __dir__():
    tmp = dir()
    tmp.extend(__all__)
    return tmp

https://github.com/koaning/scikit-lego/issues/304 bot eine weitere Lösung durch Hotfixing auf der sklearn.pipeline.FeatureUnion

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen