Pandasでは列データを行データへと変換するstack
関数と逆に行データを列データへと変換するunstack
関数が実装されています。
ちょっとした見た目を変更する時もかなり手軽に出来るようになるので使ってみることをオススメします。
MultiIndexとなっているDataFrameに対して分析したい対象が見やすくなるように整形することが容易になります。
本記事ではstack関数とunstack関数の使い方を解説します。
stack関数
まずはstack
関数から解説します。stack関数を使うことで列から行への変換をすることができます。
APIドキュメント
pandas.DataFrame.stack(level=-1, dropna=True)
params:
パラメータ名 | 型 | 概要 |
---|---|---|
level | int,str もしくはリスト |
(省略可能)初期値-1 どの階層のカラムラベルをインデックスラベルに移動させるかを選択します。デフォルトでは最も内側(level=-1)のカラムラベルを移動させます。複数階層選択することも可能です。 |
dropna | bool値 | (省略可能)初期値True 変形した際に生じる欠損値しかない行データを削除するかどうかを指定します。 |
returns:
変形されたDataFrameまたはSeries
引数は合わせて2つほどあります。
1つは移動させるカラムラベルの階層を指定するlevel
引数ともう1つは移動させた際に発生する欠損値を含む行を取り除くかどうかを指定するdropna
引数です。
変形した結果1つの列データしか残らない場合、Seriesになります。 使いながら覚えた方が早いと思うので手を動かしていきます。
カラムラベルが単一列のとき
まずは以下のCSVファイルのデータを利用します。
,basic,basic,basic,score,score,score
,class,grade,state,math,English,science
Alice,A,2,NY,85,69,50
Bob,B,1,DC,92,93,65
Catharine,B,1,DC,85,55,60
David,B,2,PA,70,89,79
Ellen,A,3,NY,98,86,67
Frank,A,3,DC,84,61,50
George,B,1,OH,97,95,62
Helen,A,2,OR,87,92,67
このファイルをsample_stack.csv
として保存します。以下のリンクからもダウンロードできます。
まずはカラムラベルが単一列(マルチインデックスではない場合)の時を試したいので一番上の行は読み飛ばして読み込みます。
In [1]: import pandas as pd
In [5]: df_single = pd.read_csv("sample_stack.csv",skiprows=[0], index_col=0)
In [7]: df_single
Out[7]:
class grade state math English science
Alice A 2 NY 85 69 50
Bob B 1 DC 92 93 65
Catharine B 1 DC 85 55 60
David B 2 PA 70 89 79
Ellen A 3 NY 98 86 67
Frank A 3 DC 84 61 50
George B 1 OH 97 95 62
Helen A 2 OR 87 92 67
ではこのDataFrameにstack
関数を適用させてみます。カラムラベルが単層構造(MultiIndexではない)ので、返り値はSeriesになります。少々データが多めなので長めのデータとなります。
In [8]: df_single.stack()
Out[8]:
Alice class A
grade 2
state NY
math 85
English 69
science 50
Bob class B
grade 1
state DC
math 92
English 93
science 65
Catharine class B
grade 1
state DC
math 85
English 55
science 60
David class B
grade 2
state PA
math 70
English 89
science 79
Ellen class A
grade 3
state NY
math 98
English 86
science 67
Frank class A
grade 3
state DC
math 84
English 61
science 50
George class B
grade 1
state OH
math 97
English 95
science 62
Helen class A
grade 2
state OR
math 87
English 92
science 67
dtype: object
この時インデックスラベルはMultiIndexオブジェクトとなっており、名前ー情報の種類
となっています。
複数列構造(MultiIndex)のとき
次は先ほどのデータのカラムラベルをMultiIndexオブジェクトとして読み込みます。
In [11]: df_multi = pd.read_csv("sample_stack.csv",index_col=0,header=[0,1])
In [12]: df_multi
Out[12]:
basic score
class grade state math English science
Alice A 2 NY 85 69 50
Bob B 1 DC 92 93 65
Catharine B 1 DC 85 55 60
David B 2 PA 70 89 79
Ellen A 3 NY 98 86 67
Frank A 3 DC 84 61 50
George B 1 OH 97 95 62
Helen A 2 OR 87 92 67
このまま適用してみます。 すると、下の階層のカラムラベルが移動することになります。
In [13]: df_multi.stack()
Out[13]:
basic score
Alice English NaN 69.0
class A NaN
grade 2 NaN
math NaN 85.0
science NaN 50.0
state NY NaN
Bob English NaN 93.0
class B NaN
grade 1 NaN
math NaN 92.0
science NaN 65.0
state DC NaN
Catharine English NaN 55.0
class B NaN
grade 1 NaN
math NaN 85.0
science NaN 60.0
state DC NaN
David English NaN 89.0
class B NaN
grade 2 NaN
math NaN 70.0
science NaN 79.0
state PA NaN
Ellen English NaN 86.0
class A NaN
grade 3 NaN
math NaN 98.0
science NaN 67.0
state NY NaN
Frank English NaN 61.0
class A NaN
grade 3 NaN
math NaN 84.0
science NaN 50.0
state DC NaN
George English NaN 95.0
class B NaN
grade 1 NaN
math NaN 97.0
science NaN 62.0
state OH NaN
Helen English NaN 92.0
class A NaN
grade 2 NaN
math NaN 87.0
science NaN 67.0
state OR NaN
stackする階層を指定する
次はlevel
引数を使ってstackする階層を指定してみます。
デフォルトでは最も内側(カラムラベルでなら最も下とも表現できます)の層を移動させています。
level=0
だと一番外側で、level=1
だと1つ内側になります。
In [14]: df_multi.stack(level=0) # 一番外側の階層が移動する
Out[14]:
English class grade math science state
Alice basic NaN A 2.0 NaN NaN NY
score 69.0 NaN NaN 85.0 50.0 NaN
Bob basic NaN B 1.0 NaN NaN DC
score 93.0 NaN NaN 92.0 65.0 NaN
Catharine basic NaN B 1.0 NaN NaN DC
score 55.0 NaN NaN 85.0 60.0 NaN
David basic NaN B 2.0 NaN NaN PA
score 89.0 NaN NaN 70.0 79.0 NaN
Ellen basic NaN A 3.0 NaN NaN NY
score 86.0 NaN NaN 98.0 67.0 NaN
Frank basic NaN A 3.0 NaN NaN DC
score 61.0 NaN NaN 84.0 50.0 NaN
George basic NaN B 1.0 NaN NaN OH
score 95.0 NaN NaN 97.0 62.0 NaN
Helen basic NaN A 2.0 NaN NaN OR
score 92.0 NaN NaN 87.0 67.0 NaN
In [15]: df_multi.stack(level=1) # 1つ内側の階層が移動する
Out[15]:
basic score
Alice English NaN 69.0
class A NaN
grade 2 NaN
math NaN 85.0
science NaN 50.0
state NY NaN
Bob English NaN 93.0
class B NaN
grade 1 NaN
math NaN 92.0
science NaN 65.0
state DC NaN
Catharine English NaN 55.0
class B NaN
grade 1 NaN
math NaN 85.0
science NaN 60.0
state DC NaN
David English NaN 89.0
class B NaN
grade 2 NaN
math NaN 70.0
science NaN 79.0
state PA NaN
Ellen English NaN 86.0
class A NaN
grade 3 NaN
math NaN 98.0
science NaN 67.0
state NY NaN
Frank English NaN 61.0
class A NaN
grade 3 NaN
math NaN 84.0
science NaN 50.0
state DC NaN
George English NaN 95.0
class B NaN
grade 1 NaN
math NaN 97.0
science NaN 62.0
state OH NaN
Helen English NaN 92.0
class A NaN
grade 2 NaN
math NaN 87.0
science NaN 67.0
state OR NaN
リストで両方指定することも可能です。
In [21]: df_multi.stack(level=[0,1])
Out[21]:
Alice basic class A
grade 2
state NY
score math 85
science 50
Bob basic class B
grade 1
state DC
score math 92
science 65
Catharine basic class B
grade 1
state DC
score math 85
science 60
David basic class B
grade 2
state PA
score math 70
science 79
Ellen basic class A
grade 3
state NY
score math 98
science 67
Frank basic class A
grade 3
state DC
score math 84
science 50
George basic class B
grade 1
state OH
score math 97
science 62
Helen basic class A
grade 2
state OR
score math 87
science 67
dtype: object
欠損値も表示させる
dropna=False
にすると移動後に新たに生じる組み合わせ(例えばbasicとEnglish)は基本NaN値があてがわれます。この結果両方とも欠損値となった場合、省略するかどうかを指定します。
一旦英語の成績を全部NaNに置き換えます。
In [16]: import numpy as np
In [17]: df_multi["score","English"] = np.nan
In [18]: df_multi
Out[18]:
basic score
class grade state math English science
Alice A 2 NY 85 NaN 50
Bob B 1 DC 92 NaN 65
Catharine B 1 DC 85 NaN 60
David B 2 PA 70 NaN 79
Ellen A 3 NY 98 NaN 67
Frank A 3 DC 84 NaN 50
George B 1 OH 97 NaN 62
Helen A 2 OR 87 NaN 67
次にこのDataFrameに対してstack
関数を適用してみます。
In [19]: df_multi.stack() # デフォルトだとEnglishの部分は全部削除される
Out[19]:
basic score
Alice class A NaN
grade 2 NaN
math NaN 85.0
science NaN 50.0
state NY NaN
Bob class B NaN
grade 1 NaN
math NaN 92.0
science NaN 65.0
state DC NaN
Catharine class B NaN
grade 1 NaN
math NaN 85.0
science NaN 60.0
state DC NaN
David class B NaN
grade 2 NaN
math NaN 70.0
science NaN 79.0
state PA NaN
Ellen class A NaN
grade 3 NaN
math NaN 98.0
science NaN 67.0
state NY NaN
Frank class A NaN
grade 3 NaN
math NaN 84.0
science NaN 50.0
state DC NaN
George class B NaN
grade 1 NaN
math NaN 97.0
science NaN 62.0
state OH NaN
Helen class A NaN
grade 2 NaN
math NaN 87.0
science NaN 67.0
state OR NaN
In [20]: df_multi.stack(dropna=False) # FalseにするとEnglishの部分は削除されない
Out[20]:
basic score
Alice English NaN NaN
class A NaN
grade 2 NaN
math NaN 85.0
science NaN 50.0
state NY NaN
Bob English NaN NaN
class B NaN
grade 1 NaN
math NaN 92.0
science NaN 65.0
state DC NaN
Catharine English NaN NaN
class B NaN
grade 1 NaN
math NaN 85.0
science NaN 60.0
state DC NaN
David English NaN NaN
class B NaN
grade 2 NaN
math NaN 70.0
science NaN 79.0
state PA NaN
Ellen English NaN NaN
class A NaN
grade 3 NaN
math NaN 98.0
science NaN 67.0
state NY NaN
Frank English NaN NaN
class A NaN
grade 3 NaN
math NaN 84.0
science NaN 50.0
state DC NaN
George English NaN NaN
class B NaN
grade 1 NaN
math NaN 97.0
science NaN 62.0
state OH NaN
Helen English NaN NaN
class A NaN
grade 2 NaN
math NaN 87.0
science NaN 67.0
state OR NaN
unstack関数
次にstack
関数と逆の操作。つまり、インデックスラベルをカラムラベルに移動させるunstack
関数の使い方について解説します。
行うこと自体が逆になるだけなので、基本的な考え方はstack
関数とほぼ同一です。
APIドキュメント
pandas.DataFrame.stack(level=-1, fill_values=None)
params:
パラメータ名 | 型 | 概要 |
---|---|---|
level | int,str もしくはリスト |
(省略可能)初期値-1 どの階層のカラムラベルをインデックスラベルに移動させるかを選択します。デフォルトでは最も内側(level=-1)のカラムラベルを移動させます。複数階層選択することも可能です。 |
fill_value | 値 | (省略可能)初期値None 変形した際に欠損値が発生するとき、どんな値で埋め合わせをするかを指定します。 |
returns:
変形されたDataFrameまたはSeries
引数をみてみると先ほどあったdropna
の代わりにfill_value
が追加されています。
なぜこうしたのかは今ひとつ不明ですがfill_value
があることでunsatck
関数では新たに生成された欠損値に対する補完を行う値を指定ができます。
インデックスラベルが単層のとき
先ほどと同じデータを使います。NaN値もそのまま残しておきます。
In [22]: df_multi
Out[22]:
basic score
class grade state math English science
Alice A 2 NY 85 NaN 50
Bob B 1 DC 92 NaN 65
Catharine B 1 DC 85 NaN 60
David B 2 PA 70 NaN 79
Ellen A 3 NY 98 NaN 67
Frank A 3 DC 84 NaN 50
George B 1 OH 97 NaN 62
Helen A 2 OR 87 NaN 67
unstack
関数を適用させます。
行→列へとデータが変換されます。
ただ、今回インデックスラベルが単層なので変形後のデータはSeriesとなるので横長ではなく縦長の見た目のデータとなります。
In [23]: df_multi.unstack()
Out[23]:
basic class Alice A
Bob B
Catharine B
David B
Ellen A
Frank A
George B
Helen A
grade Alice 2
Bob 1
Catharine 1
David 2
Ellen 3
Frank 3
George 1
Helen 2
state Alice NY
Bob DC
Catharine DC
David PA
Ellen NY
Frank DC
George OH
Helen OR
score math Alice 85
Bob 92
Catharine 85
David 70
Ellen 98
Frank 84
George 97
Helen 87
English Alice NaN
Bob NaN
Catharine NaN
David NaN
Ellen NaN
Frank NaN
George NaN
Helen NaN
science Alice 50
Bob 65
Catharine 60
David 79
Ellen 67
Frank 50
George 62
Helen 67
dtype: object
多層構造(MultiIndex)のとき
もう一度csvファイルから読み込みます。今度は名前とクラスをインデックスラベルに設定します。
In [39]: df_multi_index = pd.read_csv("sample_stack.csv",index_col=[0,1],header=[0,1])
In [40]: df_multi_index
Out[40]:
basic score
grade state math English science
Alice A 2 NY 85 69 50
Bob B 1 DC 92 93 65
Catharine B 1 DC 85 55 60
David B 2 PA 70 89 79
Ellen A 3 NY 98 86 67
Frank A 3 DC 84 61 50
George B 1 OH 97 95 62
Helen A 2 OR 87 92 67
In [41]: df_multi_index.unstack() # クラス部分がunstackされる
Out[41]:
basic score
grade state math English science
A B A B A B A B A B
Alice 2.0 NaN NY NaN 85.0 NaN 69.0 NaN 50.0 NaN
Bob NaN 1.0 NaN DC NaN 92.0 NaN 93.0 NaN 65.0
Catharine NaN 1.0 NaN DC NaN 85.0 NaN 55.0 NaN 60.0
David NaN 2.0 NaN PA NaN 70.0 NaN 89.0 NaN 79.0
Ellen 3.0 NaN NY NaN 98.0 NaN 86.0 NaN 67.0 NaN
Frank 3.0 NaN DC NaN 84.0 NaN 61.0 NaN 50.0 NaN
George NaN 1.0 NaN OH NaN 97.0 NaN 95.0 NaN 62.0
Helen 2.0 NaN OR NaN 87.0 NaN 92.0 NaN 67.0 NaN
In [42]: df_multi_index.unstack(level=0) # 名前がunstackされる
Out[42]:
basic ... score
grade ... science
Alice Bob Catharine David Ellen ... David Ellen Frank George Helen
A 2.0 NaN NaN NaN 3.0 ... NaN 67.0 50.0 NaN 67.0
B NaN 1.0 1.0 2.0 NaN ... 79.0 NaN NaN 62.0 NaN
[2 rows x 40 columns]
fill_valueで欠損値の補完
fill_value
引数で欠損値の補完を行うことができます。
今回は"missing"
で穴埋めしてみます。
In [43]: df_multi_index.unstack(fill_value="missing")
Out[43]:
basic ... score
grade state ... English science
A B A ... B A B
Alice 2 missing NY ... missing 50 missing
Bob missing 1 missing ... 93 missing 65
Catharine missing 1 missing ... 55 missing 60
David missing 2 missing ... 89 missing 79
Ellen 3 missing NY ... missing 67 missing
Frank 3 missing DC ... missing 50 missing
George missing 1 missing ... 95 missing 62
Helen 2 missing OR ... missing 67 missing
[8 rows x 10 columns]
まとめ
今回はラベルを移動させるstack
、unstack
関数の使い方についてまとめました。
-
stack
は列→行 -
unstack
は行→列
となります。
MultiIndexと一緒に使いこなせるようになるとデータの見た目を簡単に変えることができます。