【Pandas】pivot_tableでデータを集計する!

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
部署商品売上
01月東京本社A100
11月東京本社B150
22月東京本社A140
31月関西支店A120
41月関西支店B130
51月九州支店A90
61月九州支店B80

部署×商品ごとの売上合計を求める

サンプルデータを対象に、pivot_table()を使って、部署×商品ごとの売上合計を求めてみます。

df_pivoted = pd.pivot_table(
    df,
    values='売上',
    index='部署',
    columns='商品',
    aggfunc='sum',
)
print(df_pivoted)
Python
商品AB
部署
九州支店9080
東京本社240150
関西支店120130

各引数に対象となる列を入力すると、売上をクロス集計することができます。

この時、aggfunc=’sum’としてあげることで、合計の算出が可能です。 また、sum以外にも、mean(平均)やmax(最大値)、median(中央値)などを入力することで合計以外の集計も可能です。

複数の集計関数を使う

集計関数は複数指定することも可能です。
複数指定する場合はリスト形式で指定します。

df_pivoted = pd.pivot_table(
    df,
    values='売上',
    index='部署',
    columns='商品',
    aggfunc=['sum', 'mean', 'max']
)
print(df_pivoted)
Python
summeanmax
商品ABABAB
部署
九州支店908090809080
東京本社240150120150140150
関西支店120130120130120130

欠損値(NaN)の置き換え

データによっては、ある組み合わせに値が存在せずNaNが発生することがあります。

df_pivoted = pd.pivot_table(
    df,
    values='売上',
    index='部署',
    columns='月',
    aggfunc='sum',
)
print(df_pivoted)
Python
1月2月
部署
九州支店170NaN
東京本社250140
関西支店250NaN

そんなときはfill_valueで置き換えが可能です。

df_pivoted = pd.pivot_table(
    df,
    values='売上',
    index='部署',
    columns='月',
    aggfunc='sum',
    fill_value=0
)
print(df_pivoted)
Python
1月2月
部署
九州支店1700
東京本社250140
関西支店2500

総計を追加する

margins=Trueを指定すると、総計行・総計列を自動で追加できます。
また、margins_nameを指定すると、総計の名前を変更できます。

df_pivoted = pd.pivot_table(
    df,
    values='売上',
    index='部署',
    columns='商品',
    aggfunc='sum',
    margins=True,
    margins_name='総計'
)
print(df_pivoted)
Python
商品AB総計
部署
九州支店9080170
東京本社240150390
関西支店120130250
総計450360810

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
インデックス日付商品売上
02023-01-01A100
12023-01-01A120
22023-01-02B200
32023-01-02B220

pivot()の場合

df_pivoted = df.pivot(index='日付', columns='商品', values='売上')
print(df_pivoted)
Python
ValueError: 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
日付AB
2023-01-012200
2023-01-020420

aggfunc=’sum’を指定することで、重複を合計として集計しながら、横持ちへの変換ができました。

尚、pivot()の詳細については、以下の解説記事もご覧ください。

まとめ

本記事では、Pandasのpivot_table()を使ったデータの集計方法について詳しく解説しました。

pivot_table()はデータをクロス集計し把握する上で非常に強力なメソッドで、groupby()に比べて、表形式で見やすい出力を簡単に得られる点も魅力といえるでしょう。

ぜひご自身のプロジェクトや業務の中でも活用してみてください。

タイトルとURLをコピーしました