¿Cómo reemplazar un valor en un dataframe de pandas con un nombre de columna basado en una condición?

Tengo un dataframe que se parece a esto:

introduzca la descripción de la imagen aquí

Quiero reemplazar todos los 1 en el rango A: D con el nombre de la columna, para que el resultado final se asemeje:

introduzca la descripción de la imagen aquí

¿Cómo puedo hacer eso?

Puedes recrear mi dataframe con esto:

dfz = pd.DataFrame({'A' : [1,0,0,1,0,0], 'B' : [1,0,0,1,0,1], 'C' : [1,0,0,1,3,1], 'D' : [1,0,0,1,0,0], 'E' : [22.0,15.0,None,10.,None,557.0]}) 

Una forma podría ser usar replace y pasar las tags de una columna de mapeo en serie a los valores (esas mismas tags en este caso):

 >>> dfz.loc[:, 'A':'D'].replace(1, pd.Series(dfz.columns, dfz.columns)) ABCD 0 ABCD 1 0 0 0 0 2 0 0 0 0 3 ABCD 4 0 0 3 0 5 0 BC 0 

Para que el cambio sea permanente, asignaría el DataFrame devuelto a dfz.loc[:, 'A':'D'] .

Dejando de lado las soluciones, es útil tener en cuenta que puede perder muchos beneficios de rendimiento cuando mezcla tipos numéricos y de cadena en las columnas, ya que se obliga a los pandas a usar el tipo de “objeto” genérico para mantener los valores.

Prefiero una solución muy elegante de @ajcr.

En caso de que tenga nombres de columna que no pueda usar fácilmente para cortarlos, aquí está mi solución:

 dfz.ix[:, dfz.filter(regex=r'(A|B|C|D)').columns.tolist()] = ( dfz[dfz!=1].ix[:,dfz.filter(regex=r'(A|B|C|D)').columns.tolist()] .apply(lambda x: x.fillna(x.name)) ) 

Salida:

 In [207]: dfz Out[207]: ABCDE 0 ABCD 22.0 1 0 0 0 0 15.0 2 0 0 0 0 NaN 3 ABCD 10.0 4 0 0 3 0 NaN 5 0 BC 0 557.0 

Tal vez no sea tan elegante pero … simplemente recorre columnas y reemplaza:

 for i in dfz[['A','B','C','D']].columns: dfz[i].replace(1,i,inplace=True)