web-dev-qa-db-ja.com

パンダ:特定のレベルのマルチインデックスを変更する

Multiindexを使用するデータフレームがあり、Multiindexの特定のレベルを変更したい。たとえば、最初のレベルは文字列であり、そのインデックスレベルから空白を削除したい場合があります。

df.index.levels[1] = [x.replace(' ', '') for x in df.index.levels[1]]

ただし、上記のコードはエラーになります。

TypeError: 'FrozenList' does not support mutable operations.

Reset_indexを実行して列を変更し、Multiindexを再作成できることは知っていますが、Multiindexの特定のレベルを直接変更するよりエレガントな方法があるのではないかと思います。

24
user1642513

@cxrodgersのコメントのおかげで、これを行う最も速い方法は次のとおりだと思います。

df.index = df.index.set_levels(df.index.levels[0].str.replace(' ', ''), level=0)

古い、長い答え:

@Shovaltによって提案されたリストの理解は機能するが、私のマシンでは遅いと感じた(10,000行を超えるデータフレームを使用)。

代わりに、.set_levelsメソッドを使用することができましたが、これはかなり高速でした。

%timeit pd.MultiIndex.from_tuples([(x[0].replace(' ',''), x[1]) for x in df.index])
1 loop, best of 3: 394 ms per loop

%timeit df.index.set_levels(df.index.get_level_values(0).str.replace(' ',''), level=0)
10 loops, best of 3: 134 ms per loop

実際には、テキストを追加する必要がありました。これは.set_levelsでさらに高速でした:

%timeit pd.MultiIndex.from_tuples([('00'+x[0], x[1]) for x in df.index])
100 loops, best of 3: 5.18 ms per loop

%timeit df.index.set_levels('00'+df.index.get_level_values(0), level=0)
1000 loops, best of 3: 1.38 ms per loop

%timeit df.index.set_levels('00'+df.index.levels[0], level=0)
1000 loops, best of 3: 331 µs per loop

このソリューションは、@ denfromufaによるコメントからのリンクの回答に基づいています...

python-マルチインデックスとタイムゾーン-凍結リストエラー-スタックオーバーフロー

15
John

コメントで述べたように、インデックスは不変であり、変更時に再作成する必要がありますが、reset_indexを使用する必要はありません。新しいマルチインデックスを直接作成できます。

df.index = pd.MultiIndex.from_tuples([(x[0], x[1].replace(' ', ''), x[2]) for x in df.index])

この例は、中間レベルを変更する3レベルのインデックス用です。さまざまなレベルのサイズに合わせて、タプルのサイズを変更する必要があります。

14
Shovalt