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' columns
objet existant par un nouveau étant donné une liste de noms de colonnes de remplacement.
df.columns = new
où new
est 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 columns
et 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 df
de 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' keys
argument
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 new
liste en tant que noms de colonne. Nous avons fini par répéter y765
. Au lieu de cela, nous pouvons utiliser l' keys
argument de la pd.concat
fonction 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 dtype
pour toutes les colonnes. Sinon, vous vous retrouverez avec dtype
object
pour 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 transpose
et set_index
. pd.DataFrame.set_index
nous permet de définir un index en ligne mais il n'y a pas de correspondant set_columns
. Nous pouvons donc transposer, puis set_index
transposer en arrière. Cependant, la même mise en garde unique dtype
ou mixte dtype
de 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 lambda
dans pd.DataFrame.rename
qui parcourt chaque élément de new
Dans cette solution, nous passons un lambda qui le prend x
mais l'ignore ensuite. Cela prend aussi un y
mais 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 x
et y
, je peux protéger ma y
variable. 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