Invertir la encoding ‘one-hot’ en Pandas

Declaración del problema Quiero ir desde este dataframe que es básicamente un codificado en caliente.

In [2]: pd.DataFrame({"monkey":[0,1,0],"rabbit":[1,0,0],"fox":[0,0,1]}) Out[2]: fox monkey rabbit 0 0 0 1 1 0 1 0 2 1 0 0 3 0 0 0 4 0 0 0 

A este que está ‘inverso’ codificado en caliente.

  In [3]: pd.DataFrame({"animal":["monkey","rabbit","fox"]}) Out[3]: animal 0 monkey 1 rabbit 2 fox 

Me imagino que hay algún tipo de uso inteligente de aplicar o zip para hacer cosas delgadas, pero no estoy seguro de cómo … ¿Puede alguien ayudarme?

No he tenido mucho éxito con la indexación, etc., para tratar de resolver este problema.

Yo usaría aplicar para decodificar las columnas:

 In [2]: animals = pd.DataFrame({"monkey":[0,1,0,0,0],"rabbit":[1,0,0,0,0],"fox":[0,0,1,0,0]}) In [3]: def get_animal(row): ...: for c in animals.columns: ...: if row[c]==1: ...: return c In [4]: animals.apply(get_animal, axis=1) Out[4]: 0 rabbit 1 monkey 2 fox 3 None 4 None dtype: object 

ACTUALIZACIÓN: creo que ayhan tiene razón y debería ser:

 df.idxmax(axis=1) 

Manifestación:

 In [40]: s = pd.Series(['dog', 'cat', 'dog', 'bird', 'fox', 'dog']) In [41]: s Out[41]: 0 dog 1 cat 2 dog 3 bird 4 fox 5 dog dtype: object In [42]: pd.get_dummies(s) Out[42]: bird cat dog fox 0 0.0 0.0 1.0 0.0 1 0.0 1.0 0.0 0.0 2 0.0 0.0 1.0 0.0 3 1.0 0.0 0.0 0.0 4 0.0 0.0 0.0 1.0 5 0.0 0.0 1.0 0.0 In [43]: pd.get_dummies(s).idxmax(1) Out[43]: 0 dog 1 cat 2 dog 3 bird 4 fox 5 dog dtype: object 

Respuesta VIEJA: (muy probablemente, respuesta incorrecta)

prueba esto:

 In [504]: df.idxmax().reset_index().rename(columns={'index':'animal', 0:'idx'}) Out[504]: animal idx 0 fox 2 1 monkey 1 2 rabbit 0 

datos:

 In [505]: df Out[505]: fox monkey rabbit 0 0 0 1 1 0 1 0 2 1 0 0 3 0 0 0 4 0 0 0 

Prueba esto:

 df = pd.DataFrame({"monkey":[0,1,0,1,0],"rabbit":[1,0,0,0,0],"fox":[0,0,1,0,0], "cat":[0,0,0,0,1]}) df cat fox monkey rabbit 0 0 0 0 1 1 0 0 1 0 2 0 1 0 0 3 0 0 1 0 4 1 0 0 0 pd.DataFrame([x for x in np.where(df ==1, df.columns,'').flatten().tolist() if len(x) >0],columns= (["animal"]) ) animal 0 rabbit 1 monkey 2 fox 3 monkey 4 cat 

Lo haría:

 cols = df.columns.to_series().values pd.DataFrame(np.repeat(cols[None, :], len(df), 0)[df.astype(bool).values], df.index[df.any(1)]) 

introduzca la descripción de la imagen aquí


Sincronización

El método de MaxU tiene ventaja para grandes marcos de datos

df pequeño 5 x 3

introduzca la descripción de la imagen aquí

df grande 1000000 x 52

introduzca la descripción de la imagen aquí

Esto funciona con tags únicas y múltiples.

Podemos utilizar la indexación avanzada para abordar este problema. Aquí está el enlace.

 import pandas as pd df = pd.DataFrame({"monkey":[1,1,0,1,0],"rabbit":[1,1,1,1,0],\ "fox":[1,0,1,0,0], "cat":[0,0,0,0,1]}) df['tags']='' # to create an empty column for col_name in df.columns: df.ix[df[col_name]==1,'tags']= df['tags']+' '+col_name print df 

Y el resultado es:

  cat fox monkey rabbit tags 0 0 1 1 1 fox monkey rabbit 1 0 0 1 1 monkey rabbit 2 0 1 0 1 fox rabbit 3 0 0 1 1 monkey rabbit 4 1 0 0 0 cat 

Explicación: iteramos sobre las columnas en el dataframe.

 df.ix[selection criteria, columns to write value] = value df.ix[df[col_name]==1,'tags']= df['tags']+' '+col_name 

La línea anterior básicamente encuentra todos los lugares donde df [nombre_col] == 1, selecciona las ‘tags’ de la columna y lo configura en el valor RHS que es df [‘tags’] + ” + nombre_col

Nota: .ix ha quedado en desuso desde Pandas v0.20. En su lugar, debe utilizar .loc o .iloc , según corresponda.