Pandasでは、データを集計するための便利な関数が多数用意されています。
その中でもpivot_table()は、データをクロスで集計したい時などに便利な関数です。
本記事では、そんなpivot_table()の使い方を、具体的なサンプル付きで解説します。
pivot_table()とは
pivot_table()は、指定した列を行・列に配置し、数値データを集計するためのメソッドです。
Excelの「ピボットテーブル」と同じイメージで、複数カテゴリをクロス集計するのに便利です。
基本的な構文
pd.pivot_table(
df,
values=None,
index=None,
columns=None,
aggfunc='mean',
fill_value=None,
margins=False,
margins_name='All'
)
Python- values: 集計対象の列
- index: 行に指定する列
- columns:列に指定する列
- aggfunc:集計関数(デフォルトは平均)
- fill_value:欠損値の補完
- margins:Trueで総計行・総計列を追加
- margins_name:総計の名前
コード例
サンプルデータ
今回はこちらの売上データを例にpivot_table()の使い方を説明します。
import pandas as pd
data = {
'月': ['1月', '1月', '2月', '1月', '1月', '1月', '1月'],
'部署': ['東京本社', '東京本社', '東京本社', '関西支店', '関西支店', '九州支店', '九州支店'],
'商品': ['A', 'B', 'A', 'A', 'B', 'A', 'B'],
'売上': [100, 150, 140, 120, 130, 90, 80]
}
df = pd.DataFrame(data)
print(df)
Python月 | 部署 | 商品 | 売上 | |
---|---|---|---|---|
0 | 1月 | 東京本社 | A | 100 |
1 | 1月 | 東京本社 | B | 150 |
2 | 2月 | 東京本社 | A | 140 |
3 | 1月 | 関西支店 | A | 120 |
4 | 1月 | 関西支店 | B | 130 |
5 | 1月 | 九州支店 | A | 90 |
6 | 1月 | 九州支店 | B | 80 |
部署×商品ごとの売上合計を求める
サンプルデータを対象に、pivot_table()を使って、部署×商品ごとの売上合計を求めてみます。
df_pivoted = pd.pivot_table(
df,
values='売上',
index='部署',
columns='商品',
aggfunc='sum',
)
print(df_pivoted)
Python商品 | A | B |
---|---|---|
部署 | ||
九州支店 | 90 | 80 |
東京本社 | 240 | 150 |
関西支店 | 120 | 130 |
各引数に対象となる列を入力すると、売上をクロス集計することができます。
この時、aggfunc=’sum’としてあげることで、合計の算出が可能です。 また、sum以外にも、mean(平均)やmax(最大値)、median(中央値)などを入力することで合計以外の集計も可能です。
複数の集計関数を使う
集計関数は複数指定することも可能です。
複数指定する場合はリスト形式で指定します。
df_pivoted = pd.pivot_table(
df,
values='売上',
index='部署',
columns='商品',
aggfunc=['sum', 'mean', 'max']
)
print(df_pivoted)
Pythonsum | mean | max | ||||
---|---|---|---|---|---|---|
商品 | A | B | A | B | A | B |
部署 | ||||||
九州支店 | 90 | 80 | 90 | 80 | 90 | 80 |
東京本社 | 240 | 150 | 120 | 150 | 140 | 150 |
関西支店 | 120 | 130 | 120 | 130 | 120 | 130 |
欠損値(NaN)の置き換え
データによっては、ある組み合わせに値が存在せずNaNが発生することがあります。
df_pivoted = pd.pivot_table(
df,
values='売上',
index='部署',
columns='月',
aggfunc='sum',
)
print(df_pivoted)
Python月 | 1月 | 2月 |
---|---|---|
部署 | ||
九州支店 | 170 | NaN |
東京本社 | 250 | 140 |
関西支店 | 250 | NaN |
そんなときはfill_valueで置き換えが可能です。
df_pivoted = pd.pivot_table(
df,
values='売上',
index='部署',
columns='月',
aggfunc='sum',
fill_value=0
)
print(df_pivoted)
Python月 | 1月 | 2月 |
---|---|---|
部署 | ||
九州支店 | 170 | 0 |
東京本社 | 250 | 140 |
関西支店 | 250 | 0 |
総計を追加する
margins=Trueを指定すると、総計行・総計列を自動で追加できます。
また、margins_nameを指定すると、総計の名前を変更できます。
df_pivoted = pd.pivot_table(
df,
values='売上',
index='部署',
columns='商品',
aggfunc='sum',
margins=True,
margins_name='総計'
)
print(df_pivoted)
Python商品 | A | B | 総計 |
---|---|---|---|
部署 | |||
九州支店 | 90 | 80 | 170 |
東京本社 | 240 | 150 | 390 |
関西支店 | 120 | 130 | 250 |
総計 | 450 | 360 | 810 |
groupby()との違い
Pandasのデータ集計の方法として、groupby()という集計方法もあります。
groupby()も強力な集計方法ではありますが、pivot_table()のような表形式での集計ではなく、基本的には縦持ちとして出力されます。
そのため、データを柔軟に加工しやすいという点ではgroupby()が使いやすいですが、視覚的な見やすさという点ではpivot_table()の方が見やすく、用途に応じた使い分けを行うと良いでしょう。
Tips:重複データの横持ちデータ(wide形式)への変換
縦持ちデータ(long形式)を横持ちデータ(wide形式)に変換したいときは、通常pivot()を使用します。
pivot()では、index × columnsの組み合わせがユニーク(一意)でなければならず、複数の値が存在する場合にはエラーになります。 このようなケースにおいては、pivot_table()の使用がおすすめです。
以下のデータを例に見てみましょう。
data = {
'日付': ['2023-01-01', '2023-01-01', '2023-01-02', '2023-01-02'],
'商品': ['A', 'A', 'B', 'B'],
'売上': [100, 120, 200, 220]
}
df = pd.DataFrame(data)
print(df)
Pythonインデックス | 日付 | 商品 | 売上 |
---|---|---|---|
0 | 2023-01-01 | A | 100 |
1 | 2023-01-01 | A | 120 |
2 | 2023-01-02 | B | 200 |
3 | 2023-01-02 | B | 220 |
pivot()の場合
df_pivoted = df.pivot(index='日付', columns='商品', values='売上')
print(df_pivoted)
PythonValueError: Index contains duplicate entries, cannot reshape
Bash「日付 × 商品」がユニークでないため、エラーとなってしまいます。
pivot_table()の場合
df_pivoted = pd.pivot_table(
df,
values='売上',
index='日付',
columns='商品',
aggfunc='sum',
fill_value=0
)
print(df_pivoted)
Python日付 | A | B |
---|---|---|
2023-01-01 | 220 | 0 |
2023-01-02 | 0 | 420 |
aggfunc=’sum’を指定することで、重複を合計として集計しながら、横持ちへの変換ができました。
尚、pivot()の詳細については、以下の解説記事もご覧ください。
まとめ
本記事では、Pandasのpivot_table()を使ったデータの集計方法について詳しく解説しました。
pivot_table()はデータをクロス集計し把握する上で非常に強力なメソッドで、groupby()に比べて、表形式で見やすい出力を簡単に得られる点も魅力といえるでしょう。
ぜひご自身のプロジェクトや業務の中でも活用してみてください。