0
0

More than 1 year has passed since last update.

pandas,MultiIndex,空値な列名,Unnamed困る

Posted at

pandasを使っているとき,MultiIndexを使いたくなる時が(あまりやりたくはないですが)あります.そしてMultiIndexと普通の階層のないインデックスを混在させたいときもあります.例えば以下のような感じ.

df = pd.DataFrame(
    [ 
        [ "ピカチュウ", "10まんボルト", "でんこうせっか", "アイアンテール", "エレキネット" ],
        [ "ルカリオ", "はどうだん", "インファイト", "かげぶんしん", "きしかいせい" ],
        [ "カイリュー", "りゅうのまい", "ドラゴンクロー", "ぼうふう", "りゅうせいぐん" ],
    ],
    columns=pd.MultiIndex.from_tuples( [("なまえ", ""), ("わざ", "1"), ("わざ", "2"), ("わざ", "3"), ("わざ", "4")] )
)

print( df )

以下出力.

出力
# 出力は以下のような感じ
   なまえ       わざ
                  1             2               3            4
0  ピカチュウ  10まんボルト  でんこうせっか  アイアンテール  エレキネット
1  ルカリオ    はどうだん    インファイト    かげぶんしん   きしかいせい
2  カイリュー  りゅうのまい  ドラゴンクロー  ぼうふう       りゅうせいぐん

わざMultiIndexなまえは普通のインデックスです.

MultiIndexに対して,インデックスに階層がない(ように見える)ものを「普通のインデックス」と呼んでいますが,お察しの通りこれは適切でない表現です.あくまで第0レベルのみのMultiIndexが妥当な表現と思われます.

このような時に列を取り出すときのTipsを備忘録としてまとめます.

またこのようなデータをテキストデータとして保存した後,再度読み込んだ時のTipsも.

列を取り出したいよー

print( df[ ("わざ", "1" ) ] ) # MultiIndexな方にアクセスするとき

print( df[ "なまえ" ] ) # MultiIndexじゃないほうにアクセスするとき

# # MultiIndexじゃないほうにアクセスするとき,以下の記法でもOK
# print( df[ ("なまえ", "") ] )
# print( df[ ("なまえ", ) ] )

print( type( df[ "なまえ" ] ) ) # 型も見ておく

print( df.columns ) # ついでに列の情報もみておく

以下出力.

出力
0    10まんボルト
1      はどうだん
2     りゅうのまい
Name: (わざ, 1), dtype: object

0    ピカチュウ
1     ルカリオ
2    カイリュー
Name: なまえ, dtype: object

<class 'pandas.core.series.Series'>

MultiIndex( [
    ('なまえ',  ''),
    ( 'わざ', '1'),
    ( 'わざ', '2'),
    ( 'わざ', '3'),
    ( 'わざ', '4')
], )

一度テキストに保存し,その後読み込んだ時

DataFramepoke.txt として保存し,読み込んで同じことをします.

df = pd.read_table( r"./poke.txt", delimiter="\t", header=[0, 1] )
print( df )

print( df[ ("わざ", "1" ) ] ) # これはもともとの通り

print( df["なまえ"] ) # ここが微妙
print( type( df["なまえ"] ) ) # ここも微妙

print( df.columns ) # ここが問題な感じ

結果は以下.

                 なまえ       わざ
     Unnamed: 0_level_1        1             2            3              4
0    ピカチュウ            10まんボルト  でんこうせっか   アイアンテール  エレキネット
1    ルカリオ              はどうだん    インファイト    かげぶんしん     きしかいせい
2    カイリュー            りゅうのまい  ドラゴンクロー   ぼうふう        りゅうせいぐん

0    10まんボルト
1      はどうだん
2     りゅうのまい
Name: (わざ, 1), dtype: object

  Unnamed: 0_level_1
0              ピカチュウ
1               ルカリオ
2              カイリュー

<class 'pandas.core.frame.DataFrame'>

MultiIndex( [
    ('なまえ', 'Unnamed: 0_level_1'),
    ( 'わざ',                  '1'),
    ( 'わざ',                  '2'),
    ( 'わざ',                  '3'),
    ( 'わざ',                  '4')
], )

もともと列なまえは第0レベルだけで,その下の第1レベルは空値でした.しかし読み込む時に空値の部分には,Unnamed: 0_level_1 が自動で入力されてしまうようです.すると df["なまえ"]pd.Series ではなく pd.DataFrame として扱われてしまうなど,ちょっと微妙です.

そのため,列のIndexの中にある,Unnamed: 0_level_1を空文字で置き換えてしまいましょう.

df = pd.read_table( r"./poke.txt", delimiter="\t", header=[0, 1] )

df.columns = df.columns.map( lambda x: tuple("" if y.startswith("Unnamed") else y for y in x) )

Unnamedで始まる列の要素名を空文字に置き換えればOKです.

おわりに

なにか他にいい方法あれば教えてください.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0