Pandasのピボットテーブルを使うと行と列を変換し、指定したグループ単位で簡単に集計(合計値、平均値、カウント数など)ができます。
エクセルのピボットテーブルはGUIベースなので操作が簡単なことにたいして、Pandasのピボットテーブルはコード指定する必要があるので明確に理解する必要があります。
私はPandasのピボットテーブルを知った時にエクセルで経験した便利機能が使えると思い喜んだのですが、Pandasピボットテーブルの記述方法は「dataframe.pivot」と「dataframe.pivot_table」の2通りあったり、コーディング時に迷うことがあったり正直難しいなと思っていました。
現在はPandasピボットテーブルを完全に習得し、思い通りに操作できるようになったので迷いやすいポイントやよく使うコード例をご紹介することで皆様が簡単にピボットテーブルを使えることを目指します。
- ピボットテーブルの使い方が全くわからない
- 「dataframe.pivot」と「dataframe.pivot_table」の違いが知りたい
- よく使うピボットテーブルのパターンを知りたい
ピボットテーブルが使えるメリット
ピボットテーブル機能があると簡易的に集計できるので少ないコードで早くアウトプットが出せますし、コードが短いがゆえに保守対応も簡単です。
例えば、ピボットテーブル機能がないSQLでピボットと同じ結果を出すには、かなり長いコードを書く必要があり現実的ではありません。
そんな便利なピボットテーブル機能を利用したことない方向けに簡単なサンプルデータとピボットテーブルの操作体験ができるサンプルコードを作成しましたのでご活用くださいませ。
dataframe.pivotとdataframe.pivot_tableの違い
Pandasのピボットテーブルにはdataframe.pivotとdataframe.pivot_tableの2つのメソッドがありますが、dataframe.pivot_tableだけ覚えれば大丈夫です。
dataframe.pivotは簡易版なので一部機能のみですがdataframe.pivot_tableは全ての機能を利用でき高度な操作や柔軟性があります。
体験用のサンプルデータを紹介
ピボットテーブルを体験できるサンプルデータを作成しましたのでダウンロードし、デスクトップ上に保存してください。
サンプルデータは私が好きなおやつを元に作成し、最初の5行を下記に表示しました。
import pandas as pd
df1=pd.read_csv(r"C:\Users\abi00\Desktop\sample_1.csv")
#最初の5行のみ表示
df1.head(5)
売上日 | 大カテゴリ | 中カテゴリ | 単価 | 売上数量 | 売上金額 | 商品ID | 商品名 |
---|---|---|---|---|---|---|---|
2020-06-27 | おやつ | たいやき | 4000 | 5 | 20000 | 0 | たいやきみかん |
2020-01-25 | おやつ | たいやき | 4000 | 5 | 20000 | 1 | たいやきおれんじ |
2020-12-22 | おやつ | たいやき | 4000 | 6 | 24000 | 2 | やきいもたいやき |
2020-08-04 | おやつ | たいやき | 4000 | 7 | 28000 | 3 | あんこたいやき |
2020-01-22 | おやつ | たいやき | 4000 | 1 | 4000 | 4 | 栗たいやき |
dataframe.pivot_tableの使い方
ピボットテーブルは表示させたい項目(列)やインデックス(行)をグループ表示させ、集計値(合計値や平均値など)を指定する機能があります。
下記にdataframe.pivot_tableの構造を示します。
DataFrame.pivot_table(index=”インデックス名”,columns=”項目名”,values=”集計したい項目名値”,margins=”小計・総計の表示有無”,aggfunc=”集計方法”)
dataframe.pivot_table(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True)
データがアウトプットされる視点で記載してみます。
- columns:列にする項目を指定
- index:行にする項目を指定
- values:値として使用する列を指定 ※aggfuncを利用した集計関数として下記が存在
・sum:合計
・mean:平均
・max:最大
・min:最小
・count:件数 - margins:値をTrueにするとピボットテーブルの最後行列に合計値を表示
- dropna:値をTrueにすると欠損値が含まれる行や列を除外
これらのパラメータを適切に指定することで、目的に応じたピボットテーブルを作成することができます。
dataframe.pivot_tableを体験
サンプルデータでピボットテーブルを実行
それでは先ほどのサンプルデータを利用し下記パラメーターを入れたコードを実行してみましょう。
①行指定(index) → 中カテゴリ
②列指定(columns) → 大カテゴリ
③値指定(values) → ”売上数量”
④集計関数(aggfunc)→ count指定
import pandas as pd
df1=pd.read_csv(r"C:\Users\abi00\Desktop\sample_1.csv")
df1=df1.pivot_table(index="中カテゴリ", columns="大カテゴリ", values="売上数量", aggfunc = 'count')
#表示の便宜上インデックスをリセットします。
df1.reset_index()
結果をみると行と列が中カテゴリ、大カテゴリ毎に表示され集計された数量の合計値が値として格納されております。
大カテゴリ | 中カテゴリ | おやつ | 果物 | 麺類 |
---|---|---|---|---|
たいやき | 30.0 | NaN | NaN | |
どら焼き | 31.0 | NaN | NaN | |
みかん | NaN | 31.0 | NaN | |
りんご | NaN | 43.0 | NaN | |
パスタ | NaN | NaN | 27.0 | |
ラフランス | NaN | 31.0 | NaN | |
ラーメン | NaN | NaN | 21.0 |
次に集計値をcountからsumに変えることで売上数量の合計値を表示させます。
df1=df1.pivot_table(index="中カテゴリ", columns="大カテゴリ", values="売上数量", aggfunc = 'sum')
#表示の便宜上インデックスをリセットします。
df1.reset_index()
大カテゴリ | 中カテゴリ | おやつ | 果物 | 麺類 |
---|---|---|---|---|
たいやき | 147.0 | NaN | NaN | |
どら焼き | 191.0 | NaN | NaN | |
みかん | NaN | 173.0 | NaN | |
りんご | NaN | 240.0 | NaN | |
パスタ | NaN | NaN | 147.0 | |
ラフランス | NaN | 153.0 | NaN | |
ラーメン | NaN | NaN | 111.0 |
「値が存在する数量」から「数量の合計値」に変わったことがわかります。
aggfuncパラメーターの使い方
集計値のNaNを除外したい場合は違う値に置き換えるオプション「fill_value=置換する値」を利用します。
df1=df1.pivot_table(index="中カテゴリ", columns="大カテゴリ", values="売上数量", aggfunc = 'sum',fill_value=0)
df1.reset_index()
これと同様の考えでaggfuncを「mean,max,min」に変更すると値も変化します。
大カテゴリ | 中カテゴリ | おやつ | 果物 | 麺類 |
---|---|---|---|---|
たいやき | 147 | 0 | 0 | |
どら焼き | 191 | 0 | 0 | |
みかん | 0 | 173 | 0 | |
りんご | 0 | 240 | 0 | |
パスタ | 0 | 0 | 147 | |
ラフランス | 0 | 153 | 0 | |
ラーメン | 0 | 0 | 111 |
これと同様の考えでaggfuncを「mean,max,min」に変更すると値も変化します。
marginsパラメーターの使い方
カテゴリ毎の小計や総計を表示させることも可能でmargins=True, margins_name=’つけたい名称’とすることで表示されます。
df1.pivot_table(index="Survived", columns="Sex", values="Fare", aggfunc = 'count', margins=True, margins_name='Total')
大カテゴリ | 中カテゴリ | おやつ | 果物 | 麺類 | Total |
---|---|---|---|---|---|
たいやき | 147 | 0 | 0 | 147 | |
どら焼き | 191 | 0 | 0 | 191 | |
みかん | 0 | 173 | 0 | 173 | |
りんご | 0 | 240 | 0 | 240 | |
パスタ | 0 | 0 | 147 | 147 | |
ラフランス | 0 | 153 | 0 | 153 | |
ラーメン | 0 | 0 | 111 | 111 | |
Total | 338 | 566 | 258 | 1162 |
複数項目を指定する方法
今までの例は単一項目指定でしたが複数項目はlist型で指定でき[“中カテゴリ”,”売上日”]としました。
df1.pivot_table(index=["中カテゴリ","売上日"], columns="大カテゴリ", values="売上数量", aggfunc = 'sum',fill_value=0, margins=True, margins_name='Total')
大カテゴリ | 中カテゴリ | 売上日 | おやつ | 果物 | 麺類 | Total |
---|---|---|---|---|---|---|
たいやき | 2020-01-19 | 1 | 0 | 0 | 1 | |
たいやき | 2020-01-22 | 1 | 0 | 0 | 1 | |
たいやき | 2020-01-25 | 5 | 0 | 0 | 5 | |
たいやき | 2020-01-26 | 6 | 0 | 0 | 6 | |
たいやき | 2020-02-03 | 5 | 0 | 0 | 5 | |
たいやき | 2020-02-25 | 1 | 0 | 0 | 1 | |
たいやき | 2020-03-05 | 8 | 0 | 0 | 8 | |
たいやき | 2020-03-22 | 6 | 0 | 0 | 6 | |
たいやき | 2020-03-26 | 8 | 0 | 0 | 8 | |
たいやき | 2020-05-05 | 10 | 0 | 0 | 10 |
valuesの値をmax、minで複数表記すると
df1.pivot_table(index=["Pclass","Survived"], columns="Sex", values="Fare", aggfunc = [max,min], margins=True, margins_name='Total')
大カテゴリ | 中カテゴリ | 売上日 | おやつ | 果物 | 麺類 | Total |
---|---|---|---|---|---|---|
たいやき | 2020-01-19 | 1 | 0 | 0 | 1 | |
たいやき | 2020-01-22 | 1 | 0 | 0 | 1 | |
たいやき | 2020-01-25 | 5 | 0 | 0 | 5 | |
たいやき | 2020-01-26 | 6 | 0 | 0 | 6 | |
たいやき | 2020-02-03 | 5 | 0 | 0 | 5 |
値を複数に指定することも可能でvalues=[“売上数量”,”売上金額”]とするコードと結果です。
中カテゴリ | 売上数量 | 売上金額 | |||||||
---|---|---|---|---|---|---|---|---|---|
大カテゴリ | おやつ | 果物 | 麺類 | Total | おやつ | 果物 | 麺類 | Total | |
たいやき | 147 | 0 | 0 | 147 | 588000 | 0 | 0 | 588000 | |
どら焼き | 191 | 0 | 0 | 191 | 1528000 | 0 | 0 | 1528000 | |
みかん | 0 | 173 | 0 | 173 | 0 | 1038000 | 0 | 1038000 | |
りんご | 0 | 240 | 0 | 240 | 0 | 1680000 | 0 | 1680000 | |
パスタ | 0 | 0 | 147 | 147 | 0 | 0 | 2646000 | 2646000 |
df1.pivot_table(index=["中カテゴリ"], columns="大カテゴリ", values=["売上数量","売上金額"], aggfunc = 'sum',fill_value=0, margins=True, margins_name='Total')
pivot_table応用編
ユニーク値で集計する方法
値をユニーク化して件数を確認するにはlambdaを利用します。
df1.pivot_table(index="Survived", columns="Sex", values="Fare", margins=True, margins_name='Total', aggfunc = lambda x:len(x.unique()))
大カテゴリ | 中カテゴリ | おやつ | 果物 | 麺類 |
---|---|---|---|---|
たいやき | 8.0 | NaN | NaN | |
どら焼き | 9.0 | NaN | NaN | |
みかん | NaN | 10.0 | NaN | |
りんご | NaN | 10.0 | NaN | |
パスタ | NaN | NaN | 7.0 |
ユニーク化したことでカウント数が減少しました。
複数のvalesで違う集計関数を使う方法
valuesの値をlist型にしてカンマ区切りで複数記載します。agguuncにはvaluesで指定した項目ごとの集計関数を辞書値で登録します。
df1.pivot_table(index=["中カテゴリ"], columns="大カテゴリ", values=["売上数量","売上金額"],aggfunc ={"売上数量":"count","売上金額":"sum"},fill_value=0, margins=True, margins_name='Tota
中カテゴリ | 売上数量 | 売上金額 | |||||||
---|---|---|---|---|---|---|---|---|---|
大カテゴリ | おやつ | 果物 | 麺類 | Total | おやつ | 果物 | 麺類 | Total | |
たいやき | 30 | 0 | 0 | 30 | 588000 | 0 | 0 | 588000 | |
どら焼き | 31 | 0 | 0 | 31 | 1528000 | 0 | 0 | 1528000 | |
みかん | 0 | 31 | 0 | 31 | 0 | 1038000 | 0 | 1038000 | |
りんご | 0 | 43 | 0 | 43 | 0 | 1680000 | 0 | 1680000 | |
パスタ | 0 | 0 | 27 | 27 | 0 | 0 | 2646000 | 2646000 |
valuesをカンマ区切りで出したい時
元データには、値が縦に並んでいるが値にすると横に並びます。
その時に、カンマなどで区切られていないと、もともとの値の境目がわからない。
この問題を解決するにはvaluesをlistとして出すことです。
df.pivot_table(index=["項目名"],values="",aggfunc = list)
上記のようにaggfuncにlistを指定することで、list式で出すことができます。
インデックスをリセットする方法
ピボットの集計結果を利用して更にデータ結合する場合はマルチインデックスになっているケースがあるのでインデックスをリセットしないと実行できないケースがあるのでやり方を説明します。
df1=df1.pivot_table(index="中カテゴリ", columns="大カテゴリ", values="売上数量", aggfunc = 'sum',fill_value=0)
df1.reset_index()
以下に具体的な例を示します
pivot_table = dataframe.pivot_table(values='値にする列名', index='行にする列名', columns='列にする列名', aggfunc='sum')
pivot_table = pivot_table.reset_index()
pandasの公式ドキュメントをご確認したいかたはこちらです。
コメント