Je veux trouver le moyen de changer le nom d'une colonne spécifique dans un cadre de données multiniveau.
Avec ces données:
data = {
('A', '1', 'I'): [1, 2, 3, 4, 5],
('B', '2', 'II'): [1, 2, 3, 4, 5],
('C', '3', 'I'): [1, 2, 3, 4, 5],
('D', '4', 'II'): [1, 2, 3, 4, 5],
('E', '5', 'III'): [1, 2, 3, 4, 5],
}
dataDF = pd.DataFrame(data)
Ce code ne fonctionne pas:
dataDF.rename(columns = {('A', '1', 'I'):('Z', '100', 'Z')}, inplace=True)
Résultat:
A B C D E
1 2 3 4 5
I II I II III
0 1 1 1 1 1
1 2 2 2 2 2
2 3 3 3 3 3
3 4 4 4 4 4
4 5 5 5 5 5
Et pas non plus:
dataDF.columns.values[0] = ('Z', '100', 'Z')
Résultat:
A B C D E
1 2 3 4 5
I II I II III
0 1 1 1 1 1
1 2 2 2 2 2
2 3 3 3 3 3
3 4 4 4 4 4
4 5 5 5 5 5
Mais avec la combinaison des codes ci-dessus qui fonctionnent !!!
dataDF.columns.values[0] = ('Z', '100', 'Z')
dataDF.rename(columns = {('A', '1', 'I'):('Z', '100', 'Z')}, inplace=True)
dataDF
Résultat:
Z B C D E
100 2 3 4 5
Z II I II III
0 1 1 1 1 1
1 2 2 2 2 2
2 3 3 3 3 3
3 4 4 4 4 4
4 5 5 5 5 5
Est-ce que ce bug des pandas?
C'est ma théorie
les pandas ne veulent pas que pd.Index
s soit mutable. Nous pouvons le voir si nous essayons de changer nous-mêmes le premier élément de l'index
dataDF.columns[0] = ('Z', '100', 'Z')
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-32-2c0b76762235> in <module>() ----> 1 dataDF.columns[0] = ('Z', '100', 'Z') //anaconda/envs/3.5/lib/python3.5/site-packages/pandas/indexes/base.py in __setitem__(self, key, value) 1372 1373 def __setitem__(self, key, value): -> 1374 raise TypeError("Index does not support mutable operations") 1375 1376 def __getitem__(self, key): TypeError: Index does not support mutable operations
Mais les pandas ne peuvent pas contrôler ce que vous faites avec l'attribut values
.
dataDF.columns.values[0] = ('Z', '100', 'Z')
nous voyons que dataDF.columns
est identique, mais dataDF.columns.values
reflète clairement le changement. Malheureusement, df.columns.values
n’est pas ce qui apparaît sur l’affichage du cadre de données.
D'un autre côté, cela semble vraiment fonctionner. Le fait que cela ne me semble pas mauvais.
dataDF.rename(columns={('A', '1', 'I'): ('Z', '100', 'Z')}, inplace=True)
Je crois que si cela ne fonctionne que si les valeurs ont été modifiées, c'est que rename
force la reconstruction des colonnes en examinant les valeurs. Depuis que nous changeons les valeurs, cela fonctionne maintenant. C'est exceptionnellement kludgy et je ne recommande pas de construire un processus qui repose sur cela.
ma recommandation
from_col = ('A', '1', 'I')
to_col = ('Z', '100', 'Z')
colloc = dataDF.columns.get_loc(from_col)
cvals = dataDF.columns.values
cvals[colloc] = to_col
dataDF.columns = pd.MultiIndex.from_tuples(cvals.tolist())
dataDF
[![enter code here][1]][1]
Vous pouvez simplement le changer comme DF.columns.levels=[[u'Z', u'B', u'C', u'D', u'E'],[u'5', u'2', u'3', u'4', u'5'],[u'IIIIII', u'II', u'III']]
Je suis tombé sur cette question alors que j'essayais moi-même de trouver la solution pour renommer les noms de colonnes dans un cadre de données à plusieurs niveaux. J'ai essayé la solution fournie par @Dark Matter car elle semblait très simple:
dataDF.columns.levels = [[u'Z', u'B', u'C', u'D', u'E'], [u'100', u'2', u'3', u'4', u'5'], [u'Z', u'II', u'III']]
Mais un message d'erreur était affiché:
C:\anaconda3\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: setting `levels` directly is deprecated. Use set_levels instead
"""Entry point for launching an IPython kernel.
Il semble que cela a fonctionné mais ne fonctionne plus. Alors j'ai utilisé:
dataDF.columns.set_levels([['Z', 'B', 'C', 'D', 'E'],
['100', '2', '3', '4', '5'],
['Z', 'II', 'III']],
[0, 1, 2], inplace=True)
Résultat: dataDF
Z B C D E
100 2 3 4 5
Z II Z II III
0 1 1 1 1 1
1 2 2 2 2 2
2 3 3 3 3 3
3 4 4 4 4 4
4 5 5 5 5 5