J'ai un DataFrame utilisant des pandas et des étiquettes de colonne que je dois modifier pour remplacer les étiquettes de colonne d'origine.

Je voudrais changer les noms de colonnes dans un DataFrame A où les noms de colonnes d'origine sont:

['$a', '$b', '$c', '$d', '$e'] 

À

['a', 'b', 'c', 'd', 'e'].

J'ai les noms de colonnes modifiés stockés dans une liste, mais je ne sais pas comment remplacer les noms de colonnes.

1699
user1504276 5 juil. 2012 à 18:21

20 réponses

Meilleure réponse

Attribuez-le simplement à l'attribut .columns:

>>> df = pd.DataFrame({'$a':[1,2], '$b': [10,20]})
>>> df.columns = ['a', 'b']
>>> df
   a   b
0  1  10
1  2  20
1718
eumiro 5 juil. 2012 à 14:23

Une autre option consiste à renommer à l'aide d'une expression régulière:

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
8
sbha 7 juil. 2018 à 02:07

En supposant que vous pouvez utiliser une expression régulière. Cette solution supprime le besoin d'encodage manuel à l'aide d'expressions régulières

import pandas as pd
import re

srch=re.compile(r"\w+")

data=pd.read_csv("CSV_FILE.csv")
cols=data.columns
new_cols=list(map(lambda v:v.group(),(list(map(srch.search,cols)))))
data.columns=new_cols
2
Kaustubh J 12 avril 2019 à 03:34
df.rename(index=str,columns={'A':'a','B':'b'})

https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.rename.html

15
Yog 29 août 2018 à 13:35

Pandas 0.21+ Réponse

Il y a eu quelques mises à jour importantes pour renommer les colonnes dans la version 0.21.

  • Le {{ La méthode X0}} a ajouté le paramètre axis qui peut être défini sur columns ou 1. Cette mise à jour rend cette méthode compatible avec le reste de l'API pandas. Il a toujours les paramètres index et columns mais vous n'êtes plus obligé de les utiliser.
  • Le {{X0} } La méthode avec le inplace défini sur False vous permet de renommer toutes les étiquettes d'index ou de colonne avec une liste.

Exemples pour Pandas 0.21+

Construisez un exemple de 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

Utilisation de rename avec axis='columns' ou axis=1

df.rename({'$a':'a', '$b':'b', '$c':'c', '$d':'d', '$e':'e'}, axis='columns')

Ou

df.rename({'$a':'a', '$b':'b', '$c':'c', '$d':'d', '$e':'e'}, axis=1)

Les deux aboutissent aux résultats suivants:

   a  b  c  d   e
0  1  3  5  7   9
1  2  4  6  8  10

Il est toujours possible d'utiliser l'ancienne signature de méthode:

df.rename(columns={'$a':'a', '$b':'b', '$c':'c', '$d':'d', '$e':'e'})

La fonction rename accepte également les fonctions qui seront appliquées à chaque nom de colonne.

df.rename(lambda x: x[1:], axis='columns')

Ou

df.rename(lambda x: x[1:], axis=1)

Utiliser set_axis avec une liste et inplace=False

Vous pouvez fournir à la méthode set_axis une liste de longueur égale au nombre de colonnes (ou index). Actuellement, inplace par défaut est True, mais inplace sera réglé par défaut sur False dans les futures versions.

df.set_axis(['a', 'b', 'c', 'd', 'e'], axis='columns', inplace=False)

Ou

df.set_axis(['a', 'b', 'c', 'd', 'e'], axis=1, inplace=False)

Pourquoi ne pas utiliser df.columns = ['a', 'b', 'c', 'd', 'e']?

Il n'y a rien de mal à affecter directement des colonnes comme celle-ci. C'est une très bonne solution.

L'avantage d'utiliser set_axis est qu'il peut être utilisé dans le cadre d'une chaîne de méthodes et qu'il renvoie une nouvelle copie du DataFrame. Sans cela, vous devrez stocker vos étapes intermédiaires de la chaîne dans une autre variable avant de réaffecter les colonnes.

# 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()
162
JohnE 17 nov. 2017 à 19:31

Si vous avez le dataframe, df.columns vide tout dans une liste que vous pouvez manipuler puis réaffecter dans votre dataframe en tant que noms de colonnes ...

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

Meilleur moyen? IDK. Un moyen - oui.

Une meilleure façon d'évaluer toutes les principales techniques proposées dans les réponses à la question est ci-dessous en utilisant cProfile pour mesurer la mémoire et le temps d'exécution. @kadee, @kaitlyn et @eumiro avaient les fonctions avec les temps d'exécution les plus rapides - bien que ces fonctions soient si rapides que nous comparons l'arrondi de .000 et .001 secondes pour toutes les réponses. Morale: ma réponse ci-dessus n'est probablement pas la «meilleure» façon.

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)')
17
andrewwowens 7 sept. 2016 à 02:24
df = pd.DataFrame({'$a': [1], '$b': [1], '$c': [1], '$d': [1], '$e': [1]})

Si votre nouvelle liste de colonnes est dans le même ordre que les colonnes existantes, l'affectation est 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 vous aviez un dictionnaire composé d'anciens noms de colonne pour de nouveaux noms de colonne, vous pouvez procéder comme suit:

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 vous n'avez pas de liste ou de mappage de dictionnaire, vous pouvez supprimer le premier symbole $ via une compréhension de liste:

df.columns = [col[1:] if col[0] == '$' else col for col in df]
17
Alexander 13 sept. 2017 à 12:24

Je sais que cette question et réponse a été mâchée à mort. Mais je m'en suis référé à l'inspiration pour l'un des problèmes que j'avais. J'ai pu le résoudre en utilisant des morceaux de différentes réponses, fournissant ainsi ma réponse au cas où quelqu'un en aurait besoin.

Ma méthode est générique dans laquelle vous pouvez ajouter des délimiteurs supplémentaires en séparant la variable delimiters= par une virgule et en la rendant pérenne.

Code de travail:

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 ]

Sortie:

>>> 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
9
Anil_M 4 août 2016 à 20:26

Vous pouvez utiliser str.slice pour cela:

df.columns = df.columns.str.slice(1)
10
Anton Protopopov 28 janv. 2016 à 17:31

La méthode rename peut prendre une fonction , par exemple:

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)
383
smci 20 oct. 2019 à 22:06
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 cette façon, vous pouvez modifier manuellement le new_names comme vous le souhaitez. Fonctionne très bien lorsque vous devez renommer seulement quelques colonnes pour corriger les fautes d'orthographe, les accents, supprimer les caractères spéciaux, etc.

59
migloo 21 mai 2015 à 17:54

Si vous devez gérer des charges de colonnes nommées par le système fournisseur hors de votre contrôle, j'ai trouvé l'approche suivante qui est une combinaison d'une approche générale et de remplacements spécifiques en une seule fois.

Créez d'abord un dictionnaire à partir des noms de colonnes de la trame de données à l'aide d'expressions regex afin de jeter certaines annexes de noms de colonnes, puis ajoutez des remplacements spécifiques au dictionnaire pour nommer les colonnes principales comme prévu plus tard dans la base de données réceptrice.

Ceci est ensuite appliqué à la trame de données en une seule fois.

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)
6
Chris A 5 juil. 2019 à 11:46

Voici une petite fonction astucieuse que j'aime utiliser pour réduire la frappe:

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   

Voici un exemple de son fonctionnement:

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')
4
seeiespi 18 mai 2018 à 23:36

Notez que ces approches ne fonctionnent pas pour un MultiIndex. Pour un MultiIndex, vous devez faire quelque chose comme ceci:

>>> 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
8
oxer 29 août 2016 à 21:27

Une autre façon de remplacer les étiquettes de colonne d'origine est de supprimer les caractères indésirables (ici «$») des étiquettes de colonne d'origine.

Cela aurait pu être fait en exécutant une boucle for sur df.columns et en ajoutant les colonnes supprimées à df.columns.

Au lieu de cela, nous pouvons le faire proprement dans une seule déclaration en utilisant la compréhension de liste comme ci-dessous:

df.columns = [col.strip('$') for col in df.columns]

(La méthode strip en Python supprime le caractère donné du début et de la fin de la chaîne.)

13
piet.t 5 juil. 2017 à 13:19

Noms des colonnes et noms des séries

Je voudrais expliquer un peu ce qui se passe dans les coulisses.

Les trames de données sont un ensemble de séries.

Les séries sont à leur tour une extension d'un numpy.array

Les numpy.array ont une propriété .name

C'est le nom de la série. Il est rare que les pandas respectent cet attribut, mais il persiste par endroits et peut être utilisé pour pirater certains comportements de pandas.

Nommer la liste des colonnes

Beaucoup de réponses ici parlent de l'attribut df.columns étant un list alors qu'en fait c'est un Series. Cela signifie qu'il a un attribut .name.

Voici ce qui se passe si vous décidez de renseigner le nom des colonnes 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

Notez que le nom de l'index vient toujours une colonne plus bas.

Des artefacts qui persistent

L'attribut .name persiste parfois. Si vous définissez df.columns = ['one', 'two'], le df.one.name sera 'one'.

Si vous définissez df.one.name = 'three', df.columns vous donnera quand même ['one', 'two'] et df.one.name vous donnera 'three'

MAIS

pd.DataFrame(df.one) reviendra

    three
0       1
1       2
2       3

Parce que les pandas réutilisent le .name du Series déjà défini.

Noms de colonnes à plusieurs niveaux

Pandas a des façons de faire des noms de colonnes à plusieurs couches. Il n'y a pas tellement de magie en jeu, mais je voulais aussi couvrir cela dans ma réponse, car je ne vois personne en parler ici.

    |one            |
    |one      |two  |
0   |  4      |  1  |
1   |  5      |  2  |
2   |  6      |  3  |

Ceci est facilement réalisable en définissant des colonnes sur des listes, comme ceci:

df.columns = [['one', 'one'], ['one', 'two']]
33
firelynx 29 sept. 2016 à 12:30

Très simple à utiliser

df.columns = ['Name1', 'Name2', 'Name3'...]

Et il attribuera les noms des colonnes par l'ordre dans lequel vous les avez mis

12
Thodoris P 29 nov. 2015 à 19:22
df.columns = ['a', 'b', 'c', 'd', 'e']

Il remplacera les noms existants par les noms que vous fournissez, dans l'ordre que vous fournissez.

75
Mike_K 12 oct. 2018 à 05:45

Tel que documenté dans http://pandas.pydata.org/pandas-docs/stable/text.html:

df.columns = df.columns.str.replace('$','')
172
kadee 30 mai 2015 à 13:24

Étant donné que vous souhaitez uniquement supprimer le signe $ dans tous les noms de colonne, vous pouvez simplement faire:

df = df.rename(columns=lambda x: x.replace('$', ''))

OU

df.rename(columns=lambda x: x.replace('$', ''), inplace=True)
130
paulo.filip3 26 mars 2014 à 10:20