Übergabe kategorialer Daten an den Sklearn-Entscheidungsbaum

75

Es gibt mehrere Beiträge zum Codieren kategorialer Daten in Sklearn-Entscheidungsbäume, aber aus der Sklearn-Dokumentation haben wir diese erhalten

Einige Vorteile von Entscheidungsbäumen sind:

(...)

Kann sowohl numerische als auch kategoriale Daten verarbeiten. Andere Techniken sind normalerweise auf die Analyse von Datensätzen spezialisiert, die nur einen Variablentyp aufweisen. Weitere Informationen finden Sie in den Algorithmen.

Führen Sie jedoch das folgende Skript aus

import pandas as pd 
from sklearn.tree import DecisionTreeClassifier

data = pd.DataFrame()
data['A'] = ['a','a','b','a']
data['B'] = ['b','b','a','b']
data['C'] = [0, 0, 1, 0]
data['Class'] = ['n','n','y','n']

tree = DecisionTreeClassifier()
tree.fit(data[['A','B','C']], data['Class'])

gibt den folgenden Fehler aus:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/sklearn/tree/tree.py", line 154, in fit
    X = check_array(X, dtype=DTYPE, accept_sparse="csc")
  File "/usr/local/lib/python2.7/site-packages/sklearn/utils/validation.py", line 377, in check_array
    array = np.array(array, dtype=dtype, order=order, copy=copy)
ValueError: could not convert string to float: b

Ich weiß, dass es in R möglich ist, kategoriale Daten mit Sklearn zu übergeben. Ist das möglich?

0xhfff
quelle

Antworten:

-3

Entgegen der akzeptierten Antwort würde ich es vorziehen, die von Scikit-Learn bereitgestellten Tools für diesen Zweck zu verwenden. Der Hauptgrund dafür ist, dass sie leicht in eine Pipeline integriert werden können .

Scikit-Learn selbst bietet sehr gute Klassen für den Umgang mit kategorialen Daten. Anstatt Ihre benutzerdefinierte Funktion zu schreiben, sollten Sie eine verwenden, LabelEncoderdie speziell für diesen Zweck entwickelt wurde .

Beachten Sie den folgenden Code aus der Dokumentation:

from sklearn import preprocessing
le = preprocessing.LabelEncoder()
le.fit(["paris", "paris", "tokyo", "amsterdam"])
le.transform(["tokyo", "tokyo", "paris"]) 

Dadurch werden sie automatisch in Zahlen für Ihre Algorithmen für maschinelles Lernen codiert. Dies unterstützt jetzt auch das Zurückkehren zu Zeichenfolgen von Ganzzahlen. Sie können dies tun, indem Sie einfach inverse_transformwie folgt aufrufen :

list(le.inverse_transform([2, 2, 1]))

Dies würde zurückkehren ['tokyo', 'tokyo', 'paris'].

Beachten Sie auch, dass Sie für viele andere Klassifizierer, abgesehen von Entscheidungsbäumen wie logistischer Regression oder SVM, Ihre kategorialen Variablen mithilfe der One-Hot-Codierung codieren möchten . Scikit-learn unterstützt dies auch durch die OneHotEncoderKlasse.

Hoffe das hilft!

Abhinav Arora
quelle
152
-1 das ist irreführend. Derzeit verarbeiten sklearn-Entscheidungsbäume keine kategorialen Daten - siehe Problem Nr. 5442 . Dieser Ansatz der Verwendung der Etikettencodierung konvertiert in Ganzzahlen, die DecisionTreeClassifier() als numerisch behandelt werden . Wenn Ihre kategorialen Daten nicht ordinal sind, ist dies nicht gut - Sie erhalten Splits, die keinen Sinn ergeben. Die Verwendung von a OneHotEncoderist der einzig gültige Weg, ist jedoch rechenintensiv.
James Owers
@Abhinav, Ist es möglich, das LabelEncoderauf mehrere Spalten eines Datenrahmens gleichzeitig anzuwenden? Können wir beispielsweise im Datenrahmen der Frage so etwas wie le.fit_transform(data[['A','B','C']])Beschriftungen für alle kategorialen Spalten gleichzeitig abrufen ? Oder Sie sollten die kategorialen Spalten explizit angeben, um nur die kategorialen Spalten zu konvertieren.
Minu
21
Das ist sehr irreführend. Bitte konvertieren Sie keine Zeichenfolgen in Zahlen und verwenden Sie sie nicht in Entscheidungsbäumen. Es gibt keine Möglichkeit, mit kategorialen Daten in scikit-learn umzugehen. Eine Möglichkeit besteht darin, den Entscheidungsbaumklassifikator in Spark zu verwenden, in dem Sie die kategorialen Merkmale und ihre Ordinalität explizit deklarieren können. Siehe hier für weitere Details github.com/scikit-learn/scikit-learn/pull/4899
Pradeep Banavara
6
Jeder muss Messskalen lernen, nämlich Nominal-, Ordinal-, Intervall- und Verhältnisskalen. Zahl bedeutet nicht, dass es in der Nominalskala numerisch ist; Es ist nur eine Flagge. Zum Beispiel können wir 1 für Rot, 2 für Blau und 3 für Grün verwenden. Angenommen, 10 Personen bevorzugen Rot und 10 bevorzugen Grün. Ist es sinnvoll, den Mittelwert ((10 * 1 + 10 * 3) / 20 = 2) zu berechnen und anzugeben, dass im Durchschnitt Blau bevorzugt wird?
Regi Mathew
2
Äh ... ich hatte keine Ahnung, dass es so viel Aufmerksamkeit hatte. Prost @ayorgo, wird reichen!
James Owers
57

(Dies ist nur eine Neuformatierung meines obigen Kommentars aus dem Jahr 2016 ... es gilt immer noch.)

Die akzeptierte Antwort auf diese Frage ist irreführend.

Derzeit verarbeiten sklearn-Entscheidungsbäume keine kategorialen Daten - siehe Problem Nr. 5442 .

Der empfohlene Ansatz zur Verwendung der Beschriftungscodierung wird in Ganzzahlen konvertiert, die als numerischDecisionTreeClassifier() behandelt werden . Wenn Ihre kategorialen Daten nicht ordinal sind, ist dies nicht gut - Sie erhalten Splits, die keinen Sinn ergeben.

Die Verwendung von a OneHotEncoderist der einzig gültige Weg, der beliebige Teilungen zulässt, die nicht von der Etikettenreihenfolge abhängen, aber rechenintensiv sind.

James Owers
quelle
2
OneHotEncoding kann anscheinend die Leistung von Entscheidungsbäumen beeinträchtigen, da es zu äußerst spärlichen Features führt, die die Bedeutung von Features
Arun
1
Einverstanden - Ich empfehle diesen Ansatz nicht, aber es ist die einzige Möglichkeit, das derzeit beschriebene Problem zu vermeiden.
James Owers
Ich vermute, dass es Fälle gibt (mit Funktionen mit vielen kleinen Ebenen), in denen die "Unsinn" -Splits bei einem normalerweise codierten kategorialen Feature dennoch eine bessere Leistung erzielen als die sehr begrenzten Splits bei dem One-Hot-codierten Feature.
Ben Reiniger
Gibt es eine andere Implementierung des Entscheidungsbaumklassifikators, die dies handhaben kann?
Modem Rakesh goud
12

(..)

Kann sowohl numerische als auch kategoriale Daten verarbeiten.

Dies bedeutet nur, dass Sie verwenden können

  • die DecisionTreeClassifier-Klasse für Klassifizierungsprobleme
  • die DecisionTreeRegressor-Klasse für die Regression.

In jedem Fall müssen Sie kategoriale Variablen einmalig codieren, bevor Sie einen Baum mit sklearn anpassen, wie folgt:

import pandas as pd
from sklearn.tree import DecisionTreeClassifier

data = pd.DataFrame()
data['A'] = ['a','a','b','a']
data['B'] = ['b','b','a','b']
data['C'] = [0, 0, 1, 0]
data['Class'] = ['n','n','y','n']

tree = DecisionTreeClassifier()

one_hot_data = pd.get_dummies(data[['A','B','C']],drop_first=True)
tree.fit(one_hot_data, data['Class'])
Guillaume
quelle
2
Möglicherweise möchten Sie 'pd.get_dummies' herumspielen. Beispielsweise könnte die Option 'drop_first = True' helfen, Multicolinearitätsprobleme zu vermeiden. Hier gibt es ein schönes Tutorial.
Rafael Valero
4

Für nominelle kategoriale Variablen würde ich nicht verwenden, LabelEncodersondern sklearn.preprocessing.OneHotEncoderoder pandas.get_dummiesstattdessen, weil es normalerweise keine Reihenfolge in dieser Art von Variablen gibt.

Cédric Gaudissart
quelle
2

Sklearn-Entscheidungsbäume verarbeiten keine Konvertierung von kategorialen Zeichenfolgen in Zahlen. Ich schlage vor, Sie finden in Sklearn eine Funktion (vielleicht diese ), die dies tut, oder schreiben manuell Code wie:

def cat2int(column):
    vals = list(set(column))
    for i, string in enumerate(column):
        column[i] = vals.index(string)
    return column
mrwyatt
quelle
Ja, das ist normalerweise so, aber zum Drucken ist es nicht wirklich gut.
0xhfff
Wenn Sie von der Ganzzahl zurück zur Zeichenfolgendarstellung wechseln möchten, erstellen Sie ein Wörterbuch, das die Zuordnung zwischen Zeichenfolge und Ganzzahl enthält, und verwenden Sie dieses, um die Ganzzahldarstellung zu "dekodieren".
Mrwyatt
1
Die Aussage ist ungenau. Scikit-Learn-Klassifizierer behandeln die Etikettencodierung nicht implizit. Scikit-learn bietet jedoch viele Klassen, um dies zu handhaben. Ich würde die Verwendung von Scikit-Lernwerkzeugen empfehlen, da diese mit minimalem Aufwand auch in eine Pipeline für maschinelles Lernen integriert werden können.
Abhinav Arora