データ分析の世界で表構造のデータを扱う時、大きく分けて、ワイド型(wide format)とロング型(long format)(もしくは、スタック型(stacked format))と呼ばれる2つの表のフォーマットを意識しておくとよい。 これら2つの違いは、キー(値を唯一識別するための項目)を列名として持つか(ワイド型)、1つの列の値として持つか(ロング型)の違いである。 下図の左がワイド型で右がロング型の例である。いずれも「売上」という値を識別するためのキー項目として企業名(A〜E)とQuater(1Q〜4Q)があり、どちらの表も内容的には変わらず、フォーマットが違うだけである。
ロング型の利点は、キー項目を列で持っているために、groupby()
などのキー単位の処理を伴う処理がやりやすいことにある。
一方でワイド型は、回帰モデルなどの入力データで利用されるフォーマットである(1行1サンプル)。
前処理はロング型で行い、モデル構築やデータ内容の表示といった分析の最終工程でワイド型が利用されるのが典型的なパターンである。
1. ワイド型-ロング型の変換(pivot, stack, unstack)
2. 集計を伴うpivot(pivot_table)
3. 件数集計(cross_table)
4. ダミー変数の生成(get_dummies)
stack型とmatrix型の表構造を相互変換する。
d = pd.DataFrame( {'r':['A', 'A', 'A', 'B', 'B', 'B'], 'c':['x', 'y', 'z', 'x', 'y', 'z'], 'v':[40, 50, 60, 70, 80, 90]} )
no. | 実行コード | 入力 | 出力 | 備考 |
---|---|---|---|---|
1-1 | dd = d.pivot(index='r', columns='c', values='v') print(dd) |
![]() |
![]() |
pivot()は、stack形式のデータをmatrix形式のデータに変換する。indexで行ラベル、columnsで列ラベル、valuesで値となる列名を指定する。 ただし、同じ行ラベル-列ラベルがあればエラーとなることに注意する。 |
1-2 | # 1-1を実行した後に実行できる。 sr = dd.stack() print(sr) |
![]() |
![]() |
stack()は、全ての列名を値としてstack形式に変換する。ちょうどpivot()の逆の動きをする。 |
1-3 | # 1-2を実行した後に実行できる。 print(sr.unstack()) |
![]() |
![]() |
unstack()は、行のマルチインデックスの内側の列をpivot()のように列に展開する。 multi-indexの場合はunstack()を使うことでpivot()が実現できると考えればよい。 |
1-4 | # 1-2を実行した後に実行できる。 sr.name = 'v' print(sr.reset_index()) |
![]() |
![]() |
結果srは行ラベルがマルチインデクスのSeriesなので、名前を設定してインデックスをresetすれば、完全に元のデータdに戻る。 |
pivot()は表の構造を変換するだけであるのに対して、pivot_tableは値の集計を伴うpivotと考えればよい。
pivot()で使った入力データとは、行(r)-列(r)の値に重複がある点が異なる。 A-xとB-yは2件存在する。
d = pd.DataFrame( {'r':['A', 'A', 'A', 'B', 'B', 'B', 'C'], 'c':['x', 'x', 'y', 'x', 'y', 'y', 'y'], 'v':[40, 50, 60, 70, 80, 90, 100]} )
no. | 実行コード | 入力 | 出力 | 備考 |
---|---|---|---|---|
2-1 | dd = d.pivot_table( index='r', columns='c', values='v', aggfunc=np.sum) print(dd) |
![]() |
![]() |
pivot()と同様に、stack形式のデータをmatrix形式のデータに変換し値を集計する。 indexで行ラベル、columnsで列ラベル、valuesで値となる列名を指定する。 そして、同じ行ラベル-列ラベルの値をどのように集計するかをaggfunc=で指定する(デフォルトはnp.mean)。 ここではnp.sum(合計)関数で集計している。matrixにしたときに、行ラベル-列ラベルの値が存在しなければNAとなる。 |
2-2 | dd = d.pivot_table( index='r', columns='c', values='v', aggfunc=np.sum, fill_value=0) print(dd) |
![]() |
![]() |
fill_value=を指定すれば、NAがその値で出力される。 |
2-3 | dd = d.pivot_table( index='r', columns='c', values='v', aggfunc=np.sum, fill_value=0, margins=True) print(dd) |
![]() |
![]() |
margins=Trueとすれば周辺の集約結果が追加される。 |
2-4 | dd = d.pivot_table( index='r', columns='c', values='v', aggfunc=['count', 'sum', np.mean, np.median, np.min, np.argmax], fill_value=0) print(dd) |
![]() |
![]() |
複数の集約関数を指定すれば列がmulti-indexとなって全ての集約関数の結果が出力される。 |
クロス集計表を作成する。stack型のデータから行-列の値の組み合わせの件数をカウントする。pivot()やpivot_table()と違い、pandasメソッドであり、行と列となる2つのSeriesをパラメータとして与える。
d = pd.DataFrame( {'r':['A', 'A', 'A', 'B', 'B', 'B', 'C'], 'c':['x', 'x', 'y', 'x', 'y', 'y', 'y'], 'v':[40, 50, 60, 70, 80, 90, 100]} )
no. | 実行コード | 入力 | 出力 | 備考 |
---|---|---|---|---|
3-1 | dd = pd.crosstab(d['r'], d['c']) print(dd) |
![]() |
![]() |
行と列を表す2つのSeriesを与え、その件数をカウントする。 |
3-2 | dd = pd.crosstab(d['r'], d['c'], margins=True) print(dd) |
![]() |
![]() |
margins=Trueで行と列の件数合計を出力する。 |
3-3 | dd = pd.crosstab(d['r'], d['c'], normalize=True) print(dd) |
![]() |
![]() |
normalize=Trueにて全体に対する構成比を出力する。 |
3-4 | dd = pd.crosstab(d['r'], d['c'], normalize='index') print(dd) |
![]() |
![]() |
normalize='index'で行に対する構成比となる。 |
3-5 | dd = pd.crosstab(d['r'], d['c'], normalize='columns') print(dd) |
![]() |
![]() |
normalize='columns'にて列に対する構成比を出力する。 |
3-6 | dd = pd.crosstab(d['r'], d['c'], values=d['v'], aggfunc=np.sum) print(dd) |
![]() |
![]() |
values=とaggfunc=を指定することでpivot_table()と同様にvaluesの列を集約して出力する。 |
d = pd.DataFrame( {'r':['A', 'A', 'A', 'B', 'B', 'B', 'C'], 'c':['x', 'x', 'y', 'x', 'y', 'y', 'y'], 'v':[40, 50, 60, 70, 80, 90, 100]} )
no. | 実行コード | 入力 | 出力 | 備考 |
---|---|---|---|---|
4-1 | dd = pd.get_dummies(d['r']) print(dd) |
![]() |
![]() |
r列の値A,B,Cをdummy化する。A,B,Cを列にして、それぞれの値の行は1に、それ以外は0を出力する。 |
4-2 | dd = pd.get_dummies(d['r'], prefix='r') print(dd) |
![]() |
![]() |
prefix=を指定することで、その文字列が列名の頭に追加される。 |
4-3 | dd = pd.get_dummies(pd.cut(d['v'], [30, 60, 80])) print(dd) |
![]() |
![]() |
pd.cut()と組み合わせることで、数値変数をdummy化できる。 |