Pandas: Wunschliste: get_dummies () für das Train / Test-Framework verwendbar machen

Erstellt am 28. Nov. 2014  ·  21Kommentare  ·  Quelle: pandas-dev/pandas

Get_dummies () in Pandas zu haben ist wirklich nett, aber um für maschinelles Lernen nützlich zu sein, müsste es in einem Zug- / Test-Framework (oder "fit_transform" und "transform" mit der sklearn-Terminologie) verwendbar sein. Lassen Sie mich wissen, wenn dies weitere Erklärungen benötigt.

Ich denke, dies ist ein Fehlerbericht auf der Wunschliste, um Pandas diese Funktionalität hinzuzufügen. Ich kann sogar eine Pull-Anfrage erstellen, wenn die Leute zustimmen, dass dies in Pandas nützlich wäre (und bereit sind, ein wenig zu coachen und Code-Überprüfungen für meinen ersten Beitrag zu diesem Projekt durchzuführen).

Categorical Reshaping Usage Question

Hilfreichster Kommentar

Sie müssen lediglich Ihre Variablen Categorical wenn Sie möglicherweise nicht beobachtete Variablen angeben möchten. Dies kann zum Zeitpunkt der Erstellung oder danach erfolgen (siehe Dokumentation)

In [5]: df_train = pd.DataFrame({"car":Series(["seat","bmw"]).astype('category',categories=['seat','bmw','mercedes']),"color":["red","green"]})

In [6]: df_train
Out[6]: 
    car  color
0  seat    red
1   bmw  green

In [7]: pd.get_dummies(df_train )
Out[7]: 
   car_seat  car_bmw  car_mercedes  color_green  color_red
0         1        0             0            0          1
1         0        1             0            1          0

Die ursprüngliche Frage ist nicht genau spezifiziert, also schließen.

Alle 21 Kommentare

Wie wäre es mit einem Pseudocode-Beispiel mit Ein- und Ausgängen aus einem Beispielrahmen?

@ chrish42 , ein Beispiel wäre toll.

Zu Ihrer Information, scikit-learn hat die OneHotEncoder- Klasse, die in ihre Pipeline passt.

So etwas sollte funktionieren?

import pandas as pd
from sklearn.pipeline import TransformerMixin

class DummyEncoder(TransformerMixin):

    def __init__(self, columns=None):

        self.columns = columns

    def transform(self, X, y=None, **kwargs):

        return pd.get_dummies(X, columns=self.columns)

    def fit(self, X, y=None, **kwargs):

        return self

Geben

In [15]: df
Out[15]: 
   A  B  C
0  1  a  a
1  2  b  a

In [16]: DummyEncoder().transform(df)
Out[16]: 
   A  B_a  B_b  C_a
0  1    1    0    1
1  2    0    1    1

Seien Sie vorsichtig bei der Reihenfolge der Spalten.

@ TomAugspurger , eigentlich ist die Kompatibilität mit der sklearn-Verarbeitungspipeline selbst nicht der Teil, der mich interessiert. Was ich möchte, ist die Möglichkeit, die von get_dummes () durchgeführte Transformation in einem Dataset zu speichern und diese Transformation dann unverändert anzuwenden (wobei genau dieselben Spalten erstellt werden), selbst wenn das zweite Dataset eine Teilmenge der Werte des ersten enthält in einer Spalte usw. Das habe ich eigentlich mit "verwendbar in einem Zug- / Test-Framework" gemeint. Ist diese Erklärung klarer? (Ich kann ein Beispiel hinzufügen, von dem jemand glaubt, dass es noch benötigt wird.)

Ich bin mir der OneHotEncoder -Klasse in sklearn bewusst, aber es gibt andere Einschränkungen.

Ich stolperte über das gleiche Problem wie @ chrish42 und fand get_dummies, die mir Kopfschmerzen bereiteten.

Beispiel für die Einschränkungen der aktuellen Get-Dummies

Nehmen wir an, wir arbeiten mit Daten aus dem folgenden df_train DataFrame

`` `.python
df_train = pandas.DataFrame ({"Auto": ["Sitz", "BMW"], "Farbe": ["Rot", "Grün"]})
pandas.get_dummies (df_train)

car_bmw car_seat color_green color_red
0 0 1 0 1
1 1 0 1 0


Then we are provided with

``` .python
df_test = pandas.DataFrame({"car":["seat","mercedes"], "color":["red","green"]})
pandas.get_dummies(df_test )

         car_mercedes  car_seat  color_green  color_red
0             0         1            0          1
1             1         0            1          0

Da ich in df_train noch nie einen "Mercedes" -Wert für die Variable "Auto" beobachtet habe, möchte ich die folgende Hot-Codierung erhalten können:

`` `.python
car_bmw car_seat color_green color_red
0 0 1 0 1
1 0 0 1 0


Where the column car_mercedes actually never appears.

This could be solved by allowing get_dummies to receive an input dictionary stating the accepted values that we allow for each column.  

Returning to the previous example, we could give as input to get_dummies the following dict of sets

``` .python
accepted_values_per_column = {'car': {'bmw', 'seat'}, 'color': {'green', 'red'}}

und wir würden erwarten, dass get_dummies zurückkehren

`` `.python
get_dummies (df_test, accept_values_per_column = accept_values_per_column)

       car_bmw  car_seat  color_green  color_red

0 0 1 0 1
1 0 0 1 0
`` `

und erwarten Sie, dass get_dummies (df_test) zurückgibt, was bereits zurückgegeben wird.

Sie müssen lediglich Ihre Variablen Categorical wenn Sie möglicherweise nicht beobachtete Variablen angeben möchten. Dies kann zum Zeitpunkt der Erstellung oder danach erfolgen (siehe Dokumentation)

In [5]: df_train = pd.DataFrame({"car":Series(["seat","bmw"]).astype('category',categories=['seat','bmw','mercedes']),"color":["red","green"]})

In [6]: df_train
Out[6]: 
    car  color
0  seat    red
1   bmw  green

In [7]: pd.get_dummies(df_train )
Out[7]: 
   car_seat  car_bmw  car_mercedes  color_green  color_red
0         1        0             0            0          1
1         0        1             0            1          0

Die ursprüngliche Frage ist nicht genau spezifiziert, also schließen.

Und wenn Sie in die andere Richtung gehen, von der Codierung bis zurück zu Categorical, verwenden Sie Categorical.from_codes.

Noch ein paar unaufgeforderte Ratschläge. Wenn Sie sich überhaupt für genaue Schätzungen der Koeffizienten in den Kategorien interessieren, lassen Sie eine der codierten Spalten fallen, da Sie sonst eine Multicolinearität mit dem Achsenabschnitt haben (falls Sie eine haben).

Am 5. Oktober 2015, um 05:34 Uhr, schrieb Jeff Reback [email protected] :

Sie müssen Ihre Variablen lediglich kategorisch machen, wenn Sie möglicherweise nicht beobachtete Variablen angeben möchten. Dies kann zum Zeitpunkt der Erstellung oder danach erfolgen (siehe Dokumentation)

In [5]: df_train = pd.DataFrame ({"Auto": Serie (["Sitz", "bmw"]). Astype ('Kategorie', Kategorien = ['Sitz', 'bmw', 'Mercedes'] ), "Farbe": ["Rot", "Grün"]})

In [6]: df_train
Out [6]:
Autofarbe
0 Sitz rot
1 bmw grün

In [7]: pd.get_dummies (df_train)
Out [7]:
car_seat car_bmw car_mercedes color_green color_red
0 1 0 0 0 1
1 0 1 0 1 0
Die ursprüngliche Frage ist nicht genau spezifiziert, also schließen.

- -
Antworte direkt auf diese E-Mail oder sieh sie dir auf GitHub an.

@TomAugspurger @jreback Ich glaube, ich bin in letzter Zeit auf das gleiche Problem gestoßen und möchte ein Beispiel nennen

train_a = pd.DataFrame ({"IsBadBuy": [0,1,0], "Make": ['Toyota', 'Mazda', 'BMW']})

IsBadBuy Make_BMW Make_Mazda Make_Toyota
0 0 0 0 1
1 1 0 1 0
2 0 1 0 0

test_a = pd.DataFrame ({"Make": ['Toyota', 'BMW']})
print pd.get_dummies (test_a, columns = ['Make'])

Make_BMW Make_Toyota
0 0 1
1 1 0

Im Idealfall sollte hier die Spalte Make_Mazda beibehalten werden, da der ML-Algorithmus die gleiche Anzahl von Features erwarten würde und die Werte, die wir im Test erhalten, eine Teilmenge der Werte im Zug sind.

Verwenden Sie eine Kategorie. Das wird auf die richtige Anzahl von Spalten erweitert. Ich habe einen Vortrag darüber gehalten, wenn Sie interessiert sind https://m.youtube.com/watch?v=KLPtEBokqQ0

    _____________________________

Von: Ajay Saxena [email protected]
Gesendet: Donnerstag, 12. Januar 2017, 18:31 Uhr
Betreff: Re: [pandas-dev / pandas] Wunschliste: get_dummies () für das Train / Test-Framework verwendbar machen (# 8918)
An: pandas-dev / pandas [email protected]
Cc: Tom Augspurger [email protected] , Erwähnung Erwä[email protected]

@jreback Ich glaube, ich bin in letzter Zeit auf das gleiche Problem gestoßen und möchte ein Beispiel nennen

train_a = pd.DataFrame ({"IsBadBuy": [0,1,0], "Make": ['Toyota', 'Mazda', 'BMW']})

IsBadBuy Make_BMW Make_Mazda Make_Toyota
0 0 0 0 1
1 1 0 1 0
2 0 1 0 0

test_a = pd.DataFrame ({"Make": ['Toyota', 'BMW']})
print pd.get_dummies (test_a, columns = ['Make'])

Make_BMW Make_Toyota
0 0 1
1 1 0

Im Idealfall sollte hier die Spalte Make_Mazda beibehalten werden, da der ML-Algorithmus die gleiche Anzahl von Features erwarten würde und die Werte, die wir im Test erhalten, eine Teilmenge der Werte im Zug sind.

- -
Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail, zeigen Sie sie auf GitHub an oder schalten Sie den Thread stumm.

Danke @TomAugspurger

Der PyData Chicago 2016-Vortrag von @TomAugspurger war wirklich gut gemacht. Er hat großartige Arbeit geleistet, um alle Gründe zu veranschaulichen, warum dieses Problem / diese Anfrage nicht geschlossen werden sollte. IMHO sollte entweder seine Klasse DummyEncoder oder ein vernünftiges Äquivalent in Pandas enthalten sein. Ja, ich kann zu seinem Github gehen und seine Klasse kopieren / emulieren, aber es wäre viel schöner, wenn sie nur in der Bibliothek unterstützt würde.

Ich denke, es besteht Bedarf an einer Bibliothek, die früh in der Datenmodellierung eingesetzt wird
Pipeline und funktioniert gut mit Pandas und Scikit-Learn.
Aber Pandas hängen nicht vom Scikit-Lernen ab und umgekehrt. Ich denke es gibt
Platz für eine weitere Bibliothek, die auf beiden gebaut wurde.

Am Mittwoch, den 10. Mai 2017 um 18:13 Uhr, Brian Wylie [email protected]
schrieb:

Der PyData Chicago 2016 Vortrag von @TomAugspurger
https://github.com/TomAugspurger war wirklich gut gemacht. Er hat eine
fantastische Arbeit, um alle Gründe zu veranschaulichen, warum dieses Problem / diese Anfrage sollte
nicht geschlossen werden. IMHO entweder seine Klasse DummyEncoder oder eine vernünftige
Äquivalent sollte in Pandas enthalten sein. Ja, ich kann zu seinem Github gehen
und kopiere / emuliere seine Klasse, aber es wäre viel schöner, sie einfach zu haben
innerhalb der Bibliothek unterstützt.

Übrigens denke ich, dass https://github.com/TomAugspurger mein sein könnte
neuer Lieblings-PyData-Guru. Ich werde alles jagen, was er ist
fertig / arbeite daran und versuche es zu absorbieren .. nicht auf gruselige / pirschende Weise .. du
weiß nur auf normale Weise, dass das überhaupt nicht gruselig ist. :) :)

- -
Sie erhalten dies, weil Sie erwähnt wurden.
Antworte direkt auf diese E-Mail und sieh sie dir auf GitHub an
https://github.com/pandas-dev/pandas/issues/8918#issuecomment-300638388 ,
oder schalten Sie den Thread stumm
https://github.com/notifications/unsubscribe-auth/ABQHIpTqgHSE7iFVF9Pp4_YoKB9DPLcEks5r4kSrgaJpZM4DB6Hb
.

Hier ist eine kleine Lösung, an der einige von uns gearbeitet haben und die für einige hier hilfreich sein kann. Dummy-Variablen mit Anpassungs- / Transformationsfunktionen.

https://github.com/joeddav/get_smarties

Feedback und Beiträge wären hilfreich!

Dies scheint im Zusammenhang mit # 14017 zu stehen

Ich habe eine Lösung erstellt, die genau bei diesem Problem hilfreich sein kann. Eine kategoriale Hot-Encoding-Variable in einem Zugtest-Framework. Es kann auch Fälle behandeln, in denen der Datensatz zu groß ist, um in den Maschinenspeicher zu passen.

https://github.com/yashu-seth/dummyPy

Sie können auch ein kleines Tutorial zu diesem Thema finden Sie hier .

@ TomAugspurger Dieser Code funktioniert nicht. Wenn ich meine Produktionsdaten für einzelne Datensätze transformiere, erhalte ich nur die eine heißcodierte Spalte für den einzelnen Wert, der vorhanden ist.
Was vermisse ich?

Pyodbc importieren
Gurke importieren
aus sklearn.linear_model import LogisticRegression
aus sklearn.linear_model LinearRegression importieren

importiere numpy als np
Pandas als pd importieren
aus sklearn.pipeline TransformerMixin importieren
aus sklearn.pipeline importiere make_pipeline

Klasse DummyEncoder (TransformerMixin):
def fit (self, X, y = None):
self.index_ = X.index
self.columns_ = X.columns
self.cat_columns_ = X.select_dtypes (include = ['category']). column
self.non_cat_columns_ = X.columns.drop (self.cat_columns_)

    self.cat_map_ = {col: X[col].cat for col in self.cat_columns_}

    left = len(self.non_cat_columns_)
    self.cat_blocks_ = {}
    for col in self.cat_columns_:
        right = left + len(X[col].cat.categories)
        self.cat_blocks_[col], left = slice(left, right), right
    return self

def transform(self, X, y=None):
    return np.asarray(pd.get_dummies(X))

def inverse_transform(self, X):
    non_cat = pd.DataFrame(X[:, :len(self.non_Cat_columns_)],
                             columns=self.non_cat_columns_)
    cats = []
    for col, cat in self.cat_map_.items():
        slice_ = self.cat_blocks_[col]
        codes = X[:, slice_].argmax(1)
        series = pd.Series(pd.Categorical.from_codes(
                codes, cat.categories, ordered=cat.ordered
        ), name=col)
        cats.append(series)
    df = pd.concat([non_cat] + cats, axis=1)[self.columns_]
    return df

Daten aus SQL in Pandas Dataframe importieren

cnxn = pyodbc.connect ('DRIVER = {SQL Server}; Server = {XXXXX}; DATABASE = {ML_Learn_Taxi}; UID = {XXXX}; PWD = {XXXX}')
sql = "" "
SELECT top 1 CONVERT (int, [order_key]) order_key
, CONVERT (int, [service_date_key]) service_date_key
, [order_source_desc]
, 1 als 'return_flag'
FROM [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
WHERE [order_source_desc] = 'Online'
UNION
SELECT top 2 CONVERT (int, [order_key])
, CONVERT (int, [service_date_key])
, [order_source_desc]
, 2
FROM [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
WHERE [order_source_desc] = 'Eingehender Anruf'
UNION
SELECT top 1 CONVERT (int, [order_key])
, CONVERT (int, [service_date_key])
, [order_source_desc]
, 1
FROM [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
WHERE [order_source_desc] = 'Ausgehender Anruf'
"" "

prod_sql = "" "
SELECT top 1 CONVERT (int, [order_key]) order_key
, CONVERT (int, [service_date_key]) service_date_key
, [order_source_desc]
, 1 als 'return_flag'
FROM [ML_Return_Customer]. [Dbo]. [Return_customers_test_set]
WHERE [order_source_desc] = 'Online'
"" "

InputDataSet = pd.read_sql (sql, cnxn)
ProdDataSet = pd.read_sql (prod_sql, cnxn)

print (" * * * * Daten

* * * * * ")
print (InputDataSet)

print (" * Kategorie Spalten Info

* * ")
Spalten = ['order_source_desc']
InputDataSet [Spalten] = InputDataSet [Spalten] .apply (Lambda x: x.astype ('Kategorie'))

InputDataSet.info ()

print (" * Lineare Regression

* * ")

X = InputDataSet.drop ('return_flag', axis = 1)
y = InputDataSet ['return_flag']

A = ProdDataSet.drop ('return_flag', axis = 1)
B = ProdDataSet ['return_flag']

enc = DummyEncoder ()
enc.fit (X)

rain = enc.transform (X)

Prod = enc.transform (A)

drucken (Prod)

AUSGABE: * * * * Daten

* * * *
order_key service_date_key order_source_desc return_flag
0 10087937 20151214 Online 1
1 10088174 20151201 Eingehender Anruf 2
2 10088553 20151217 Eingehender Anruf 2
3 663478 20160806 Ausgehender Anruf 1
* Informationen zu Kategoriespalten * *

RangeIndex: 4 Einträge, 0 bis 3
Datenspalten (insgesamt 4 Spalten):
order_key 4 ungleich null int64
service_date_key 4 nicht null int64
order_source_desc 4 Nicht-Null-Kategorie
return_flag 4 ungleich null int64
dtypes: Kategorie (1), int64 (3)
Speichernutzung: 284,0 Bytes
* Lineare Regression * * *
[[10087937 20151214 1]]

Ich denke, dieser Thread ist etwas chaotisch, deshalb werde ich versuchen, hier eine einfache Lösung zusammenzufassen und wie dies bereits möglich ist. Ich werde in einer Spalte demonstrieren, aber Sie können es auf viele verallgemeinern.

In "fit" rufen Sie also einfach an:

categories = sorted(training_data.iloc[:, column_index].value_counts(dropna=True).index)

Sie speichern categories in dem Zustand, den Sie während der Anpassung lernen.

Und dann tun Sie in "transformieren":

from pandas.api import types as pandas_types

categorical_data = testing_data.iloc[:, [column_index]].astype(
    pandas_types.CategoricalDtype(categories=categories),
)
one_hot_encoded = pandas.get_dummies(categorical_data)

Und es wird eine One-Hot-Codierung immer in derselben Zuordnung für Werte durchgeführt. Wenn während des Trainings kein kategorialer Wert vorhanden war, wird er während des Tests als NaN angesehen. Wenn während des Tests kein Wert angezeigt wird, wird keine Spalte dafür festgelegt.

Das ist sehr nett. Ich wünschte nur, jeder, der dies tun möchte, müsste es nicht neu entdecken. ;-);

In Übung des Kaggle XGBoost-Tutorials wurde der folgende Code angezeigt. Das macht den Trick.

X_train = pd.get_dummies(X_train)
X_valid = pd.get_dummies(X_valid)
X_test = pd.get_dummies(X_test)
X_train, X_valid = X_train.align(X_valid, join='left', axis=1)
X_train, X_test = X_train.align(X_test, join='left', axis=1)

Ich habe das gleiche Problem auch mehrmals gesehen. Ich habe unten eine Klasse geschrieben (die Ideen aus dieser Diskussion aufgreift), die mir die Sache erleichtert hat.

import pandas
from sklearn.preprocessing import LabelEncoder

class CategoryEncoder:
    '''
    labelEncoding : boolean -> True If the categorical columns are to be label encoded
    oneHotEncoding : boolean -> True If the categorical columns are to be one hot encoded (using pandas.get_dummies method)
    dropFirst : boolean -> True if first column is to be dropped (usually to avoid multi-collinearity) post one hot encoding
                           Doesn't matter if oneHotEncoding = False

    df : pandas.DataFrame() -> dataframe object that needs to be encoded
    catCols : list -> list of the categorical columns that need to be encoded
    '''
    def __init__(self,labelEncoding=True,oneHotEncoding=False,dropFirst=False):
        self.labelEncoding = labelEncoding
        self.oneHotEncoding = oneHotEncoding
        self.dropFirst = dropFirst
        self.labelEncoder = {}
        self.oneHotEncoder = {}

    def fit(self,df,catCols=[]):
        df1 = df.copy()
        if self.labelEncoding:
            for col in catCols:
                labelEncoder = LabelEncoder()
                labelEncoder.fit(df1.loc[:,col].astype(str))
                df1.loc[:,col] = labelEncoder.transform(df1.loc[:,col])
                self.labelEncoder[col] = labelEncoder.classes_

        if self.oneHotEncoding:
            for col in catCols:
                cats = sorted(df1.loc[:,col].value_counts(dropna=True).index)
                self.oneHotEncoder[col] = cats

    def transform(self,df,catCols=[]):
        df1 = df.copy()
        if self.labelEncoding:
            for col in catCols:
                labelEncoder = self.labelEncoder[col]
                labelEncoder = {v:i for i,v in enumerate(labelEncoder.tolist())}
                print(labelEncoder)
                df1.loc[:,col] = df1.loc[:,col].map(labelEncoder)

        if self.oneHotEncoding:
            for col in catCols:
                oneHotEncoder = self.oneHotEncoder[col]
                df1.loc[:,col] = df1.loc[:,col].astype(pandas.CategoricalDtype(categories=oneHotEncoder))
            df1 = pandas.get_dummies(df1,columns=catCols,drop_first=self.dropFirst)

        return df1

Einfach zu initiieren und auch eine Instanz des Encoders zu verwenden.

enc1 = CategoryEncoder(True,False)     # Will label encode but not one-hot encode
enc2 = CategoryEncoder(False,True,True)     # Will one-hot encode but not label encode
enc3 = CategoryEncoder(True,True,True)     # Will label encode first and then one-hot encode

# List of categorical columns you want to encode
categorical_columns = ['col_1', 'col_2']

enc1.fit(train_df, categorical_columns)
enc1.transform(test_df, categorical_columns) # Returns the dataframe encoded columns

HINWEIS: Hiermit werden keine Ausnahmen behoben, z. B. die Übergabe der Spaltennamen, die im Datenrahmen nicht verfügbar sind

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen
bleepcoder.com verwendet öffentlich lizenzierte GitHub-Informationen, um Entwicklern auf der ganzen Welt Lösungen für ihre Probleme anzubieten. Wir sind weder mit GitHub, Inc. noch mit anderen Entwicklern affiliiert, die GitHub für ihre Projekte verwenden. Wir hosten keine der Videos oder Bilder auf unseren Servern. Alle Rechte gehören ihren jeweiligen Eigentümern.
Quelle für diese Seite: Quelle

Beliebte Programmiersprachen
Beliebte GitHub Projekte
Mehr GitHub Projekte

© 2024 bleepcoder.com - Contact
Made with in the Dominican Republic.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.