with - python rename columns in a dataframe




Rinominare le colonne in panda (19)

Ho un DataFrame che utilizza etichette panda e colonne che devo modificare per sostituire le etichette delle colonne originali.

Mi piacerebbe cambiare i nomi delle colonne in un DataFrame A cui i nomi delle colonne originali sono:

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

a

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

Ho i nomi delle colonne modificati memorizzati in un elenco, ma non so come sostituire i nomi delle colonne.


DataFrame - df.rename () funzionerà.

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

df è il DataFrame che hai, e il Vecchio Nome è il nome della colonna che vuoi cambiare, quindi il Nuovo Nome è il nuovo nome che cambi. Questo metodo integrato DataFrame rende le cose molto più semplici.


Nomi di colonna vs nomi di serie

Mi piacerebbe spiegare un po 'cosa succede dietro le quinte.

I dataframes sono un insieme di serie.

Le serie a loro volta sono un'estensione di un numpy.array

numpy.array ha una proprietà .name

Questo è il nome della serie. È raro che i panda rispettino questo attributo, ma si attarda nei luoghi e può essere utilizzato per violare alcuni comportamenti dei panda.

Denominare l'elenco di colonne

Un sacco di risposte qui parla dell'attributo df.columns come list quando in realtà si tratta di una Series . Questo significa che ha un attributo .name .

Questo è ciò che accade se decidi di inserire il nome delle colonne 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

Si noti che il nome dell'indice viene sempre inferiore di una colonna.

Manufatti che indugiano

L'attributo .name attarda a volte. Se imposti df.columns = ['one', 'two'] allora df.one.name sarà 'one' .

Se imposti df.one.name = 'three' allora df.columns ti darà ancora ['one', 'two'] , e df.one.name ti darà 'three'

MA

pd.DataFrame(df.one) restituirà

    three
0       1
1       2
2       3

Perché i panda riutilizzano il .name della serie già definita.

Nomi di colonne a più livelli

Panda ha modi di fare nomi di colonne a più livelli. Non c'è molta magia coinvolta, ma volevo coprire anche questa nella mia risposta dato che non vedo nessuno raccoglierlo qui.

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

Questo è facilmente ottenibile impostando le colonne sugli elenchi, in questo modo:

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

Una linea o soluzioni Pipeline

Mi concentrerò su due cose:

  1. OP afferma chiaramente

    Ho i nomi delle colonne modificati memorizzati in un elenco, ma non so come sostituire i nomi delle colonne.

    Non voglio risolvere il problema di come sostituire '$' o rimuovere il primo carattere da ogni intestazione di colonna. OP ha già fatto questo passo. Invece voglio concentrarmi sulla sostituzione dell'oggetto delle columns esistenti con uno nuovo dato un elenco di nomi di colonne di sostituzione.

  2. df.columns = new where new è l'elenco dei nuovi nomi di colonne è semplice come si ottiene. Lo svantaggio di questo approccio è che richiede la modifica dell'attributo delle columns del dataframe esistente e non viene eseguito in linea. Mostrerò alcuni modi per eseguire questo tramite pipelining senza modificare il dataframe esistente.

Installazione 1
Per concentrarsi sulla necessità di rinominare i nomi delle colonne sostituiti con un elenco preesistente, creerò un nuovo esempio df dataframe con i nomi iniziali delle colonne e i nomi delle nuove colonne non correlate.

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

Soluzione 1
pd.DataFrame.rename

È stato già detto che se si avesse un dizionario che mappava i vecchi nomi di colonne in nomi di nuove colonne, si poteva usare 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

Tuttavia, puoi facilmente creare quel dizionario e includerlo nella chiamata da rename . Quanto segue si avvantaggia del fatto che durante l'iterazione su df , iteriamo su ogni nome di colonna.

# 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

Funziona alla grande se i nomi delle colonne originali sono unici. Ma se non lo sono, allora questo si rompe.

Installazione 2
colonne non univoche

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

Soluzione 2
pd.concat usando l'argomento keys

Innanzitutto, osserva cosa succede quando tentiamo di utilizzare la soluzione 1:

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

   y765  y765  z432
0     1     3     5
1     2     4     6

Non abbiamo mappato il new elenco come nomi di colonne. Abbiamo finito per ripetere y765 . Invece, possiamo usare l'argomento keys della funzione pd.concat mentre si scorre attraverso le colonne di df .

pd.concat([c for _, c in df.items()], axis=1, keys=new) 

   x098  y765  z432
0     1     3     5
1     2     4     6

Soluzione 3
Ricostruire. Questo dovrebbe essere usato solo se hai un singolo dtype per tutte le colonne. Altrimenti, finirai con dtype object dtype per tutte le colonne e la conversione indietro richiederà più lavoro sul dizionario.

Singolo dtype

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

   x098  y765  z432
0     1     3     5
1     2     4     6

dtype misto

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

   x098  y765  z432
0     1     3     5
1     2     4     6

Soluzione 4
Questo è un trucco ingannevole con transpose e set_index . pd.DataFrame.set_index ci consente di impostare un indice in linea ma non ci sono set_columns corrispondenti. Quindi possiamo trasporre, quindi set_index e trasporre indietro. Tuttavia, qui si applica lo stesso dtype singolo contro il dtype dtype misto della soluzione 3.

Singolo dtype

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

   x098  y765  z432
0     1     3     5
1     2     4     6

dtype misto

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

Soluzione 5
Utilizzare un lambda in pd.DataFrame.rename che pd.DataFrame.rename ciclicamente da ogni elemento di new
In questa soluzione, passiamo un lambda che prende x ma poi lo ignora. Ci vuole anche un y ma non se lo aspetta. Invece, un iteratore viene dato come valore predefinito e posso quindi usarlo per scorrere uno alla volta senza considerare il valore di x .

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

   x098  y765  z432
0     1     3     5
1     2     4     6

E come ho fatto notare dalla gente in chat di sopython , se aggiungo un * tra y , posso proteggere la mia variabile y . Però, in questo contesto, non credo che abbia bisogno di protezione. Vale ancora la pena menzionarlo.

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

   x098  y765  z432
0     1     3     5
1     2     4     6

Basta assegnarlo all'attributo .columns :

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

Dal momento che vuoi solo rimuovere il $ sign in tutti i nomi delle colonne, puoi semplicemente fare:

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

O

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

Ecco una piccola e utile funzione che mi piace usare per ridurre la digitazione:

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   

Ecco un esempio di come funziona:

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

Nel caso in cui non si desidera che i nomi delle righe df.columns = ['a', 'b',index=False]


Nota che questo approccio non funziona per un MultiIndex. Per un MultiIndex, devi fare qualcosa come il seguente:

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

Potresti usare str.slice per questo:

df.columns = df.columns.str.slice(1)

Prova questo. Per me funziona

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

Se hai il dataframe, df.columns scarica tutto in un elenco che puoi manipolare e quindi riassegnare nel tuo dataframe come i nomi delle colonne ...

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

Miglior modo? IDK. Un modo - si.

Un modo migliore per valutare tutte le principali tecniche proposte nelle risposte alla domanda è sotto usando cProfile per misurare la memoria e il tempo di esecuzione. @kadee, @kaitlyn, & @eumiro hanno le funzioni con i tempi di esecuzione più veloci, anche se queste funzioni sono così veloci che stiamo confrontando l'arrotondamento di .000 e .001 secondi per tutte le risposte. Morale: la mia risposta sopra probabilmente non è il modo migliore.

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

Semplice e semplice basta usare

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

e assegnerà i nomi delle colonne in base all'ordine in cui li metti


Un altro modo per sostituire le etichette delle colonne originali è eliminare i caratteri indesiderati (qui '$') dalle etichette delle colonne originali.

Questo potrebbe essere stato eseguito eseguendo un ciclo for su df.columns e aggiungendo le colonne strippate a df.columns.

Invece, possiamo farlo in una singola dichiarazione usando la comprensione delle liste come di seguito:

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

(Il metodo strip in Python rimuove il carattere specificato dall'inizio e dalla fine della stringa.)


Un'altra opzione è rinominare usando un'espressione regolare:

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

Rinomina le colonne del dataframe e sostituisci il 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 = pd.DataFrame({'$a': [1], '$b': [1], '$c': [1], '$d': [1], '$e': [1]})

Se il tuo nuovo elenco di colonne è nello stesso ordine delle colonne esistenti, l'assegnazione è semplice:

new_cols = ['a', 'b', 'c', 'd', 'e']
df.columns = new_cols
>>> df
   a  b  c  d  e
0  1  1  1  1  1

Se avessi un dizionario digitato su vecchi nomi di colonne in nomi di nuove colonne, potresti fare quanto segue:

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

Se non si dispone di un elenco o di una mappatura del dizionario, è possibile rimuovere il simbolo $ principale tramite una comprensione di lista:

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

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

Sostituirà i nomi esistenti con i nomi che fornisci, nell'ordine da te fornito.


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)

In questo modo puoi modificare manualmente i new_names come desideri. Funziona alla grande quando è necessario rinominare solo poche colonne per correggere mispelling, accenti, rimuovere caratteri speciali, ecc.





rename