マルチレベルデータフレームの特定の列の名前を変更する方法を見つけたいです。
このデータで:
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)
このコードは機能しません:
dataDF.rename(columns = {('A', '1', 'I'):('Z', '100', 'Z')}, inplace=True)
結果:
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
そしてまた:
dataDF.columns.values[0] = ('Z', '100', 'Z')
結果:
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
しかし、上記のコードの組み合わせが機能している!!!
dataDF.columns.values[0] = ('Z', '100', 'Z')
dataDF.rename(columns = {('A', '1', 'I'):('Z', '100', 'Z')}, inplace=True)
dataDF
結果:
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
これはパンダのバグですか?
これは私の理論です
パンダはpd.Index
sを変更可能にすることを望んでいません。インデックスの最初の要素を自分で変更しようとすると、これがわかります
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は、values
属性を実行することを制御できません。
dataDF.columns.values[0] = ('Z', '100', 'Z')
dataDF.columns
は同じに見えますが、dataDF.columns.values
は明らかに変更を反映しています。残念ながら、df.columns.values
は、データフレームの表示に表示されるものではありません。
一方、これは実際に機能するはずです。それが私に悪いと感じていないという事実。
dataDF.rename(columns={('A', '1', 'I'): ('Z', '100', 'Z')}, inplace=True)
これが値を変更した後にのみ機能する理由は、rename
が値を確認することによって列の再構築を強制しているためだと思います。値を変更したので、機能します。これは非常に扱いにくいため、これに依存するプロセスを構築することはお勧めしません。
私の推奨事項
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]
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']]
のように変更するだけです
私自身が複数レベルのデータフレーム内の列名の名前を変更するための解決策を見つけようとしていたときに、この質問に遭遇しました。 @Dark Matterが提供するソリューションを試してみました。非常にシンプルなソリューションのようです。
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']]
しかし、エラーメッセージが表示されました。
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.
動作したようですが、動作しなくなりました。だから私は使用しました:
dataDF.columns.set_levels([['Z', 'B', 'C', 'D', 'E'],
['100', '2', '3', '4', '5'],
['Z', 'II', 'III']],
[0, 1, 2], inplace=True)
結果: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