ピボットテーブルとはエクセルで有名な機能の1つで馴染みの方も多いかもしれません。

複雑なデータ構造を一目で分かりやすくする目的でよく使われるもので、クロス集計したものをまとめたものとなります。 2つの要素間の相関が分かりやすく現れるので使いこなせると重宝するでしょう。例えば男女間での科目ごとの平均点といったものをひと目で把握することができます。

Pandasでも手軽にピボットテーブルを作成できるpivot_table関数が実装されています。

そこで本記事ではpivot_table関数の使い方について解説します。

pivot_table関数

APIドキュメント

まずはAPIドキュメントから見ていきます。

pandas.pivot_table(data, values=None, index=None, columns=None, aggfunc=’mean’, fill_value=None, margins=False, dropna=True, margins_name=’All’)

params:

パラメータ名 概要
data DataFrame ピボットテーブルを作成したいデータを選択します。
values カラム (省略可能)初期値None
集計を行う対象の列データを指定します。
index カラム,Grouper,配列
もしくはこれらのリスト
(省略可能)初期値None
行ラベルとして使用するものを指定します。
columns カラム,Grouper,配列
もしくはこれらのリスト
(省略可能)初期値None
列ラベルとして使用するものを指定します。
aggfunc 関数,関数のリスト,
辞書
(省略可能)初期値np.mean
データを集計する手法を指定します。
fill_value スカラー (省略可能)初期値None
欠損値を補完する値を指定します。
margins bool値 (省略可能)初期値False
Trueの時列ごとの合計と行ごとの合計を表示します。
dropna bool値 (省略可能)初期値True
全てのデータがNaN値である列データを集計に含まないようにします。
margins_name str (省略可能)初期値’All’
小計を表示する行と列のラベル名を指定します。

returns:

ピボットテーブルとなったDataFrameが返されます

引数を見てみると、色々と細かく指定できることが分かります。ただ1つ1つの意味が理解できていればこれらの引数を指定してあげるだけで手軽にピボットテーブルを作成することが可能です。

また、DataFrame.pivot_table関数も存在しています。data引数の有無だけの違いなので同一の関数と見なして問題ありません。

ピボットテーブルを作成する

とりあえずピボットテーブルを作成してみましょう。Kaggleのタイタニックのデータを使用します。

ダウンロードはこちらの公式サイトから

このデータから寄港地(Embarked)と生存したかどうか(Survived)の値で振り分けたものでの平均年齢を表示させます。

In [1]: import pandas as pd

In [2]: df = pd.read_csv("train.csv") # タイタニックの訓練データを読み込む

In [3]: df.columns # 列ラベルは12個
Out[3]:
Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
       'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'],
      dtype='object')

In [5]: pd.pivot_table(df, values="Age",index="Survived", columns="Embarked", aggfunc='mean')
Out[5]:
Embarked          C       Q          S
Survived                              
0         33.666667  30.325  30.203966
1         28.973671  22.500  28.113184

寄港地と生存したかどうかで分類した中での平均年齢を出すことができました。 Cはフランスのシェルブール,Qはアイルランドのクイーンズタウン,Sはイギリスのサウサンプトンとなっています。 Survivedの0は生き残れず、1は生き残れたことを表すラベルです。

データを見てみると、生き残った人々の方が平均年齢が若く、クイーンズタウンから乗り込んだ人の間では顕著な差が現れたと読み取れます。

複数要素を元に多層化させる

インデックスラベルとカラムラベルに選択できるデータは複数選択することが可能です。その場合、MultiIndexとして表示されます。

In [10]: pd.pivot_table(df,values="Age",index=["Pclass","Embarked"],columns="Survived")
Out[10]:
Survived                 0          1
Pclass Embarked                      
1      C         43.380952  35.905660
       Q         44.000000  33.000000
       S         43.845238  34.529091
2      C         29.500000  16.875000
       Q         57.000000  30.000000
       S         33.603659  26.822027
3      C         26.065217  13.940000
       Q         28.083333  19.500000
       S         26.484716  22.737705

データの個数をカウントする

では次にこれの人数の内訳を見てみます。aggfunc='count'とすることで要素数を計算できます。

In [17]: df.pivot_table(index='Survived',columns='Embarked',aggfunc='count') # df.pivot_tableでも使える
Out[17]:
         Age          Cabin        Fare ...   Sex SibSp          Ticket         
Embarked   C   Q    S     C  Q   S    C ...     S     C   Q    S      C   Q    S
Survived                                ...                                     
0         51  20  353    17  2  49   75 ...   427    75  47  427     75  47  427
1         79   8  201    52  2  80   93 ...   217    93  30  217     93  30  217

[2 rows x 30 columns]

valuesを指定しないとこのようにインデックスとカラムラベルに選択されていないデータ全てを対象にピボットテーブルが作成されます。

今回aggfunc='count'としているのでそれぞれのデータで有効なものがいくつあったかをカウントしています。 今はAgeでの内訳をみたいので、values="Age"とすれば求めるピボットテーブルが作成されます。

In [23]: df.pivot_table(values="Age",index='Survived',columns='Embarked',aggfunc='count')
Out[23]:
Embarked   C   Q    S
Survived             
0         51  20  353
1         79   8  201

列ごとと行ごとの合計を表示

margins=Trueにすればそれぞれのデータの合計を表示させることができます。

In [24]: df.pivot_table(values="Age",index="Survived",columns="Embarked",aggfunc="count",margins=True)
Out[24]:
Embarked    C   Q    S  All
Survived                   
0          51  20  353  424
1          79   8  201  288
All       130  28  554  712

デフォルトでは"All"と表示されます。ここの名前を変更することもできます。margins_nameで設定可能です。

In [25]: df.pivot_table(values="Age",index="Survived",columns="Embarked",aggfunc="count",margins=True, margins_name="total")
Out[25]:
Embarked    C   Q    S  total
Survived                     
0          51  20  353    424
1          79   8  201    288
total     130  28  554    712

複数の統計量を表示させる

今の2つの値を並べて表示させます。aggfunc=["mean","count"]のようにリストに収めれば可能です。

In [26]: df.pivot_table(values="Age",index='Survived',columns='Embarked',aggfunc=['count', 'mean'])
Out[26]:
         count                mean                   
Embarked     C   Q    S          C       Q          S
Survived                                             
0           51  20  353  33.666667  30.325  30.203966
1           79   8  201  28.973671  22.500  28.113184

関数を使って統計処理を指定する

他の関数を使って処理を指定することも可能です。 例としてNumPyの関数を使ってみます。

In [29]: df.pivot_table(values="Age",index='Survived',columns='Embarked',aggfunc=[np.mean,np.std]) # 平均と標準偏差を表示
Out[29]:
               mean                           std                      
Embarked          C       Q          S          C          Q          S
Survived                                                               
0         33.666667  30.325  30.203966  14.990553  19.212986  13.711031
1         28.973671  22.500  28.113184  15.530733   7.191265  14.812722

欠損値を補完

fill_valueで欠損値します。以下のようなCabinEmbarkedで仕分けた平均年齢を出してみます。

In [42]: pd.pivot_table(df,values="Age",index="Cabin",columns="Embarked")
Out[42]:
Embarked        C   Q          S
Cabin                           
A10          36.0 NaN        NaN
A16          48.0 NaN        NaN
A20          49.0 NaN        NaN
A23           NaN NaN  80.000000
A24           NaN NaN  31.000000
A26          56.0 NaN        NaN
...           ...  ..        ...
E77           NaN NaN  57.000000
E8            NaN NaN  30.000000
F G63         NaN NaN  42.000000
F G73         NaN NaN  22.000000
F2            NaN NaN  13.833333
F33           NaN NaN  29.000000
F4            NaN NaN   2.500000
G6            NaN NaN  14.750000
T             NaN NaN  45.000000

[133 rows x 3 columns]

欠損値が目立っているのがわかると思います。ここの値を0で埋めてみます。

fill_value=0で可能です。

In [44]: pd.pivot_table(df,values="Age",index="Cabin",columns="Embarked",fill_value=0)
Out[44]:
Embarked        C    Q          S
Cabin                            
A10          36.0  0.0   0.000000
A16          48.0  0.0   0.000000
A20          49.0  0.0   0.000000
A23           0.0  0.0  80.000000
A24           0.0  0.0  31.000000
A26          56.0  0.0   0.000000
...           ...  ...        ...
E77           0.0  0.0  57.000000
E8            0.0  0.0  30.000000
F G63         0.0  0.0  42.000000
F G73         0.0  0.0  22.000000
F2            0.0  0.0  13.833333
F33           0.0  0.0  29.000000
F4            0.0  0.0   2.500000
G6            0.0  0.0  14.750000
T             0.0  0.0  45.000000

[133 rows x 3 columns]

欠損値があるデータも表示させる

デフォルトではdropna=Trueとなっており全ての全ての行(列)において欠損値である列(行)データは表示されません。 dorpna=Falseにするとその設定を解除できます。

In [45]: pd.pivot_table(df,values="Age",index="Cabin",columns="Embarked",dropna=False)
Out[45]:
Embarked     C   Q          S
Cabin                        
A10       36.0 NaN        NaN
A14        NaN NaN        NaN
A16       48.0 NaN        NaN
A19        NaN NaN        NaN
A20       49.0 NaN        NaN
A23        NaN NaN  80.000000
A24        NaN NaN  31.000000
A26       56.0 NaN        NaN
...        ...  ..        ...
E77        NaN NaN  57.000000
E8         NaN NaN  30.000000
F E69      NaN NaN        NaN
F G63      NaN NaN  42.000000
F G73      NaN NaN  22.000000
F2         NaN NaN  13.833333
F33        NaN NaN  29.000000
F38        NaN NaN        NaN
F4         NaN NaN   2.500000
G6         NaN NaN  14.750000
T          NaN NaN  45.000000

[146 rows x 3 columns]

形状をみてみると行数が増加していることがわかります。

In [48]: pd.pivot_table(df,values="Age",index="Cabin",columns="Embarked",dropna=False).shape
Out[48]: (146, 3)

In [49]: pd.pivot_table(df,values="Age",index="Cabin",columns="Embarked").shape
Out[49]: (133, 3)

まとめ

今回はpivot_table関数の使い方について解説しました。ピボットテーブルはデータの見通しを良くする上で非常に強力な表となってきます。

agg_funcの指定の仕方で様々な数値データを呼び出すことが可能になるので、より使いこなしたい方はこの引数を使いこなせるように練習すると良いでしょう。

参考