web-dev-qa-db-ja.com

パンダ:マルチレベルの列を持つデータフレームの特定の列名を変更する

マルチレベルデータフレームの特定の列の名前を変更する方法を見つけたいです。

このデータで:

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

これはパンダのバグですか?

7
sh.jeon

これは私の理論です

パンダはpd.Indexsを変更可能にすることを望んでいません。インデックスの最初の要素を自分で変更しようとすると、これがわかります

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]
17
piRSquared

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']]のように変更するだけです

1
Dark Matter

私自身が複数レベルのデータフレーム内の列名の名前を変更するための解決策を見つけようとしていたときに、この質問に遭遇しました。 @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
1
novastar