Solutions en ligne ou en pipeline
Je vais me concentrer sur deux choses:
OP indique clairement
J'ai les noms de colonnes modifiés stockés dans une liste, mais je ne sais pas comment remplacer les noms de colonnes.
Je ne veux pas résoudre le problème de la façon de remplacer '$'ou de 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' columnsobjet existant par un nouveau étant donné une liste de noms de colonnes de remplacement.
df.columns = newoù newest la liste des nouveaux noms de colonnes est aussi simple que possible. L'inconvénient de cette approche est qu'elle nécessite la modification de l'attribut du cadre de données existant columnset qu'elle n'est pas effectuée en ligne. Je vais montrer quelques façons d'effectuer cela via le pipelining sans modifier le cadre de données existant.
Configuration 1
Pour me concentrer sur la nécessité de renommer les noms de colonne de remplacement par une liste préexistante, je vais créer un nouvel exemple de trame dfde données avec les noms de colonne initiaux et les nouveaux noms de colonne non lié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 aux nouveaux noms de colonne, 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 df, nous itérons sur 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, cela tombe en panne.
Configurer 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 en
pd.concat utilisant l' keysargument
Tout d'abord, notez 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 newliste en tant que noms de colonne. Nous avons fini par répéter y765. Au lieu de cela, nous pouvons utiliser l' keysargument de la pd.concatfonction tout en parcourant 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 doit être utilisé que si vous en avez un dtypepour toutes les colonnes. Sinon, vous vous retrouverez avec dtype objectpour toutes les colonnes et les reconvertir nécessite plus de travail de dictionnaire.
Célibataire dtype
pd.DataFrame(df.values, df.index, new)
x098 y765 z432
0 1 3 5
1 2 4 6
Mixte dtype
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
Ceci est un truc gimmicky avec transposeet set_index. pd.DataFrame.set_indexnous permet de définir un index en ligne mais il n'y a pas de correspondant set_columns. Nous pouvons donc transposer, puis set_indextransposer en arrière. Cependant, la même mise en garde unique dtypeou mixte dtypede la solution 3 s'applique ici.
Célibataire dtype
df.T.set_index(np.asarray(new)).T
x098 y765 z432
0 1 3 5
1 2 4 6
Mixte dtype
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 lambdadans pd.DataFrame.renamequi parcourt chaque élément de new
Dans cette solution, nous passons un lambda qui le prend xmais l'ignore ensuite. Cela prend aussi un ymais ne s'y attend pas. Au lieu de cela, un itérateur est donné comme valeur par défaut et je peux ensuite l'utiliser pour parcourir un à la fois 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 dans le chat sopython , si j'ajoute un *entre xet y, je peux protéger ma yvariable. Cependant, dans ce contexte, je ne pense pas qu'il ait besoin d'être protégé. Cela vaut encore 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