Pandasのpivot_tableの全引数を解説

概要

カテゴリカル変数と連続変数の関係の分析に特に有効で、Excelでもよく使うピボットテーブルの機能ですが、Pythonのpandasでもpivot_tableというメソッドを使うことが出来ます。本記事ではこのpivot_tableの全引数の効果を検証しました。なお、pandasのバージョンは0.23.4を使っています。

引数一覧

pandasのpivot_tableには以下の7引数があります。以降、それぞれについて説明していきます。

  1. values
  2. index
  3. columns
  4. aggfunc
  5. fill_value
  6. dropna
  7. margins_name

また、データとしてはirisを使用しました。

df = pd.read_csv("iris.csv", index_col=0)
df.head()

データ分析の定番データセットですね。(全150件の最初の5件を表示しています)

   SepalLength  SepalWidth  PetalLength  PetalWidth         Name
0          5.1         3.5          1.4         0.2  Iris-setosa
1          4.9         3.0          1.4         0.2  Iris-setosa
2          4.7         3.2          1.3         0.2  Iris-setosa
3          4.6         3.1          1.5         0.2  Iris-setosa
4          5.0         3.6          1.4         0.2  Iris-setosa

以降で引数を検討していきますが、何も指定しないとエラー(ValueError: No group keys passed!)が出るため、indexにNameを指定しておくことにします。

values

集計するカラムを指定するパラメータ。カラム名を指定するとその列のデータが集計されます。aggfuncの項で説明しますが、デフォルトではmeanが計算されます。

1変数を対象に計算する場合

1列を対象とする場合は、カラム名を直接渡すかリスト形式で渡す。

SepalLengthを対象に集計する場合。

df.pivot_table(index="Name", values='SepalLength')

Nameに含まれるカテゴリごとにSepalLengthの平均値が計算された。

                 SepalLength
Name                        
Iris-setosa            5.006
Iris-versicolor        5.936
Iris-virginica         6.588

リストで指定することも可能。

df.pivot_table(index="Name", values=['SepalLength'])

同様の計算結果が得られた。

                 SepalLength
Name                        
Iris-setosa            5.006
Iris-versicolor        5.936
Iris-virginica         6.588

2変数以上を対象に計算する場合

2列以上を対象とする場合は、対象のカラム名のリスト形式で渡す。

SepalLengthとSepalWidthを対象に集計する場合。

df.pivot_table(index="Name", values=['SepalLength', 'SepalWidth'])

Nameに含まれるカテゴリごとにSepalLengthとSepalWidthの平均値が計算された。

                 SepalLength  SepalWidth
Name                                    
Iris-setosa            5.006       3.418
Iris-versicolor        5.936       2.770
Iris-virginica         6.588       2.974

与えるカラム名の順番を変えても出力の並びが変わらないことには注意。

df.pivot_table(index="Name", values=['SepalWidth', 'SepalLength'])

SepalWidthを先にしても、出力はSepalLengthが先のまま。

                 SepalLength  SepalWidth
Name                                    
Iris-setosa            5.006       3.418
Iris-versicolor        5.936       2.770
Iris-virginica         6.588       2.974

全変数を対象に計算する場合

カラム名を指定するのが面倒な場合など、全変数を対象にしたい場合はNone(デフォルト値)を与えればよい。

df.pivot_table(index="Name", values=None)

Nameに含まれるカテゴリごとに、集計可能な全変数の平均値が計算された。

                 PetalLength  PetalWidth  SepalLength  SepalWidth
Name                                                             
Iris-setosa            1.464       0.244        5.006       3.418
Iris-versicolor        4.260       1.326        5.936       2.770
Iris-virginica         5.552       2.026        6.588       2.974

index

グルーピングする変数(行方向)を指定する引数。指定した変数の中のユニーク値で集約されるため、カテゴリ変数を指定するのが基本といえます。デフォルトはNone(なし)ですが、最低でもindexかcolumnsのどちらか一方を指定しないと前述したエラーが出ます。valueと同様にカラム名やリストが指定できるほか、時系列を対象とした場合にはGrouperで月集約等を指定することができます。

1変数を対象にグルーピングする場合

上記までで実施していますので省略します。

2変数以上を対象にグルーピングする場合

リストで渡すことで、2変数以上の組み合わせでグルーピングすることができます。

SepalLength_cutというカテゴリ変数を作っておき、本変数とNameで集約してみます。

#SepalLength_cutというカテゴリ変数を作っておく。
df['SepalLength_cut'] = pd.cut(df['SepalLength'], 5)
df.pivot_table(index=["Name", 'SepalLength_cut'], values="PetalLength")

NameとSepalLength_cutの組み合わせでグルーピングされた。

                                 PetalLength
Name            SepalLength_cut             
Iris-setosa     (4.296, 5.02]       1.428571
                (5.02, 5.74]        1.523810
                (5.74, 6.46]        1.200000
Iris-versicolor (4.296, 5.02]       3.366667
                (5.02, 5.74]        4.005556
                (5.74, 6.46]        4.435000
                (6.46, 7.18]        4.677778
Iris-virginica  (4.296, 5.02]       4.500000
                (5.02, 5.74]        4.950000
                (5.74, 6.46]        5.257143
                (6.46, 7.18]        5.540000
                (7.18, 7.9]         6.336364

NameとSepalLength_cutの順番を入れ替えて実行。

df.pivot_table(index=["Name", 'SepalLength_cut'], values="PetalLength")

SepalLength_cut、Nameの順番でグルーピングされた。(valuesと異なり順番が反映される。)

                                 PetalLength
SepalLength_cut Name                        
(4.296, 5.02]   Iris-setosa         1.428571
                Iris-versicolor     3.366667
                Iris-virginica      4.500000
(5.02, 5.74]    Iris-setosa         1.523810
                Iris-versicolor     4.005556
                Iris-virginica      4.950000
(5.74, 6.46]    Iris-setosa         1.200000
                Iris-versicolor     4.435000
                Iris-virginica      5.257143
(6.46, 7.18]    Iris-versicolor     4.677778
                Iris-virginica      5.540000
(7.18, 7.9]     Iris-virginica      6.336364

Grouperを指定する場合

本データは時系列ではないので、仮の時系列データを追加して試してみました。
Reshaping and Pivot Tablesを参考にしています。

#Timeという時系列データを作っておく。
df['Time'] = pd.date_range(start='2018/1/1', freq='1d', periods=df.shape[0])
#TImeに対して、1か月ごとに集約
df.pivot_table(values='SepalLength', index=pd.Grouper(freq='M', key='Time'))

仮で作成したデータの月ごとに集約されました。resampleを使う手間を省くことができるかもしれませんね。

            SepalLength
Time                   
2018-01-31     5.019355
2018-02-28     5.375000
2018-03-31     5.954839
2018-04-30     6.253333
2018-05-31     6.606667

columns

グルーピングする変数(列方向)を指定する引数。indexと同様に、指定した変数の中のユニーク値で集約されるため、カテゴリ変数を指定するのが基本といえます。デフォルトはNone(なし)ですが、最低でもindexかcolumnsのどちらか一方を指定しないと前述したエラーが出ます。

1変数を対象にグルーピングする場合

indexと同様ですが、indexとcolumnsを両方指定した場合を実施しておきます。

df.pivot_table(values='SepalLength', index='SepalLength_cut', columns='Name')

SepalLengthで行方向を、Nameで列方向にグルーピングしました。まさにピボットテーブルという使い方ですね。

Name             Iris-setosa  Iris-versicolor  Iris-virginica
SepalLength_cut                                              
(4.296, 5.02]       4.764286         4.966667        4.900000
(5.02, 5.74]        5.290476         5.538889        5.650000
(5.74, 6.46]        5.800000         6.085000        6.176190
(6.46, 7.18]             NaN         6.722222        6.726667
(7.18, 7.9]              NaN              NaN        7.509091

2変数以上を対象にグルーピングする場合

indexと同様のため省略。

Grouperを指定する場合

indexと同様のため省略。

aggfunc

集計する関数を指定するパラメータ。デフォルトはmean(平均値)。指定の方法により、単独の関数をしていたり、複数の関数を指定したり、変数ごとに関数を指定したり、といったことができます。関数はデータ以外の引数を取るものはそのまま使うことはできませんが、自作の関数でラッピングすることで使うことが可能です。

1つの関数を指定する場合

関数を直接、又はリストで与えることで動作します。

例えば標準偏差を計算する場合、関数にnp.std又は[np.std]を指定します。

df.pivot_table(index='Name', aggfunc=np.std)

各説明変数の標準偏差が計算できました。

                 PetalLength  PetalWidth  SepalLength  SepalWidth
Name                                                             
Iris-setosa         0.173511    0.107210     0.352490    0.381024
Iris-versicolor     0.469911    0.197753     0.516171    0.313798
Iris-virginica      0.551895    0.274650     0.635880    0.322497

2つ以上の関数を指定する場合

関数をリストで与えることで動作します。

例えば、中央値とデータ個数で指定する場合、関数に[np.median, len]を指定します。

df.pivot_table(index='Name', aggfunc=[np.median, len])

各説明変数の中央値とデータ個数が計算できました。

                     median               ...             len           
                PetalLength PetalWidth    ...     SepalLength SepalWidth
Name                                      ...                           
Iris-setosa            1.50        0.2    ...            50.0       50.0
Iris-versicolor        4.35        1.3    ...            50.0       50.0
Iris-virginica         5.55        2.0    ...            50.0       50.0

変数ごとに適用する関数を変える場合

変数名と関数を辞書の形で渡すことで動作します。

例えば、PetalLengthは平均値、PetalWidthは中央値と標準偏差という場合は、以下のように指定します。

df.pivot_table(index='Name', aggfunc={"PetalLength":np.mean, "PetalWidth":[np.median, np.std]})

それぞれの変数ごとに関数が適用されました。データの加工方法が決まっている時には使える方法かもしれないですね。

                PetalLength PetalWidth          
                       mean     median       std
Name                                            
Iris-setosa           1.464        0.2  0.107210
Iris-versicolor       4.260        1.3  0.197753
Iris-virginica        5.552        2.0  0.274650

引数を取る関数を指定する場合

np.quantileのような、データ以外に引数を取る関数を使う場合、そのまま指定してもエラーが出てしまいます。

df.pivot_table(index='Name', aggfunc=np.quantile)

q(何パーセントの値を取るのか)が指定されていないというエラー。

TypeError: quantile() missing 1 required positional argument: 'q'

苦し紛れに変数を渡すこともできません。

df.pivot_table(index='Name', aggfunc=np.quantile(q=0.1))

エラーが出てしまいます。

TypeError: quantile() missing 1 required positional argument: 'a'

このような場合は関数を自作してやる必要があります。

10パーセント値を計算する関数にラッピングする。

def quantile_10p(x):
    return np.quantile(x, q=0.1)
df.pivot_table(index='Name', aggfunc=quantile_10p)

エラーが出ずに計算できた。

                 PetalLength  PetalWidth  SepalLength  SepalWidth
Name                                                             
Iris-setosa             1.30        0.10         4.59        3.00
Iris-versicolor         3.59        1.00         5.38        2.30
Iris-virginica          4.90        1.79         5.80        2.59

fill_value

集計結果に欠損がある場合に埋める値を指定するパラメータ。デフォルトはNone(埋めない)。pivot_tableの処理後にfillna(x)をするのと同様です。

columnsの項で検討した例で、fill_valueに1を指定してみます。

df.pivot_table(values='SepalLength', index='SepalLength_cut', columns='Name', fill_value=1)

NaNになっていた部分が1で埋められました。

Name             Iris-setosa  Iris-versicolor  Iris-virginica
SepalLength_cut                                              
(4.296, 5.02]       4.764286         4.966667        4.900000
(5.02, 5.74]        5.290476         5.538889        5.650000
(5.74, 6.46]        5.800000         6.085000        6.176190
(6.46, 7.18]        1.000000         6.722222        6.726667
(7.18, 7.9]         1.000000         1.000000        7.509091

margins

グルーピング変数での集計結果の他に全体の集計結果を追加したいときに使うパラメータ。デフォルトはFalse(全体の集計はしない)。

Trueを指定すると全体の集計をしてくれます。地味に知らないと不便な引数ですね。

df.pivot_table(index='Name', values='SepalLength', margins=True)

Allという列が追加され、全体の平均が計算されている。

                 SepalLength
Name                        
Iris-setosa         5.006000
Iris-versicolor     5.936000
Iris-virginica      6.588000
All                 5.843333

dropna

全ての値がNaNのカラムがある場合に、計算対象から外すかを指定するパラメータ。デフォルトはTrue(計算しない)。

あまり用途はなさそうですが一応検証します。

#SepalLengthを全てNaNにする。
df.iloc['SepalLength'] = np.NaN
df.pivot_table(index='Name', dropna=False)

全てがNaNのSepalLengthも計算された。

                 PetalLength  PetalWidth  SepalLength  SepalWidth
Name                                                             
Iris-setosa            1.464       0.244          NaN       3.418
Iris-versicolor        4.260       1.326          NaN       2.770
Iris-virginica         5.552       2.026          NaN       2.974

margins_name

marginがTrueの場合の集計要素の名称を指定するパラメータ。デフォルトはAll。

例えばTestに設定。

df.pivot_table(index='Name', values='SepalLength', margins=True, margins_name='Test')

Testという名称で集計された。

                 SepalLength
Name                        
Iris-setosa         5.006000
Iris-versicolor     5.936000
Iris-virginica      6.588000
Test                5.843333

まとめ

ピボットテーブルの計算をするときに使うpivot_tableの全引数を検証しました。基本はindex, columns, values, marginsを、応用的にはaggfuncを使いこなせるとかなり便利なのではないかと思います。是非活用してみてください。

0

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA