LoginSignup
33

More than 3 years have passed since last update.

pandasのピボットテーブル機能を試してみた

Last updated at Posted at 2020-01-19

表やグラフをつくる際に意外と必要な機能。
知っているのと知らないのでは、天と地の差がある、そんなピボットテーブル機能をまとめてみました。
ちなみに私は学生時代、Excelのピボットテーブル機能も知らず、泣きながら実験データを整形していた記憶があります...
Qiitaへの投稿ということもあり、今回はpandasデータフレームで試してみました。

ピボットテーブルとは

Excelにある機能のひとつで、あらかじめ登録したリストのなかから必要なデータを取り出して、あらゆる方向から集計や分析を行うツールのことを指しています。
特に「集計」機能は便利で、下図の左のようなデータ形式から右のような結果を返すことができます。

image.png

クロス集計したい時や、ちょっとややこしいグラフをつくる際などに必要になります。
今回はExcelではなく、pandasデータフレーム上で似たことをやってみます。

練習用に使ったデータ

kaggle Titanicコンペのtrainデータを拝借。
それぞれのカラムの意味については、こちらを参照ください。

本題

そのままだとこんな感じですので...
image.png
解釈が難しい!

準備

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Path
input_path = "../input_data/"

# Set Display Max Columns
pd.set_option("display.max_columns", 50)

train = pd.read_csv(input_path + "train.csv", sep=",", header=0, quotechar="\"")
# test = pd.read_csv(input_path + "bank/test.csv", sep=",", header=0, quotechar="\"")

# 扱いにくいので欠損値処理
train["Embarked"] = train.Embarked.fillna("S") 
train["Age"]=train["Age"].fillna(train.Age.mean())

# 年齢を年代別へ
labels = [ "{0} - {1}".format(i, i + 9) for i in range(0, 100, 10) ]
train["Age"] = pd.cut(train["Age"], np.arange(0, 101, 10),
                      include_lowest=True, right=False,
                      labels=labels)

#今回の目的に扱いやすそうなのに絞る
df = train[["PassengerId", "Survived", "Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]]

# データの確認
df.head()

image.png

扱いにくそうな乗客者の名前などは消去。

使うのはpivot_table関数

最低限、必要な引数は下の3つ

・data(第一引数): 元データのpandas.DataFrameオブジェクトを指定。
・index: 元データの列名を指定。結果の行見出しとなる。
・columns: 元データの列名を指定。結果の列見出しとなる。

引数index, columnsに指定していない列の平均値が結果として算出されるが、型が数値でない列は除外されます。

基本的な使い方

df.pivot_table(index="Age", columns= "Sex", values="Fare")

image.png
デフォルトでは集計の平均値を返している。
(引数にaggfuncを追加することで他の結果も計算できます。)

結果の値の算出方法を指定: 引数aggfunc

デフォルトでは平均値が算出されるが、引数aggfuncに関数を指定することでほかの方法で値を算出することが可能。
デフォルト(引数aggfuncを省略した場合)はnumpy.mean()が指定される。

df.pivot_table(index="Age", columns= "Sex", values="Fare", aggfunc='count')

image.png

aggfunc='count'指定することで、当てはまるデータ個数を数え上げる。

行・列も複数選択できる:引数 index, columns

df.pivot_table(index="Age", columns= ["Pclass","Sex"], values="Survived", aggfunc='mean')

image.png

aggfuncに複数の算出方法を指定できる

df.pivot_table(index="Age", columns= ["Pclass","Sex"], values="Survived",  aggfunc=["mean","count"])

image.png

総計結果を追加する:引数margins, margins_name

df.pivot_table(index="Age", columns= ["Pclass","Sex"], values="Survived", aggfunc=["mean","count"],margins=True, margins_name="total")

image.png

結果で規格化したい時はcross_tab関数を使う: 引数normalize

cross_tab関数の引数normalizeを指定することで、全体・行ごと・列ごとに規格化できる。

pd.crosstab(index=df.Age, columns= df.Sex, values=df.Fare, aggfunc='count',  normalize=True)

image.png

・normalize=Trueまたはnormalize='all'とすると、全体を合計すると1になるように規格化。
・normalize='index' or 'columns'とすると、行 or 列ごとに合計すると1になるように規格化。

以上。

ピボットデーブルの操作後、列が多層化するのですが、列指定で抜き出すことができません。
知ってる方いらっしゃいましたら、コメントください...

参照・引用

http://yaginogogo.hatenablog.jp/entry/2016/04/22/011327
https://note.nkmk.me/python-pandas-pivot-table/
https://deepage.net/features/pandas-pivot.html
https://boxil.jp/mag/a2149/
https://deepage.net/features/pandas-pivot.html
https://qiita.com/kshigeru/items/bfa8c11d1e6487c791d3
https://qiita.com/hoto17296/items/3442af64c7acb682de6a

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33