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).
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.
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ünIn [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 .
Personen, die dies abonniert haben, sind möglicherweise an der Implementierung von dask-ml interessiert
@ 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
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 (" * Kategorie Spalten Info
* * ")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)
Prod = enc.transform (A)
drucken (Prod)
AUSGABE: * * * * Daten
* * * *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. ;-);
Der von @mitar vorgeschlagene https://nbviewer.jupyter.org/github/SuperCowPowers/scp-labs/blob/master/notebooks/Categorical_Encoding_Dangers.ipynb
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
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)Die ursprüngliche Frage ist nicht genau spezifiziert, also schließen.