こんな人にオススメ
以前pandasのMultiIndex
についての解説があったけど、こっちはインデックスが複数個あるデータフレーム。
じゃあ、ヘッダが複数個あるデータフレームは一体どうなるの?
ということで、今回は以前の続きでMultiColumns
について解説する。表のイメージは以下の感じ。
col_A | col_B | |||
hdr0 | hdr1 | hdr2 | hdr3 | |
index0 | 0 | 10 | 20 | 30 |
index1 | 10 | 20 | 30 | 40 |
index2 | 20 | 30 | 40 | 50 |
index3 | 30 | 40 | 50 | 60 |
index4 | 40 | 50 | 60 | 70 |
index5 | 50 | 60 | 70 | 80 |
MultiIndex
と似たところが多くあるので、まずはMultiIndex
の記事を見ていただいてから今回のMultiColulmns
の内容を見ていただくとより一層わかるのではないだろうか。
-
-
【pd&MultiIndex】pandasで複数インデックスの設定と書き読み
続きを見る
python環境は以下。
- Python 3.9.4
- numpy 1.20.3
- pandas 1.2.4
下準備
まずは本記事で共通の処理。
モジュールのimport
import numpy as np import pandas as pd
本記事で使用するモジュール、numpy
とpandas
のimport
。
作成するデータの行数と列数
# 6行4列の配列を作成 rows, cols = 6, 4
本記事で作成するデータ部分(ヘッダやインデックスは含まない)は、6行4列にするため予め行数と列数を定義。
辞書からMultiColumns
データフレームを作成してみる
まずは以前のMultiIndex
と同じように、辞書からMultiColumns
のデータフレームを作成してみる。
浅いkeys
を浅いヘッダーに設定
dct = { 'col_A': { 'hdr0': np.array([0, 10, 20, 30, 40, 50]), 'hdr1': np.array([10, 20, 30, 40, 50, 60]), }, 'col_B': { 'hdr2': np.array([20, 30, 40, 50, 60, 70]), 'hdr3': np.array([30, 40, 50, 60, 70, 80]), }, } index = [f"index{n}" for n in range(rows)] print(dct) # {'col_A': {'hdr0': array([ 0, 10, 20, 30, 40, 50]), 'hdr1': array([10, 20, 30, 40, 50, 60])}, 'col_B': {'hdr2': array([20, 30, 40, 50, 60, 70]), 'hdr3': array([30, 40, 50, 60, 70, 80])}}
シンプルにレベルの浅い(より上にある)ヘッダを浅い辞書のkeys
に持ってきて、深いレベルのヘッダをより深いkeys
に設定する方法。MultiIndex
ではこの方法が使えたが、MultiColumns
ではどうなるかというとうまくいかない。
print(pd.DataFrame(dct, index=index)) # col_A col_B # index0 NaN NaN # index1 NaN NaN # index2 NaN NaN # index3 NaN NaN # index4 NaN NaN # index5 NaN NaN
col_A
とcol_B
の下に辞書を置いたので認識されずに全てのデータがNaN
になってしまった。
浅いヘッダーを複数keys
に設定
dct = { 'col_A': {'hdr0': np.array([0, 10, 20, 30, 40, 50]), }, 'col_A': {'hdr1': np.array([10, 20, 30, 40, 50, 60]), }, 'col_B': {'hdr2': np.array([20, 30, 40, 50, 60, 70]), }, 'col_B': {'hdr3': np.array([30, 40, 50, 60, 70, 80]), }, } print(dct) # {'col_A': {'hdr1': array([10, 20, 30, 40, 50, 60])}, 'col_B': {'hdr3': array([30, 40, 50, 60, 70, 80])}}
では、ヘッダごとにレベルが浅いヘッダと深いヘッダを設定すればいいじゃないかとなるが、然うは問屋が卸さない。辞書は同じkeys
は許さないから。同じkeys
が出るとエラーは出ないがkeys
が上書きされて消える。
うまくいく気がしない
ということで、MultiIndex
の時と同じようにしてもうまくいく気がしないので中止。データ、インデックス、ヘッダをバラバラに作成したほうが恐らく楽なのでそうする。
配列でバラバラに設定してMultiColumns
データフレームを作成
データ、インデックス、ヘッダをバラバラにしてデータフレームを作成する。手順は増えるかもしれないが単純でわかりやすい。
columns
とindex
の設定
# level0がより左側のインデックスで、階層は上のインデックス level0 = ['col_A', 'col_A', 'col_B', 'col_B'] level1 = ['hdr0', 'hdr1', 'hdr2', 'hdr3'] columns = [level0, level1] print(columns) # [['col_A', 'col_A', 'col_B', 'col_B'], ['hdr0, hdr1, hdr2, hdr3']] index = [f"index{n}" for n in range(rows)] print(index) # ['index0', 'index1', 'index2', 'index3', 'index4', 'index5']
level0
がより浅い、上に位置するヘッダでlevel1
がlevel0
の下にくるヘッダ。インデックスは今回は1列にしてMulti
にしない。
データの作成
# データ自体を作成 data = [] for col in range(cols): # データは10ずつズラす arr = 10 * np.arange(col, col + rows) data.append(arr) data = np.array(data) # このままだと行と列の数が合わない print(data) # [[ 0 10 20 30 40 50] # [10 20 30 40 50 60] # [20 30 40 50 60 70] # [30 40 50 60 70 80]]
データは10ずつ値をズラし他ものを使用。単純な配列で良かったがなんかこうした。完全に無駄に複雑な配列。しかし、このままでは配列の行と列の個数が合わないので転置。
# 行と列を入れ替え data = data.T print(data) # [[ 0 10 20 30] # [10 20 30 40] # [20 30 40 50] # [30 40 50 60] # [40 50 60 70] # [50 60 70 80]]
MultiColumns
のデータフレーム作成
df = pd.DataFrame(data, index=index, columns=columns) print(df) # col_A col_B # hdr0 hdr1 hdr2 hdr3 # index0 0 10 20 30 # index1 10 20 30 40 # index2 20 30 40 50 # index3 30 40 50 60 # index4 40 50 60 70 # index5 50 60 70 80
pd.DataFrame
にデータ、インデックス、ヘッダの情報を入れてデータフレームを作成。ヘッダ部分が2段になっているのでこのデータフレームがMultiColumns
になっていることがわかる。
MultiColumns
のデータ抽出
MultiColumns
はヘッダが通常データフレームよりも多い。じゃあどうやって取り出すのかってこと。
MultiColumns
全体を抽出
# MultiColumnsだろうが取り出せばMultiIndexと同じ columns_val = df.keys() print(columns_val) # MultiIndex([('col_A', 'hdr0'), # ('col_A', 'hdr1'), # ('col_B', 'hdr2'), # ('col_B', 'hdr3')], # ) print(type(columns_val)) # <class 'pandas.core.indexes.multi.MultiIndex'>
データフレームのヘッダが欲しいならシンプルに.keys()
で取り出し可能。.keys()
以外にも.columns
でも同様に取り出し可能。
# .columnsでも取り出し可能 columns_val = df.columns print(columns_val) # MultiIndex([('col_A', 'hdr0'), # ('col_A', 'hdr1'), # ('col_B', 'hdr2'), # ('col_B', 'hdr3')], # ) print(type(columns_val)) # pandas.core.indexes.multi.MultiIndex
一応、データフレームではlist(df)
にするとヘッダだけが取り出されるが、この場合はもちろんlist
で返される。
# listにするとヘッダは取得可能だがもちろんlistで返される columns_val = list(df) print(columns_val) # [('col_A', 'hdr0'), ('col_A', 'hdr1'), ('col_B', 'hdr2'), ('col_B', 'hdr3')]
各レベルのMultiColumns
を抽出
# レベルごとに値を取り出し可能 level0_ind = df.columns.get_level_values(0) print(level0_ind) # Index(['col_A', 'col_A', 'col_B', 'col_B'], dtype='object') level1_ind = df.columns.get_level_values(1) print(level1_ind) # Index(['hdr0', 'hdr1', 'hdr2', 'hdr3'], dtype='object')
各レベルのヘッダを取り出すには.get_level_values
。一番レベルの浅い(上にあるヘッダ)が0
でそこから1
レベル上がるごとに+1
される。
列指定でデータを抽出
# 階層の浅いものから順番に指定する必要がある col_A = df['col_A'] print(col_A) # hdr0 hdr1 # index0 0 10 # index1 10 20 # index2 20 30 # index3 30 40 # index4 40 50 # index5 50 60 print(type(col_A)) # <class 'pandas.core.frame.DataFrame'>
列ごと取得したい場合はシンプルに[]
で欲しいヘッダ名を指定。この状態からさらにhdr
を指定することも可能。
hdr1 = col_A['hdr1'] print(hdr1) # index0 10 # index1 20 # index2 30 # index3 40 # index4 50 # index5 60 # Name: hdr1, dtype: int64 print(type(hdr1)) # <class 'pandas.core.series.Series'>
一気に指定すると以下のようになる。
# 一気に処理するとこうなる hdr1 = df['col_A']['hdr1'] print(hdr1) # index0 10 # index1 20 # index2 30 # index3 40 # index4 50 # index5 60 # Name: hdr1, dtype: int64
bool
はインデックスの抽出方法になるので注意
print(df) # col_A col_B # hdr0 hdr1 hdr2 hdr3 # index0 0 10 20 30 # index1 10 20 30 40 # index2 20 30 40 50 # index3 30 40 50 60 # index4 40 50 60 70 # index5 50 60 70 80 level0_ind = columns_val.get_level_values(0) print(level0_ind) # Index(['col_A', 'col_A', 'col_B', 'col_B'], dtype='object') condition = level0_ind == 'col_A' print(condition) # [ True True False False]
取り出した特定のレベルのヘッダに対して条件を加えることも可能。しかし、この条件のbool
で指定できるのはインデックス対してのみ。今回のヘッダに対して行うとエラー。
# boolの配列を入れて抽出するのはインデックスのみ col_A = df[condition] # ValueError: Item wrong length 4 instead of 6.
試しにインデックスと同じ要素数のbool
配列を適用するとインデックスが制限される。
# インデックスの数と同じ数のboolを使うとインデックスで条件を決められる condition = [True, True, False, False, True, False] print(df[condition]) # col_A col_B # hdr0 hdr1 hdr2 hdr3 # index0 0 10 20 30 # index1 10 20 30 40 # index4 40 50 60 70
大人しくdf['col_A']
とするのが賢い。
MultiColumns
のレベル1で条件抽出
もし、col_A
ではなくhdr1
のデータだけ全て欲しい、となった場合はどのように指定すればいいのか。これまでのデータフレームではhdr
の名称がダブっていないので、ダブったデータフレームを作成。
# level0がより左側のインデックスで、階層は上のインデックス level0 = ['col_A'] * 4 + ['col_B'] * 4 print(level0) # ['col_A', 'col_A', 'col_A', 'col_A', 'col_B', 'col_B', 'col_B', 'col_B'] level1 = ['hdr0', 'hdr1', 'hdr2', 'hdr3'] * 2 print(level1) # ['hdr0', 'hdr1', 'hdr2', 'hdr3', 'hdr0', 'hdr1', 'hdr2', 'hdr3'] columns = [level0, level1] print(columns) # [['col_A', 'col_A', 'col_A', 'col_A', 'col_B', 'col_B', 'col_B', 'col_B'], ['hdr0', 'hdr1', 'hdr2', 'hdr3', 'hdr0', 'hdr1', 'hdr2', 'hdr3']] index = [f"index{n}" for n in range(rows)] print(index) # ['index0', 'index1', 'index2', 'index3', 'index4', 'index5'] # データ自体を作成 data = np.arange(len(index) * len(level0)).reshape(len(index), -1) print(data) # [[ 0 1 2 3 4 5 6 7] # [ 8 9 10 11 12 13 14 15] # [16 17 18 19 20 21 22 23] # [24 25 26 27 28 29 30 31] # [32 33 34 35 36 37 38 39] # [40 41 42 43 44 45 46 47]]
上記の計算で作成されるデータフレームが以下。
df = pd.DataFrame(data, index=index, columns=columns) print(df) # col_A col_B # hdr0 hdr1 hdr2 hdr3 hdr0 hdr1 hdr2 hdr3 # index0 0 1 2 3 4 5 6 7 # index1 8 9 10 11 12 13 14 15 # index2 16 17 18 19 20 21 22 23 # index3 24 25 26 27 28 29 30 31 # index4 32 33 34 35 36 37 38 39 # index5 40 41 42 43 44 45 46 47
例えばhdr1
の列だけ欲しい場合はどうすればいいのか、という問いに関しての答えは以下の2種類の配列を取得するということ。本当はデータフレームとして出力されるのでインデックスの情報とかもつくが、データ部分だけ見ると以下。
1, 9, 17, 25, 33, 41
5, 13, 21, 29, 37, 45
転置してヘッダをインデックスにして抽出して元に戻す
trnsps = df.T print(trnsps) # index0 index1 index2 index3 index4 index5 # col_A hdr0 0 8 16 24 32 40 # hdr1 1 9 17 25 33 41 # hdr2 2 10 18 26 34 42 # hdr3 3 11 19 27 35 43 # col_B hdr0 4 12 20 28 36 44 # hdr1 5 13 21 29 37 45 # hdr2 6 14 22 30 38 46 # hdr3 7 15 23 31 39 47
先ほど、bool
の配列をデータフレームに入れるとインデックスに適用されるということを書いた。なら、ヘッダをインデックスにしてしまえばいいんじゃないという力技。df
も.T
で転置ができるので転置するとヘッダがインデックスに、インデックスがヘッダに入れ替わる。もちろんデータも転置される。
実際にインデックスをとってみると元ヘッダを取り出すことができる。したがって、この状態でhdr1
に当てはまる条件を適用して最後に転置で元に戻せば一件落着。
condition = index1 == 'hdr1' hdr1_onlyT = trnsps[condition] print(hdr1_onlyT) # index0 index1 index2 index3 index4 index5 # col_A hdr1 1 9 17 25 33 41 # col_B hdr1 5 13 21 29 37 45 hdr1_only = hdr1_onlyT.T print(hdr1_only) # col_A col_B # hdr1 hdr1 # index0 1 5 # index1 9 13 # index2 17 21 # index3 25 29 # index4 33 37 # index5 41 45
条件のbool
配列をloc
に適用
print(df) # col_A col_B # hdr0 hdr1 hdr2 hdr3 hdr0 hdr1 hdr2 hdr3 # index0 0 1 2 3 4 5 6 7 # index1 8 9 10 11 12 13 14 15 # index2 16 17 18 19 20 21 22 23 # index3 24 25 26 27 28 29 30 31 # index4 32 33 34 35 36 37 38 39 # index5 40 41 42 43 44 45 46 47 level1_ind = df.columns.get_level_values(1) print(level1_ind) # Index(['hdr0', 'hdr1', 'hdr2', 'hdr3', 'hdr0', 'hdr1', 'hdr2', 'hdr3'], dtype='object') # このconditionを直接データフレームに入れると、インデックスが認識されてうまくいかなかった condition = level1_ind == 'hdr1' print(condition) # [False True False False False True False False]
条件を入れたbool
の配列を.loc
でデータフレームに適用することででも条件の適用を行うことが可能。似たようなものとして.iloc
があるが違いは以下。
loc
: 行、列の名称で指定iloc
: 行、列のインデックス番号で指定
ただし、どちらもbool
配列での適用には対応しているので、ここではbool
配列でデータフレームの条件適用を行うことにする。
# locで全行を選択することで抽出可能 # 「loc」は行・列をラベルで指定、ilocがインデックスで指定 # boolならどちらも同様に可能 hdr1_only = df.loc[:, condition] print(hdr1_only) # col_A col_B # hdr1 hdr1 # index0 1 5 # index1 9 13 # index2 17 21 # index3 25 29 # index4 33 37 # index5 41 45
loc
はloc[(行), (列)]
の順番で指定する。今回は列方向に条件を適用させ、行方向に対しては全データを使用することにする。したがって行については全行を表す:
を使用する。なお、行方向にも条件を追加したい場合はスライスの要領でインデックスの名称を入れたらいい。
# 行の指定も可能 hdr1_only14 = df.loc['index1':'index4', condition] print(hdr1_only14) # col_A col_B # hdr1 hdr1 # index1 9 13 # index2 17 21 # index3 25 29 # index4 33 37
ヘッダ名の配列をloc
に適用
# pd.IndexSliceを使用することで一気にlevel1の指定が可能 slice = pd.IndexSlice[['col_A', 'col_B'], 'hdr1'] print(slice) # (['col_A', 'col_B'], 'hdr1') print(type(slice)) # <class 'tuple'> hdr1_only = df.loc[:, slice] print(hdr1_only) # col_A col_B # hdr1 hdr1 # index0 1 5 # index1 9 13 # index2 17 21 # index3 25 29 # index4 33 37 # index5 41 45
loc
に直接ヘッダの名前を入れることでも条件を適用することが可能。ヘッダ名の配列にはpd.IndexSlice
を使用。この関数ではtuple
が作られるので、自分でtupleを作成して適用してもいい。
# pd.IndexSliceで作成した配列はrupleなので、もちろん簡単に自作も可能 slice = (['col_A', 'col_B'], 'hdr1') print(df.loc[:, slice]) # col_A col_B # hdr1 hdr1 # index0 1 5 # index1 9 13 # index2 17 21 # index3 25 29 # index4 33 37 # index5 41 45
ただし、tuple
ではなくlist
にするとエラー。
# listにするとエラー slice = [['col_A', 'col_B'], 'hdr1'] print(df.loc[:, slice]) # NotImplementedError: Index._join_level on non-unique index is not implemented
また、level0
のデータをヘッダから自動で取得して指定することも可能。コードが長くて面倒だけどlevel0
の情報が多い時には使えそう。
# sliceのlevel0の配列をいちいち打ち込むのが面倒なら、データフレームから取得すればいい level0_ind = df.columns.get_level_values(0) print(level0_ind) # Index(['col_A', 'col_A', 'col_A', 'col_A', 'col_B', 'col_B', 'col_B', 'col_B'], dtype='object') # ダブってるヘッダー名を消してユニークにする level0_ind = df.columns.get_level_values(0).unique() print(level0_ind) # Index(['col_A', 'col_B'], dtype='object') slice = pd.IndexSlice[level0_ind, 'hdr1'] print(slice) # (Index(['col_A', 'col_B'], dtype='object'), 'hdr1') print(df.loc[:, slice]) # col_A col_B # hdr1 hdr1 # index0 1 5 # index1 9 13 # index2 17 21 # index3 25 29 # index4 33 37 # index5 41 45
MultiColumns
データフレームをtxtファイルに書き出し、読み込み
MultiColumns
のデータフレームを作成したので、今度はこのデータフレームを書き出す。そして、書き出したファイルを再度読み込んでみる。
データの書き出し
print(df) # col_A col_B # hdr0 hdr1 hdr2 hdr3 hdr0 hdr1 hdr2 hdr3 # index0 0 1 2 3 4 5 6 7 # index1 8 9 10 11 12 13 14 15 # index2 16 17 18 19 20 21 22 23 # index3 24 25 26 27 28 29 30 31 # index4 32 33 34 35 36 37 38 39 # index5 40 41 42 43 44 45 46 47 df.to_csv('./multicolumns.txt', sep='\\t') # col_A col_A col_A col_A col_B col_B col_B col_B # hdr0 hdr1 hdr2 hdr3 hdr0 hdr1 hdr2 hdr3 # index0 0 1 2 3 4 5 6 7 # index1 8 9 10 11 12 13 14 15 # index2 16 17 18 19 20 21 22 23 # index3 24 25 26 27 28 29 30 31 # index4 32 33 34 35 36 37 38 39 # index5 40 41 42 43 44 45 46 47
データの書き出しは.to_csv
で行う。txtファイルとして出力する場合は区切り文字sep
はsep='\t'
としてタブ区切りにすると便利。csvファイルにする際にはsep=','
にしてカンマ区切りにする。
データの読み込み
# 普通に読み込むだけだとMultiColumnsにならない df_read = pd.read_csv('./multicolumns.txt', sep='\\t') print(df_read) # Unnamed: 0 col_A col_A.1 col_A.2 col_A.3 col_B col_B.1 col_B.2 col_B.3 # 0 NaN hdr0 hdr1 hdr2 hdr3 hdr0 hdr1 hdr2 hdr3 # 1 index0 0 1 2 3 4 5 6 7 # 2 index1 8 9 10 11 12 13 14 15 # 3 index2 16 17 18 19 20 21 22 23 # 4 index3 24 25 26 27 28 29 30 31 # 5 index4 32 33 34 35 36 37 38 39 # 6 index5 40 41 42 43 44 45 46 47
前節で作成したデータフレームを書き出した。ここではそのデータフレームを再度読み込んでみる。シンプルに.read_csv
でデータを読み込んでもMultiColumns
にはならずにlevel0
だけがヘッダとして認識される。また、インデックスの部分がNaN
になったりUnnamed: 0
になったりしてしまっている。
これを解消するためには、ヘッダが2行あることを指定しないといけない。読み込み時にheader
引数で0
行目と1
行目がヘッダーであると指定する。
# ヘッダーが2行であることを設定する必要がある df_read = pd.read_csv('./multicolumns.txt', sep='\\t', header=[0, 1]) print(df_read) # col_A col_B # hdr0 hdr1 hdr2 hdr3 hdr0 hdr1 hdr2 hdr3 # index0 0 1 2 3 4 5 6 7 # index1 8 9 10 11 12 13 14 15 # index2 16 17 18 19 20 21 22 23 # index3 24 25 26 27 28 29 30 31 # index4 32 33 34 35 36 37 38 39 # index5 40 41 42 43 44 45 46 47
ヘッダ名で指定することはできない。あくまでもint
での指定となる。
# ヘッダ名の名称での指定はできない header = [ ['col_A', 'col_A', 'col_A', 'col_A', 'col_B', 'col_B', 'col_B', 'col_B'], ['hdr0', 'hdr1', 'hdr2', 'hdr3', 'hdr0', 'hdr1', 'hdr2', 'hdr3'] ] # df_read = pd.read_csv('./multicolumns.txt', sep='\\t', header=header) # ValueError: header must be integer or list of integers
MultiIndex
とMultiColumns
を合わせる
ここでは、前回のMultiIndex
と今回のMultiColumns
を組み合わせたデータフレームを作成。その後、作成したデータフレームをtxtファイルに書き出し、再度読み込む。
データの作成
c_level0 = ['col_A', 'col_A', 'col_B', 'col_B'] c_level1 = ['hdr0', 'hdr1', 'hdr2', 'hdr3'] columns = [c_level0, c_level1] i_level0 = ['ind_A', 'ind_A', 'ind_B', 'ind_B', 'ind_C', 'ind_C'] i_level1 = [1, 2, 3, 4, 5, 6] indices = [i_level0, i_level1] # データ自体を作成 data = np.arange(len(i_level0) * len(c_level0)).reshape(len(index), -1) print(data) # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11] # [12 13 14 15] # [16 17 18 19] # [20 21 22 23]]
ヘッダー・インデックスともに1つのlevel0
に対して2つのlevel1
を対応させ、ヘッダは2種類、インデックスは3種類のデータでデータフレームを作成。
df = pd.DataFrame(data, index=indices, columns=columns) df.index.names = ['index0', 'index1'] print(df) # col_A col_B # hdr0 hdr1 hdr2 hdr3 # index0 index1 # ind_A 1 0 1 2 3 # 2 4 5 6 7 # ind_B 3 8 9 10 11 # 4 12 13 14 15 # ind_C 5 16 17 18 19 # 6 20 21 22 23
データを抽出
print(df.columns) # MultiIndex([('col_A', 'hdr0'), # ('col_A', 'hdr1'), # ('col_B', 'hdr2'), # ('col_B', 'hdr3')], # ) print(df.index) # MultiIndex([('ind_A', 1), # ('ind_A', 2), # ('ind_B', 3), # ('ind_B', 4), # ('ind_C', 5), # ('ind_C', 6)], # names=['index0', 'index1'])
データフレームからヘッダ、インデックスの抽出はそれぞれ.columns
、.index
だった。今回はMulti
ということで出力される配列はMulti
に対応したものとなっている。特定のlevelのデータだけ抽出するには.get_level_values
を使用する。
print(df.columns.get_level_values(0)) # Index(['col_A', 'col_A', 'col_B', 'col_B'], dtype='object') print(df.index.get_level_values(0)) # Index(['ind_A', 'ind_A', 'ind_B', 'ind_B', 'ind_C', 'ind_C'], dtype='object', name='index0')
ある特定の列に絞って抽出するにはdf['col_A']
のようにデータ名を使用する。
print(df['col_A']) # hdr0 hdr1 # index0 index1 # ind_A 1 0 1 # 2 4 5 # ind_B 3 8 9 # 4 12 13 # ind_C 5 16 17 # 6 20 21 print(df['col_A']['hdr1']) # index0 index1 # ind_A 1 1 # 2 5 # ind_B 3 9 # 4 13 # ind_C 5 17 # 6 21 # Name: hdr1, dtype: int64
さらにインデックスまで指定するなら.loc
。もちろん指定の仕方を変えると.iloc
も使用可能。
print(df['col_A']['hdr1'].loc['ind_A']) # index1 # 1 1 # 2 5 # Name: hdr1, dtype: int64 print(df['col_A']['hdr1'].loc[['ind_A']]) # index0 index1 # ind_A 1 1 # 2 5 # Name: hdr1, dtype: int64 print(df['col_A']['hdr1'].loc[['ind_A', 'ind_C']]) # index0 index1 # ind_A 1 1 # 2 5 # ind_C 5 17 # 6 21 # Name: hdr1, dtype: int64
データの書き出しと読み込み
file = './multicolumns.txt' df.to_csv(file, sep='\\t') # col_A col_A col_B col_B # hdr0 hdr1 hdr2 hdr3 # index0 index1 # ind_A 1 0 1 2 3 # ind_A 2 4 5 6 7 # ind_B 3 8 9 10 11 # ind_B 4 12 13 14 15 # ind_C 5 16 17 18 19 # ind_C 6 20 21 22 23
データフレームの書き出しは先ほど同様.to_csv
で可能。読み込みも指定しないとうまくいかない。
# 指定しないとインデックスもヘッダも設定されない df_read = pd.read_csv(file, sep='\\t') print(df_read) # Unnamed: 0 Unnamed: 1 col_A col_A.1 col_B col_B.1 # 0 NaN NaN hdr0 hdr1 hdr2 hdr3 # 1 index0 index1 NaN NaN NaN NaN # 2 ind_A 1 0 1 2 3 # 3 ind_A 2 4 5 6 7 # 4 ind_B 3 8 9 10 11 # 5 ind_B 4 12 13 14 15 # 6 ind_C 5 16 17 18 19 # 7 ind_C 6 20 21 22 23
ヘッダー、インデックスともに2段になっているのでheader=[0, 1], index_col=[0, 1]
としてヘッダーとインデックスの行番号を指定。
# インデックスとヘッダの設定 df_read = pd.read_csv(file, sep='\\t', header=[0, 1], index_col=[0, 1]) print(df_read) # col_A col_B # hdr0 hdr1 hdr2 hdr3 # index0 index1 # ind_A 1 0 1 2 3 # 2 4 5 6 7 # ind_B 3 8 9 10 11 # 4 12 13 14 15 # ind_C 5 16 17 18 19 # 6 20 21 22 23
複雑なデータをパッと見やすく
今回と以前の2記事にわたってpandasのMultiIndex
とMultiColumns
について解説した。今回この記事を書くきっかけが研究でパラメータが2種類あるデータを扱ったから。ちょうど今回のdf
のようなcol_A
とhdr0
の関係。どうせならわかりやすくtxtファイルに書き出したいなということで色々と試した。
このように簡単なデータフレームでは使用する機会がないが知っておくとここぞという時に使うことができるようなコードなので是非とも活用してより見やすいようにしていただければと思う。
関連記事
-
-
【pd&MultiIndex】pandasで複数インデックスの設定と書き読み
続きを見る
-
-
【PEP8&flake8】pythonにおけるPEP8とflake8
続きを見る
-
-
【辞書&pandas】dict{name: , val: {a: [~], b:[~]}}のpandas化
続きを見る
-
-
【辞書の結合】dictのマージ
続きを見る
-
-
【python&csv読み込み】pythonを使ってcsvを読み込み
続きを見る
-
-
【python3.7以降&dictのkeys】ネスト(入れ子)されたdictのkeys一覧をカッコで出力
続きを見る
-
-
【python&独学】独学である程度pythonを習得するマインド
続きを見る
-
-
【python&初級】のlistとかforとかifとかまとめ
続きを見る