valeur - supprimer colonne dataframe python




Renommer des colonnes dans les pandas (16)

DataFrame - df.rename () fonctionnera.

df.rename(columns = {'Old Name':'New Name'})

df est le DataFrame que vous avez, et l' ancien nom est le nom de la colonne que vous voulez changer, puis le nouveau nom est le nouveau nom que vous changez. Cette méthode intégrée DataFrame rend les choses très faciles.

J'ai un DataFrame en utilisant des pandas et des étiquettes de colonnes que j'ai besoin de modifier pour remplacer les étiquettes de colonnes 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 colonne édités l'ont stocké dans une liste, mais je ne sais pas comment remplacer les noms de colonne.


Noms de colonnes vs noms de séries

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

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

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

numpy.array s possède une propriété .name

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

Nommer la liste des colonnes

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

C'est ce qui se passe si vous décidez de renseigner le nom des colonnes.

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 est toujours inférieur d'une colonne.

Des artefacts qui persistent

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

Si vous définissez df.one.name = 'three' alors df.columns vous donnera toujours ['one', 'two'] , et df.one.name vous donnera 'three'

MAIS

pd.DataFrame(df.one) retournera

    three
0       1
1       2
2       3

Parce que les pandas réutilise le nom de la série déjà définie.

Noms de colonnes multi-niveaux

Pandas a des façons de faire des noms de colonnes multi-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 à des listes, comme ceci:

df.columns = [['one', 'one'], ['one', 'two']]

Une ligne ou des solutions de pipeline

Je vais me concentrer sur deux choses:

  1. OP déclare clairement

    J'ai les noms de colonne édités l'ont stocké dans une liste, mais je ne sais pas comment remplacer les noms de colonne.

    Je ne veux pas résoudre le problème de savoir comment remplacer '$' ou supprimer le premier caractère de chaque en-tête de colonne. OP a déjà fait cette étape. Au lieu de cela, je veux me concentrer sur le remplacement de l'objet des columns existantes par un nouveau en donnant une liste de noms de colonnes de remplacement.

  2. df.columns = newnew est la liste des nouveaux noms de colonnes est aussi simple que possible. L'inconvénient de cette approche est qu'elle nécessite de modifier l'attribut de columns de données existantes et qu'elle n'est pas faite en ligne. Je vais montrer quelques façons d'effectuer ceci en pipelining sans éditer l'image existante.

Configuration 1
Pour mettre l'accent sur la nécessité de renommer les noms de colonne avec une liste préexistante, je vais créer un nouvel exemple de fichier de données df avec les noms de colonnes initiaux et les nouveaux noms de colonnes non apparentés.

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

Solution 1
pd.DataFrame.rename

Il a déjà été dit que si vous aviez un dictionnaire mappant les anciens noms de colonne avec de nouveaux noms de colonnes, vous pourriez utiliser 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

Cependant, vous pouvez facilement créer ce dictionnaire et l'inclure dans l'appel à rename . Ce qui suit tire parti du fait que lors de l'itération sur df , nous parcourons chaque nom de colonne.

# 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

Cela fonctionne très bien si vos noms de colonnes d'origine sont uniques. Mais s'ils ne le sont pas, alors cela tombe en panne.

Configuration 2
colonnes non uniques

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

Solution 2
pd.concat utilisant l'argument keys

Tout d'abord, remarquez ce qui se passe lorsque nous essayons d'utiliser la solution 1:

df.rename(columns=dict(zip(df, new)))

   y765  y765  z432
0     1     3     5
1     2     4     6

Nous n'avons pas mappé la new liste en tant que noms de colonnes. Nous avons fini par répéter y765 . Au lieu de cela, nous pouvons utiliser l'argument keys de la fonction pd.concat lors de l'itération à travers les colonnes 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

Solution 3
Reconstruire. Cela ne devrait être utilisé que si vous avez un seul dtype pour toutes les colonnes. Sinon, vous finirez avec l' object dtype pour toutes les colonnes et leur conversion nécessite plus de travail de dictionnaire.

dtype unique

pd.DataFrame(df.values, df.index, new)

   x098  y765  z432
0     1     3     5
1     2     4     6

dtype mixte

pd.DataFrame(df.values, df.index, new).astype(dict(zip(new, df.dtypes)))

   x098  y765  z432
0     1     3     5
1     2     4     6

Solution 4
C'est une astuce gimmicky avec transpose et set_index . pd.DataFrame.set_index nous permet de définir un index en ligne mais il n'y a pas set_columns correspondant. Nous pouvons donc transposer, puis set_index et transposer. Cependant, le même type de dtype que le type mixte dtype de la solution 3 s'applique ici.

dtype unique

df.T.set_index(np.asarray(new)).T

   x098  y765  z432
0     1     3     5
1     2     4     6

dtype mixte

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

Solution 5
Utilisez un lambda dans pd.DataFrame.rename qui parcourt chaque élément de la new
Dans cette solution, nous passons un lambda qui prend x mais l'ignore ensuite. Cela prend aussi un y mais ne l'attend pas. Au lieu de cela, un itérateur est donné en tant que valeur par défaut et je peux ensuite l'utiliser pour parcourir un par un sans tenir compte de la valeur de x .

df.rename(columns=lambda x, y=iter(new): next(y))

   x098  y765  z432
0     1     3     5
1     2     4     6

Et comme me l'ont fait remarquer les gens de sopython , si j'ajoute un * entre x et y , je peux protéger ma variable y . Bien que, dans ce contexte, je ne crois pas qu'il a besoin de protection. Cela vaut toujours la peine d'être mentionné.

df.rename(columns=lambda x, *, y=iter(new): next(y))

   x098  y765  z432
0     1     3     5
1     2     4     6

Au cas où vous ne voulez pas les noms de ligne df.columns = ['a', 'b',index=False]


Essaye ça. Ça marche pour moi

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

Je pense que cette méthode est utile:

df.rename(columns={"old_column_name1":"new_column_name1", "old_column_name2":"new_column_name2"})

Cette méthode vous permet de modifier les noms de colonne individuellement.


La méthode de df.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)

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

>>> 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

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. Une façon - oui.

Une meilleure façon d'évaluer toutes les techniques principales mises en avant 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, & @eumiro ont eu les fonctions avec les temps d'exécution les plus rapides - bien que ces fonctions soient si rapides, 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.

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)')

Si vous devez gérer des tas de colonnes nommées par le système fournissant hors de votre contrôle, je suis venu avec l'approche suivante qui est une combinaison d'une approche générale et des remplacements spécifiques en une seule fois.

Je crée d'abord un dictionnaire à partir des noms de colonnes de données à l'aide d'expressions regex afin de supprimer certaines annexes de noms de colonnes, puis j'ajoute des remplacements spécifiques au dictionnaire pour nommer les colonnes principales comme attendu plus tard dans la base de données réceptrice.

Ceci est ensuite appliqué à l'ensemble de données en une 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)

Utilisez la fonction df.rename() et reportez les colonnes à renommer. Toutes les colonnes ne doivent pas être renommées:

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)

Voici une petite fonction utile 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 comment cela fonctionne:

In [2]: df = pd.DataFrame(np.random.randint(0,10,size=(10, 4)), columns=['col1','col2','omg','idk'])

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')

Vraiment simple, utilisez simplement

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

et il va attribuer les noms de colonnes par l'ordre que vous les mettez


.columns le .columns attribut .columns :

>>> df = pd.DataFrame({'$a':[1,2], '$b': [10,20]})
>>> df.columns = ['a', 'b']
>>> df
   a   b
0  1  10
1  2  20

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 avez défini un dictionnaire avec les anciens noms de colonne sur de nouveaux noms de colonnes, vous pouvez effectuer les opérations suivantes:

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

df.columns = [col[1:] if col[0] == '$' else col for col in df]

df.columns = ['a', 'b', 'c', 'd', 'e']

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

Vous pouvez également les affecter par index comme ceci:

df.columns.values[2] = 'c'    #renames the 2nd column to 'c' (in position #3)






rename