Estoy tratando de usar scikit-learn LabelEncoder
para codificar pandas DataFrame
de etiquetas de cadena. Como el marco de datos tiene muchas (50+) columnas, quiero evitar crear un LabelEncoder
objeto para cada columna; Prefiero tener un solo LabelEncoder
objeto grande que funcione en todas mis columnas de datos.
Tirar todo el DataFrame
en LabelEncoder
crea el siguiente error. Tenga en cuenta que estoy usando datos ficticios aquí; en realidad estoy tratando con unas 50 columnas de datos etiquetados con cadenas, así que necesito una solución que no haga referencia a ninguna columna por su nombre.
import pandas
from sklearn import preprocessing
df = pandas.DataFrame({
'pets': ['cat', 'dog', 'cat', 'monkey', 'dog', 'dog'],
'owner': ['Champ', 'Ron', 'Brick', 'Champ', 'Veronica', 'Ron'],
'location': ['San_Diego', 'New_York', 'New_York', 'San_Diego', 'San_Diego',
'New_York']
})
le = preprocessing.LabelEncoder()
le.fit(df)
Rastreo (última llamada más reciente): Archivo "", línea 1, en Archivo "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/preprocessing/label.py", línea 103, en forma y = column_or_1d (y, warn = True) Archivo "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py", línea 306, en column_or_1d elevar ValueError ("forma de entrada incorrecta { 0} ". Formato (forma)) ValueError: forma de entrada incorrecta (6, 3)
¿Alguna idea sobre cómo solucionar este problema?
fuente
dataframe
de datos de cadena. Estoy haciendo clic en los objetos de codificación, por lo que quiero evitar tener que enredar / desenredar 50 objetos separados. Además, me pregunto si hay una manera de hacer que el codificador simplifique los datos, es decir, simplemente devolviendo una fila con un identificador para cada combinación única de variables en cada columna.replace
método. Vea esta respuesta a continuaciónRespuestas:
Sin embargo, puedes hacer esto fácilmente,
EDIT2:
En scikit-learn 0.20, la forma recomendada es
ya que OneHotEncoder ahora admite la entrada de cadenas. Es posible aplicar OneHotEncoder solo a ciertas columnas con ColumnTransformer.
EDITAR:
Dado que esta respuesta fue hace más de un año, y generó muchos votos a favor (incluida una recompensa), probablemente debería extender esto más.
Para inverse_transform y transform, tienes que hacer un poco de pirateo.
Con esto, ahora retiene todas las columnas
LabelEncoder
como diccionario.fuente
df.apply(LabelEncoder().fit_transform)
?LabelBinarizer
y reutilice el diccionario para un conjunto de prueba? Probéd = defaultdict(LabelBinarizer)
y despuésfit = df.apply(lambda x: d[x.name].fit_transform(x))
, pero se produce una excepción:Exception: Data must be 1-dimensional
. No estoy seguro de cómo espero que se vea el DataFrame resultante ... tal vez cada columna debería contener los vectores binarizados.Como lo mencionó larsmans, LabelEncoder () solo toma una matriz 1-d como argumento . Dicho esto, es bastante fácil rodar su propio codificador de etiquetas que opera en múltiples columnas de su elección y devuelve un marco de datos transformado. Mi código aquí se basa en parte en la excelente publicación de blog de Zac Stewart que se encuentra aquí .
La creación de un codificador de encargo consiste en la simple creación de una clase que responde a la
fit()
,transform()
yfit_transform()
métodos. En su caso, un buen comienzo podría ser algo como esto:Supongamos que queremos codificar nuestros dos atributos categóricos (
fruit
ycolor
), dejandoweight
solo el atributo numérico . Podríamos hacer esto de la siguiente manera:Que transforma nuestro
fruit_data
conjunto de datos dea
Si le pasa un marco de datos que consiste completamente en variables categóricas y omite el
columns
parámetro, se codificará cada columna (que creo que es lo que estaba buscando originalmente):Esto transforma
a
.
Tenga en cuenta que probablemente se ahogará cuando intente codificar atributos que ya son numéricos (agregue algún código para manejar esto si lo desea).
Otra característica interesante de esto es que podemos usar este transformador personalizado en una tubería:
fuente
Desde scikit-learn 0.20 puedes usar
sklearn.compose.ColumnTransformer
ysklearn.preprocessing.OneHotEncoder
:Si solo tiene variables categóricas,
OneHotEncoder
directamente:Si tiene características de tipo heterogéneo:
Más opciones en la documentación: http://scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogeneous-data
fuente
inverse_transform()
Sin embargo, no es compatible con ColumnTransformer. Al menos, no por el momento: github.com/scikit-learn/scikit-learn/issues/11463 . Esa es una gran desventaja para mi aplicación, y probablemente también lo será para otros.No necesitamos un LabelEncoder.
Puede convertir las columnas a categorías y luego obtener sus códigos. Utilicé un diccionario de comprensión a continuación para aplicar este proceso a cada columna y envolver el resultado en un marco de datos de la misma forma con índices y nombres de columna idénticos.
Para crear un diccionario de mapeo, solo puede enumerar las categorías usando una comprensión del diccionario:
fuente
esto no responde directamente a su pregunta (para lo cual Naputipulu Jon y PriceHardman tienen respuestas fantásticas)
Sin embargo, para algunas tareas de clasificación, etc., podría usar
esto puede ingresar un marco de datos con datos categóricos y devolver un marco de datos con valores binarios. Los valores variables se codifican en nombres de columna en el marco de datos resultante. más
fuente
Suponiendo que simplemente está tratando de obtener un
sklearn.preprocessing.LabelEncoder()
objeto que pueda usarse para representar sus columnas, todo lo que tiene que hacer es:En el código anterior, tendrá un número único correspondiente a cada columna. Más precisamente, tendrá un mapeo 1: 1 de
df.columns
tole.transform(df.columns.get_values())
. Para obtener la codificación de una columna, simplemente pásalale.transform(...)
. Como ejemplo, lo siguiente obtendrá la codificación para cada columna:Suponiendo que desea crear un
sklearn.preprocessing.LabelEncoder()
objeto para todas sus etiquetas de fila, puede hacer lo siguiente:En este caso, lo más probable es que tenga etiquetas de fila no únicas (como se muestra en su pregunta). Para ver qué clases creó el codificador puede hacer
le.classes_
. Notarás que esto debería tener los mismos elementos que enset(y for x in df.get_values() for y in x)
. Una vez más, para convertir una etiqueta de fila en una etiqueta codificadale.transform(...)
. Como ejemplo, si desea recuperar la etiqueta para la primera columna de ladf.columns
matriz y la primera fila, puede hacer esto:La pregunta que tenía en su comentario es un poco más complicada, pero aún se puede lograr:
El código anterior hace lo siguiente:
LabelEncoder
clase que no admite tuplas como nombre de clase.LabelEncoder
.Ahora usar este nuevo modelo es un poco más complicado. Suponiendo que deseamos extraer la representación del mismo elemento que buscamos en el ejemplo anterior (la primera columna en columnas df y la primera fila), podemos hacer esto:
Recuerde que cada búsqueda es ahora una representación de cadena de una tupla que contiene la (columna, fila).
fuente
No,
LabelEncoder
no hace esto. Toma matrices 1-d de etiquetas de clase y produce matrices 1-d. Está diseñado para manejar etiquetas de clase en problemas de clasificación, no datos arbitrarios, y cualquier intento de forzarlo a otros usos requerirá código para transformar el problema real en el problema que resuelve (y la solución de vuelta al espacio original).fuente
DataFrame
a la vez?LabelEncoder
código y adáptalo . Yo no uso Pandas, así que no sé lo difícil que será.pandas
personas se ocupen de esta pregunta: estoy seguro de que no soy la única persona con este desafío, así que espero que haya una solución preconstruida.Esto es un año y medio después del hecho, pero yo también necesitaba poder crear
.transform()
múltiples columnas de marcos de datos de pandas a la vez (y también poder hacerlo.inverse_transform()
). Esto amplía la excelente sugerencia de @PriceHardman arriba:Ejemplo:
Si
df
ydf_copy()
sonpandas
marcos de datos de tipo mixto, puede aplicarlosMultiColumnLabelEncoder()
a lasdtype=object
columnas de la siguiente manera:Puede acceder a clases de columna individuales, etiquetas de columna y codificadores de columna utilizados para ajustar cada columna mediante indexación:
mcle.all_classes_
mcle.all_encoders_
mcle.all_labels_
fuente
fit
método de arriba que en realidad no producirá ninguna etiqueta hasta que lo apliques (transform
/fit_transform
) a los datos.Siguiendo los comentarios planteados sobre la solución de @PriceHardman , propondría la siguiente versión de la clase:
Esta clase se ajusta al codificador en el conjunto de entrenamiento y utiliza la versión ajustada cuando se transforma. La versión inicial del código se puede encontrar aquí .
fuente
Un corto camino a
LabelEncoder()
múltiples columnas con undict()
:y puede usar esto
le_dict
para etiquetar Codificar cualquier otra columna:fuente
Es posible hacer todo esto en pandas directamente y es adecuado para una habilidad única del
replace
método.Primero, hagamos un diccionario de diccionarios que asignen las columnas y sus valores a sus nuevos valores de reemplazo.
Como esta siempre será una asignación uno a uno, podemos invertir el diccionario interno para obtener una asignación de los nuevos valores al original.
Ahora, podemos usar la capacidad única del
replace
método para tomar una lista anidada de diccionarios y usar las teclas externas como columnas y las teclas internas como los valores que nos gustaría reemplazar.Podemos volver fácilmente al original encadenando nuevamente el
replace
métodofuente
Después de mucha búsqueda y experimentación con algunas respuestas aquí y en otros lugares, creo que su respuesta está aquí :
Esto preservará los nombres de categoría en las columnas:
fuente
Verifiqué el código fuente ( https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/preprocessing/label.py ) de LabelEncoder. Se basó en un conjunto de transformaciones numpy, una de las cuales es np.unique (). Y esta función solo toma entrada de matriz 1-d. (corrígeme si estoy equivocado).
Ideas muy aproximadas ... primero, identifique qué columnas necesitaban LabelEncoder, luego recorra cada columna.
El df devuelto sería el que aparece después de la codificación, y label_list le mostrará lo que significan todos esos valores en la columna correspondiente. Este es un fragmento de un script de proceso de datos que escribí para trabajar. Avíseme si cree que podría haber alguna mejora adicional.
EDITAR: Solo quiero mencionar aquí que los métodos anteriores funcionan con el marco de datos sin perder lo mejor. No estoy seguro de cómo funciona para que el marco de datos contenga datos faltantes. (Tuve un trato con el procedimiento faltante antes de ejecutar los métodos anteriores)
fuente
si tenemos una sola columna para hacer la codificación de la etiqueta y su transformación inversa es fácil cómo hacerlo cuando hay varias columnas en Python
fuente
Si tiene ambos tipos de datos numéricos y categóricos en el marco de datos Puede usar: aquí X es mi marco de datos que tiene ambas variables categóricas y numéricas
Nota: Esta técnica es buena si no está interesado en convertirlos nuevamente.
fuente
Usando Neuraxle
Con este método, su codificador de etiquetas podrá ajustarse y transformarse dentro de una tubería de aprendizaje de scikit normal . Simplemente importemos:
El mismo codificador compartido para columnas:
Así es como se aplicará un LabelEncoder compartido a todos los datos para codificarlo:
Resultado:
Diferentes codificadores por columna:
Y así es como se aplicará un primer LabelEncoder independiente a las mascotas, y se compartirá un segundo para el propietario y la ubicación de las columnas. Entonces, para ser precisos, aquí tenemos una combinación de codificadores de etiquetas diferentes y compartidos:
Resultado:
fuente
Utilicé principalmente la respuesta de @Alexander pero tuve que hacer algunos cambios:
Luego, para reutilizar en el futuro, puede guardar la salida en un documento json y cuando lo necesite, leerlo y usar la
.map()
función como lo hice anteriormente.fuente
El problema es la forma de los datos (pd dataframe) que está pasando a la función de ajuste. Tienes que pasar la 1ª lista.
fuente
Aquí estoy leyendo un csv desde la ubicación y, en función, paso la lista de columnas que quiero etiquetar y el marco de datos que quiero aplicar.
fuente
¿Qué tal esto?
No es el más eficiente, sin embargo funciona y es súper simple.
fuente