python - renombrar - Renombrando columnas en pandas
pandas rename one column (28)
DataFrame - df.rename () funcionará.
df.rename(columns = {''Old Name'':''New Name''})
df es el DataFrame que tiene, y el Nombre antiguo es el nombre de la columna que desea cambiar, luego el Nombre nuevo es el nuevo nombre al que cambia. Este método incorporado de DataFrame hace que las cosas sean más fáciles.
Tengo un DataFrame que usa pandas y etiquetas de columna que necesito editar para reemplazar las etiquetas de columna originales
Me gustaría cambiar los nombres de columna en un DataFrame A
donde los nombres de columna originales son:
[''$a'', ''$b'', ''$c'', ''$d'', ''$e'']
a
[''a'', ''b'', ''c'', ''d'', ''e''].
He guardado los nombres de columna editados en una lista, pero no sé cómo reemplazar los nombres de columna.
Nombres de columnas vs nombres de series
Me gustaría explicar un poco lo que sucede detrás de escena.
Los marcos de datos son un conjunto de series.
Las series a su vez son una extensión de un numpy.array
numpy.array
s tiene una propiedad .name
Este es el nombre de la serie. Raras veces los pandas respetan este atributo, pero permanece en algunos lugares y se puede usar para piratear algunos comportamientos de pandas.
Nombrando la lista de columnas
Muchas respuestas aquí hablan de que el atributo df.columns
es una list
cuando en realidad es una Series
. Esto significa que tiene un atributo .name
.
Esto es lo que sucede si decide completar el nombre de las columnas Series
:
df.columns = [''column_one'', ''column_two'']
df.columns.names = [''name of the list of columns'']
df.index.names = [''name of the index'']
name of the list of columns column_one column_two
name of the index
0 4 1
1 5 2
2 6 3
Tenga en cuenta que el nombre del índice siempre aparece una columna más abajo.
Artefactos que perduran
El atributo .name
persiste a veces. Si configura df.columns = [''one'', ''two'']
entonces df.one.name
será ''one''
.
Si configura df.one.name = ''three''
, df.columns
aún le dará [''one'', ''two'']
, y df.one.name
le dará ''three''
PERO
pd.DataFrame(df.one)
devolverá
three
0 1
1 2
2 3
Porque los pandas reutilizan el .name
de la serie ya definida.
Nombres de columnas multi nivel
Pandas tiene formas de hacer nombres de columnas de múltiples capas. No hay tanta magia involucrada, pero quería cubrir esto en mi respuesta también, ya que no veo a nadie retomando esto aquí.
|one |
|one |two |
0 | 4 | 1 |
1 | 5 | 2 |
2 | 6 | 3 |
Esto se puede lograr fácilmente estableciendo columnas en listas, como esta:
df.columns = [[''one'', ''one''], [''one'', ''two'']]
Pandas 0.21+ Respuesta
Ha habido algunas actualizaciones significativas para el cambio de nombre de columna en la versión 0.21.
- El método de
rename
ha agregado el parámetro deaxis
que se puede establecer encolumns
o1
. Esta actualización hace que este método coincida con el resto de la API de pandas. Todavía tiene los parámetros deindex
ycolumns
, pero ya no está obligado a usarlos. - El método
set_axis
con el conjuntoinplace
enFalse
permite cambiar el nombre de todas las etiquetas de índice o columna con una lista.
Ejemplos para Pandas 0.21+
Construir muestra DataFrame:
df = pd.DataFrame({''$a'':[1,2], ''$b'': [3,4],
''$c'':[5,6], ''$d'':[7,8],
''$e'':[9,10]})
$a $b $c $d $e
0 1 3 5 7 9
1 2 4 6 8 10
Usando rename
con axis=''columns''
o axis=1
df.rename({''$a'':''a'', ''$b'':''b'', ''$c'':''c'', ''$d'':''d'', ''$e'':''e''}, axis=''columns'')
o
df.rename({''$a'':''a'', ''$b'':''b'', ''$c'':''c'', ''$d'':''d'', ''$e'':''e''}, axis=1)
Ambos resultan en lo siguiente:
a b c d e
0 1 3 5 7 9
1 2 4 6 8 10
Todavía es posible utilizar la firma del método antiguo:
df.rename(columns={''$a'':''a'', ''$b'':''b'', ''$c'':''c'', ''$d'':''d'', ''$e'':''e''})
La función de rename
también acepta funciones que se aplicarán a cada nombre de columna.
df.rename(lambda x: x[1:], axis=''columns'')
o
df.rename(lambda x: x[1:], axis=1)
Usando set_axis
con una lista e inplace=False
Puede proporcionar una lista al método set_axis
que es igual en longitud al número de columnas (o índice). Actualmente, los inplace
predeterminados en el lugar son True
, pero los valores predeterminados en el inplace
serán False
en futuras versiones.
df.set_axis([''a'', ''b'', ''c'', ''d'', ''e''], axis=''columns'', inplace=False)
o
df.set_axis([''a'', ''b'', ''c'', ''d'', ''e''], axis=1, inplace=False)
¿Por qué no usar df.columns = [''a'', ''b'', ''c'', ''d'', ''e'']
?
No hay nada de malo en asignar columnas directamente de esta manera. Es una solución perfectamente buena.
La ventaja de usar set_axis
es que se puede usar como parte de una cadena de métodos y que devuelve una nueva copia del DataFrame. Sin él, tendría que almacenar sus pasos intermedios de la cadena a otra variable antes de reasignar las columnas.
# new for pandas 0.21+
df.some_method1()
.some_method2()
.set_axis()
.some_method3()
# old way
df1 = df.some_method1()
.some_method2()
df1.columns = columns
df1.some_method3()
Soluciones de una línea o tubería.
Me centraré en dos cosas:
OP establece claramente
He guardado los nombres de columna editados en una lista, pero no sé cómo reemplazar los nombres de columna.
No quiero resolver el problema de cómo reemplazar
''$''
o quitar el primer carácter de cada encabezado de columna. OP ya ha hecho este paso. En su lugar, quiero centrarme en reemplazar el objeto decolumns
existente por uno nuevo, dada una lista de nombres de columnas de reemplazo.df.columns = new
dondenew
es la lista de nuevos nombres de columnas es tan simple como se obtiene. El inconveniente de este enfoque es que requiere editar el atributo decolumns
del marco de datos existente y no se realiza en línea. Mostraré algunas formas de realizar esto mediante la canalización sin editar el marco de datos existente.
Configuración 1
Para centrarme en la necesidad de cambiar el nombre de reemplazar nombres de columna con una lista preexistente, crearé un nuevo df
datos de muestra con nombres de columna iniciales y nombres de columna nuevos no relacionados.
df = pd.DataFrame({''Jack'': [1, 2], ''Mahesh'': [3, 4], ''Xin'': [5, 6]})
new = [''x098'', ''y765'', ''z432'']
df
Jack Mahesh Xin
0 1 3 5
1 2 4 6
Solución 1
pd.DataFrame.rename
Ya se ha dicho que si tuviera un diccionario que asignara los antiguos nombres de columna a nuevos nombres de columna, podría usar pd.DataFrame.rename
.
d = {''Jack'': ''x098'', ''Mahesh'': ''y765'', ''Xin'': ''z432''}
df.rename(columns=d)
x098 y765 z432
0 1 3 5
1 2 4 6
Sin embargo, puede crear fácilmente ese diccionario e incluirlo en la llamada para rename
. Lo siguiente se aprovecha del hecho de que al iterar sobre df
, iteramos sobre cada nombre de columna.
# given just a list of new column names
df.rename(columns=dict(zip(df, new)))
x098 y765 z432
0 1 3 5
1 2 4 6
Esto funciona muy bien si los nombres de sus columnas originales son únicos. Pero si no lo son, entonces esto se rompe.
Configuración 2
columnas no únicas
df = pd.DataFrame(
[[1, 3, 5], [2, 4, 6]],
columns=[''Mahesh'', ''Mahesh'', ''Xin'']
)
new = [''x098'', ''y765'', ''z432'']
df
Mahesh Mahesh Xin
0 1 3 5
1 2 4 6
Solucion 2
pd.concat
usando el argumento keys
Primero, note lo que sucede cuando intentamos usar la solución 1:
df.rename(columns=dict(zip(df, new)))
y765 y765 z432
0 1 3 5
1 2 4 6
No asignamos la new
lista como los nombres de columna. Terminamos repitiendo y765
. En su lugar, podemos usar el argumento de keys
de la función pd.concat
mientras pd.concat
través de las columnas de df
.
pd.concat([c for _, c in df.items()], axis=1, keys=new)
x098 y765 z432
0 1 3 5
1 2 4 6
Solucion 3
Reconstruir. Esto solo debe usarse si tiene un único tipo de dtype
para todas las columnas. De lo contrario, terminará con el object
dtype
para todas las columnas y volver a convertirlas requiere más trabajo de diccionario.
dtype
solo
pd.DataFrame(df.values, df.index, new)
x098 y765 z432
0 1 3 5
1 2 4 6
dtype
mixto
pd.DataFrame(df.values, df.index, new).astype(dict(zip(new, df.dtypes)))
x098 y765 z432
0 1 3 5
1 2 4 6
Solucion 4
Este es un truco de trucos con transpose
y set_index
. pd.DataFrame.set_index
nos permite establecer un índice en línea pero no hay un conjunto de set_columns
correspondientes. Entonces podemos transponer, luego set_index
, y transponer de vuelta. Sin embargo, aquí se aplica la misma advertencia de tipo de dtype
frente a tipo mixto de la solución 3.
dtype
solo
df.T.set_index(np.asarray(new)).T
x098 y765 z432
0 1 3 5
1 2 4 6
dtype
mixto
df.T.set_index(np.asarray(new)).T.astype(dict(zip(new, df.dtypes)))
x098 y765 z432
0 1 3 5
1 2 4 6
Solucion 5
Use una lambda
en pd.DataFrame.rename
que pd.DataFrame.rename
cada elemento de new
En esta solución, pasamos un lambda que toma x
pero luego lo ignora. También toma una y
pero no lo espera. En su lugar, se asigna un iterador como valor predeterminado y luego puedo usarlo para recorrer uno por uno sin tener en cuenta cuál es el valor de x
.
df.rename(columns=lambda x, y=iter(new): next(y))
x098 y765 z432
0 1 3 5
1 2 4 6
Y como me lo indicó la gente en el chat de Sopython , si agrego un *
entre y
, puedo proteger mi variable y
. Aunque, en este contexto, no creo que necesite protección. Todavía vale la pena mencionar.
df.rename(columns=lambda x, *, y=iter(new): next(y))
x098 y765 z432
0 1 3 5
1 2 4 6
Aquí hay una pequeña función ingeniosa que me gusta usar para reducir la escritura:
def rename(data, oldnames, newname):
if type(oldnames) == str: #input can be a string or list of strings
oldnames = [oldnames] #when renaming multiple columns
newname = [newname] #make sure you pass the corresponding list of new names
i = 0
for name in oldnames:
oldvar = [c for c in data.columns if name in c]
if len(oldvar) == 0:
raise ValueError("Sorry, couldn''t find that column in the dataset")
if len(oldvar) > 1: #doesn''t have to be an exact match
print("Found multiple columns that matched " + str(name) + " :")
for c in oldvar:
print(str(oldvar.index(c)) + ": " + str(c))
ind = input(''please enter the index of the column you would like to rename: '')
oldvar = oldvar[int(ind)]
if len(oldvar) == 1:
oldvar = oldvar[0]
data = data.rename(columns = {oldvar : newname[i]})
i += 1
return data
Aquí hay un ejemplo de cómo funciona:
In [2]: df = pd.DataFrame(np.random.randint(0,10,size=(10, 4)), columns=[''col1'',''col2'',''omg'',''idk''])
#first list = existing variables
#second list = new names for those variables
In [3]: df = rename(df, [''col'',''omg''],[''first'',''ohmy''])
Found multiple columns that matched col :
0: col1
1: col2
please enter the index of the column you would like to rename: 0
In [4]: df.columns
Out[5]: Index([''first'', ''col2'', ''ohmy'', ''idk''], dtype=''object'')
Como se documenta en http://pandas.pydata.org/pandas-docs/stable/text.html :
df.columns = df.columns.str.replace(''$'','''')
Creo que este método es útil:
df.rename(columns={"old_column_name1":"new_column_name1", "old_column_name2":"new_column_name2"})
Este método le permite cambiar los nombres de columna individualmente.
El método de df.rename() puede tomar una función, por ejemplo:
In [11]: df.columns
Out[11]: Index([u''$a'', u''$b'', u''$c'', u''$d'', u''$e''], dtype=object)
In [12]: df.rename(columns=lambda x: x[1:], inplace=True)
In [13]: df.columns
Out[13]: Index([u''a'', u''b'', u''c'', u''d'', u''e''], dtype=object)
En caso de que no quiera los nombres de fila df.columns = [''a'', ''b'',index=False]
Otra forma en que podríamos reemplazar las etiquetas de columna originales es eliminando los caracteres no deseados (aquí ''$'') de las etiquetas de columna originales.
Esto se podría haber hecho ejecutando un bucle for en df.columns y agregando las columnas eliminadas a df.columns.
En su lugar, podemos hacer esto de manera ordenada en una sola declaración usando la comprensión de lista como a continuación:
df.columns = [col.strip(''$'') for col in df.columns]
(El método de strip
en Python elimina el carácter dado desde el principio y el final de la cadena).
Otra opción es cambiar el nombre usando una expresión regular:
import pandas as pd
import re
df = pd.DataFrame({''$a'':[1,2], ''$b'':[3,4], ''$c'':[5,6]})
df = df.rename(columns=lambda x: re.sub(''/$'','''',x))
>>> df
a b c
0 1 3 5
1 2 4 6
Podrías usar str.slice
para eso:
df.columns = df.columns.str.slice(1)
Prueba esto. Esto funciona para mi
df.rename(index=str, columns={"$a": "a", "$b": "b", "$c" : "c", "$d" : "d", "$e" : "e"})
Real solo uso simple
df.columns = [''Name1'', ''Name2'', ''Name3''...]
y asignará los nombres de las columnas por el orden en que los pones.
Sé que esta pregunta y respuesta ha sido masticada hasta la muerte. Pero me referí a él como inspiración para uno de los problemas que estaba teniendo. Pude resolverlo utilizando bits y piezas de respuestas diferentes, por lo que proporcioné mi respuesta en caso de que alguien la necesite.
Mi método es genérico, en el que puede agregar delimitadores adicionales al separar los delimiters=
con comas delimiters=
variable y probarlo para el futuro.
Código de trabajo:
import pandas as pd
import re
df = pd.DataFrame({''$a'':[1,2], ''$b'': [3,4],''$c'':[5,6], ''$d'': [7,8], ''$e'': [9,10]})
delimiters = ''$''
matchPattern = ''|''.join(map(re.escape, delimiters))
df.columns = [re.split(matchPattern, i)[1] for i in df.columns ]
Salida:
>>> df
$a $b $c $d $e
0 1 3 5 7 9
1 2 4 6 8 10
>>> df
a b c d e
0 1 3 5 7 9
1 2 4 6 8 10
Si tiene que lidiar con un montón de columnas nombradas por el sistema que está fuera de su control, se me ocurrió el siguiente enfoque que es una combinación de un enfoque general y reemplazos específicos de una sola vez.
Primero creo un diccionario a partir de los nombres de las columnas del marco de datos usando expresiones regulares para eliminar ciertos apéndices de los nombres de las columnas y luego agrego reemplazos específicos al diccionario para nombrar las columnas centrales como se espera más adelante en la base de datos de recepción.
Esto se aplica a la trama de datos de una sola vez.
dict=dict(zip(df.columns,df.columns.str.replace(''(:S$|:C1$|:L$|:D$|/.Serial:L$)'','''')))
dict[''brand_timeseries:C1'']=''BTS''
dict[''respid:L'']=''RespID''
dict[''country:C1'']=''CountryID
dict[''pim1:D'']=''pim_actual''
df.rename(columns=dict, inplace=True)
Si tienes el marco de datos, df.columns vuelca todo en una lista que puedes manipular y luego reasignar a tu marco de datos como los nombres de las columnas ...
columns = df.columns
columns = [row.replace("$","") for row in columns]
df.rename(columns=dict(zip(columns, things)), inplace=True)
df.head() #to validate the output
¿Mejor manera? IDK. Una forma - si.
Una mejor manera de evaluar todas las técnicas principales presentadas en las respuestas a la pregunta es a continuación, utilizando cProfile para medir la memoria y el tiempo de ejecución. @kadee, @kaitlyn y @eumiro tuvieron las funciones con los tiempos de ejecución más rápidos, aunque estas funciones son tan rápidas que estamos comparando el redondeo de .000 y .001 segundos para todas las respuestas. Moraleja: mi respuesta anterior probablemente no sea la "mejor" forma.
import pandas as pd
import cProfile, pstats, re
old_names = [''$a'', ''$b'', ''$c'', ''$d'', ''$e'']
new_names = [''a'', ''b'', ''c'', ''d'', ''e'']
col_dict = {''$a'': ''a'', ''$b'': ''b'',''$c'':''c'',''$d'':''d'',''$e'':''e''}
df = pd.DataFrame({''$a'':[1,2], ''$b'': [10,20],''$c'':[''bleep'',''blorp''],''$d'':[1,2],''$e'':[''texa$'','''']})
df.head()
def eumiro(df,nn):
df.columns = nn
#This direct renaming approach is duplicated in methodology in several other answers:
return df
def lexual1(df):
return df.rename(columns=col_dict)
def lexual2(df,col_dict):
return df.rename(columns=col_dict, inplace=True)
def Panda_Master_Hayden(df):
return df.rename(columns=lambda x: x[1:], inplace=True)
def paulo1(df):
return df.rename(columns=lambda x: x.replace(''$'', ''''))
def paulo2(df):
return df.rename(columns=lambda x: x.replace(''$'', ''''), inplace=True)
def migloo(df,on,nn):
return df.rename(columns=dict(zip(on, nn)), inplace=True)
def kadee(df):
return df.columns.str.replace(''$'','''')
def awo(df):
columns = df.columns
columns = [row.replace("$","") for row in columns]
return df.rename(columns=dict(zip(columns, '''')), inplace=True)
def kaitlyn(df):
df.columns = [col.strip(''$'') for col in df.columns]
return df
print ''eumiro''
cProfile.run(''eumiro(df,new_names)'')
print ''lexual1''
cProfile.run(''lexual1(df)'')
print ''lexual2''
cProfile.run(''lexual2(df,col_dict)'')
print ''andy hayden''
cProfile.run(''Panda_Master_Hayden(df)'')
print ''paulo1''
cProfile.run(''paulo1(df)'')
print ''paulo2''
cProfile.run(''paulo2(df)'')
print ''migloo''
cProfile.run(''migloo(df,old_names,new_names)'')
print ''kadee''
cProfile.run(''kadee(df)'')
print ''awo''
cProfile.run(''awo(df)'')
print ''kaitlyn''
cProfile.run(''kaitlyn(df)'')
Solo .columns
atributo .columns
:
>>> df = pd.DataFrame({''$a'':[1,2], ''$b'': [10,20]})
>>> df.columns = [''a'', ''b'']
>>> df
a b
0 1 10
1 2 20
Tenga en cuenta que estos enfoques no funcionan para un MultiIndex. Para un MultiIndex, necesita hacer algo como lo siguiente:
>>> df = pd.DataFrame({(''$a'',''$x''):[1,2], (''$b'',''$y''): [3,4], (''e'',''f''):[5,6]})
>>> df
$a $b e
$x $y f
0 1 3 5
1 2 4 6
>>> rename = {(''$a'',''$x''):(''a'',''x''), (''$b'',''$y''):(''b'',''y'')}
>>> df.columns = pandas.MultiIndex.from_tuples([
rename.get(item, item) for item in df.columns.tolist()])
>>> df
a b e
x y f
0 1 3 5
1 2 4 6
Use la función df.rename()
y refiera las columnas a renombrar. No todas las columnas tienen que ser renombradas:
df = df.rename(columns={''oldName1'': ''newName1'', ''oldName2'': ''newName2''})
# Or rename the existing DataFrame (rather than creating a copy)
df.rename(columns={''oldName1'': ''newName1'', ''oldName2'': ''newName2''}, inplace=True)
Ya que solo desea eliminar el signo $ en todos los nombres de columna, simplemente puede hacer:
df = df.rename(columns=lambda x: x.replace(''$'', ''''))
O
df.rename(columns=lambda x: x.replace(''$'', ''''), inplace=True)
Cambiar el nombre de las columnas del marco de datos y reemplazar el formato.
import pandas as pd
data = {''year'':[2015,2011,2007,2003,1999,1996,1992,1987,1983,1979,1975],
''team'':[''Australia'',''India'',''Australia'',''Australia'',''Australia'',''Sri Lanka'',''Pakistan'',''Australia'',''India'',''West Indies'',''West Indies''],
}
df = pd.DataFrame(data)
#Rename Columns
df.rename(columns={''year'':''Years of Win'',''team'':''Winning Team''}, inplace=True)
#Replace format
df = df.columns.str.replace('' '', ''_'')
Renaming columns while reading the Dataframe:
>>> df = pd.DataFrame({''$a'': [1], ''$b'': [1], ''$c'': [1]}).rename(columns =
{''$a'' : ''a'',''$b'':''b'',''$c'':''c''})
Out[1]:
a b c
0 1 1 1
df = df.rename(columns=lambda n: n.replace(''$'', ''''))
Es una forma funcional de resolver esto.
df = pd.DataFrame({''$a'': [1], ''$b'': [1], ''$c'': [1], ''$d'': [1], ''$e'': [1]})
Si su nueva lista de columnas está en el mismo orden que las columnas existentes, la asignación es simple:
new_cols = [''a'', ''b'', ''c'', ''d'', ''e'']
df.columns = new_cols
>>> df
a b c d e
0 1 1 1 1 1
Si tenía un diccionario codificado en antiguos nombres de columna a nuevos nombres de columna, podría hacer lo siguiente:
d = {''$a'': ''a'', ''$b'': ''b'', ''$c'': ''c'', ''$d'': ''d'', ''$e'': ''e''}
df.columns = df.columns.map(lambda col: d[col]) # Or `.map(d.get)` as pointed out by @PiRSquared.
>>> df
a b c d e
0 1 1 1 1 1
Si no tiene una lista o una asignación de diccionario, puede quitar el símbolo de $
inicial a través de una lista de comprensión:
df.columns = [col[1:] if col[0] == ''$'' else col for col in df]
df.columns = [''a'', ''b'', ''c'', ''d'', ''e'']
Reemplazará los nombres existentes con los nombres que proporcione, en el orden que proporcione.
df.rename(index=str,columns={''A'':''a'',''B'':''b''})
old_names = [''$a'', ''$b'', ''$c'', ''$d'', ''$e'']
new_names = [''a'', ''b'', ''c'', ''d'', ''e'']
df.rename(columns=dict(zip(old_names, new_names)), inplace=True)
De esta manera puedes editar manualmente los new_names
como desees. Funciona muy bien cuando necesita cambiar el nombre de solo unas pocas columnas para corregir errores de ortografía, acentos, eliminar caracteres especiales, etc.