Ich möchte herausfinden, wie der Name einer bestimmten Spalte in einem mehrstufigen Datenrahmen geändert wird.
Mit diesen Daten:
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)
Dieser Code funktioniert nicht:
dataDF.rename(columns = {('A', '1', 'I'):('Z', '100', 'Z')}, inplace=True)
Ergebnis:
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
Und auch nicht:
dataDF.columns.values[0] = ('Z', '100', 'Z')
Ergebnis:
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
Aber mit Kombination der oben genannten Codes funktioniert !!!
dataDF.columns.values[0] = ('Z', '100', 'Z')
dataDF.rename(columns = {('A', '1', 'I'):('Z', '100', 'Z')}, inplace=True)
dataDF
Ergebnis:
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
Ist dieser Bug von Pandas?
Das ist meine Theorie
pandas wollen nicht, dass pd.Index
s veränderbar ist. Wir können das sehen, wenn wir versuchen, das erste Element des Index selbst zu ändern
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
Pandas können jedoch nicht kontrollieren, was Sie mit dem Attribut values
tun.
dataDF.columns.values[0] = ('Z', '100', 'Z')
wir sehen, dass dataDF.columns
gleich aussieht, aber dataDF.columns.values
spiegelt die Änderung eindeutig wider. Leider ist df.columns.values
nicht das, was auf der Anzeige des Datenrahmens angezeigt wird.
Auf der anderen Seite scheint das wirklich zu funktionieren. Die Tatsache, dass es mir nicht falsch vorkommt.
dataDF.rename(columns={('A', '1', 'I'): ('Z', '100', 'Z')}, inplace=True)
Ich glaube, der Grund, warum dies funktioniert, nachdem die Werte geändert wurden, ist, dass rename
die Rekonstruktion der Spalten erzwingt, indem sie die Werte betrachtet. Da wir die Werte ändern, funktioniert es jetzt. Das ist ausnahmslos kludgy und ich empfehle nicht, einen Prozess zu bauen, der darauf angewiesen ist.
meine Empfehlung
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]
Sie können es einfach ändern wie 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']]
Ich stieß auf diese Frage, als ich selbst nach einer Lösung für das Umbenennen der Spaltennamen in einem Datenrahmen mit mehreren Ebenen suchte. Ich habe die von @Dark Matter bereitgestellte Lösung ausprobiert, da es sich um eine sehr einfache Lösung handelte:
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']]
Es wurde jedoch eine Fehlermeldung angezeigt:
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.
Es scheint, dass es funktioniert hat, aber nicht mehr funktioniert. Also habe ich benutzt:
dataDF.columns.set_levels([['Z', 'B', 'C', 'D', 'E'],
['100', '2', '3', '4', '5'],
['Z', 'II', 'III']],
[0, 1, 2], inplace=True)
Ergebnis: 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