Pandasことはじめ

Jupyter NotebookやColabで頻出するスニペットまとめ。

準備

Notebookの先頭でimportしておく。NumPyは必須ではないが型の指定で使うことがある。

import pandas as pd
pd.options.display.max_columns = None # カラムの数
pd.options.display.max_rows = 100 # 行の数
pd.options.display.max_colwidth = 300 # カラムの横幅
import numpy as np

Notebookの構成

Notebookでは変数空間が共有されるため、コードブロックは基本的に直前の結果となるDataFrameだけに依存し、副作用を起こさないよう冪等に書くことが望ましい。そうすることで変更したコード以降を再実行すれば必ず結果が更新される。各ブロックは以下のように構成して、例えばdfaからdfzまで使うなどを自分のルールにしておくと良い。

# 前のブロックの結果がdfa
dfb = dfa.copy()
dfb = ...# このブロックの結果はdfb

データの取り込み

BigQueryのデータを扱う

ColabではGoogle認証をしてIPython Magicsを使うのがおすすめ。Pandasのread_gbqは使わない。

%load_ext google.cloud.bigquery

from google.colab import auth
auth.authenticate_user()
from google.cloud.bigquery import magics

認証した上で、コードブロックに

%%bigquery df --project <your-gcp-project>
SELECT
  ...
FROM
  ...

のようにクエリを書いて実行すると df で参照できる。データ転送が遅い場合はStorage APIを有効にするかClient APIを使うと改善される場合がある。

PythonのデータをDataFrameにする

元のデータ型によってDataFrame()DataFrame.from_dict()DataFrame.from_records()を使い分ける。合わないときはPythonのmap()かリスト内包で変換する。

ex = [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}]
pd.DataFrame(ex)

# 	a	b
# 0	1	2
# 1	3	4

Indexを設定する

indexによって集計などの動作が変わるので、DataFrame.reset_index()DataFrame.set_index()はこまめに行う。

ex = [{'a': 1, 'b': 2}, {'a': 1, 'b': 3}, {'a': 2, 'b': 4}]
df = pd.DataFrame(ex).set_index('a')
df

#	b
# a	
# 1	2
# 1	3
# 2	4

df.reset_index()

# 	a	b
# 0	1	2
# 1	1	3
# 2	2	4

結合

DataFrame.join()またはDataFrame.merge()を使う。

dfn = pd.DataFrame({'id': ['a', 'b', 'c', 'd'], 'name': ['apple', 'banana', 'cacao', 'durian']}).set_index('id')
dfp = pd.DataFrame({'id': ['a', 'a', 'b', 'c', 'e'], 'price': [100, 90, 150, 200, 500]}).set_index('id')
dfn.join(dfp)

# 	name	price
# id		
# a	apple	100.0
# a	apple	90.0
# b	banana	150.0
# c	cacao	200.0
# d	durian	NaN

集計

グループ化

GroupBy.agg()を使う。

ex = [{'name': 'foo', 'value': 1}, {'name': 'bar', 'value': 2}, {'name': 'foo', 'value': 3}, {'name': 'bar', 'value': 4}]
df = pd.DataFrame(ex)
df.groupby('name').agg(tuple)

#	value
# name	
# bar	(2, 4)
# foo	(1, 3)

グループの要素数

GroupBy.size()を使う。結果はSeriesになる。

ex = [{'name': 'foo', 'value': 1}, {'name': 'bar', 'value': 2}, {'name': 'foo', 'value': 3}]
df = pd.DataFrame(ex)
df.groupby(['name']).size().rename('size').to_frame()

#	size
# name	
# bar	1
# foo	2

グループの展開

DataFrame.explode()で指定したカラムのコレクションが展開される

df = pd.DataFrame([{'a': 1, 'b': [2, 3]}, {'a': 2, 'b': [4, 5]}])
df.explode('b')

#	a	b
# 0	1	2
# 0	1	3
# 1	2	4
# 1	2	5

カラムの操作

削除

DataFrame.drop()を使う。

df.drop('hoge', axis=1)

# もしくは

df.drop(columns=['hoge'])

行の操作

重複排除

DataFrame.drop_duplicates()で値の重複を排除する。値だけであることに注意。

df = pd.DataFrame([{'a': 1, 'b': 2}, {'a': 1, 'b': 2}, {'a': 2, 'b': 2}, {'a': 2, 'b': 2}])
df.drop_duplicates()

#	a	b
# 0	1	2
# 2	2	2

df.set_index('a').drop_duplicates()

# 	b
# a	
# 1	2

行番号で抽出

df.iloc[1:10]

値でフィルタ

df = pd.DataFrame([{'col': 'foo'}, {'col': 'bar'}, {'col': 'hoge'}])

# OK
df[df['col'].str.len() > 3]

# OK
df[df['col'].map(len) > 3]

# NG
df[len(df['col']) > 3]

df[]の中身はベクトルでなくてはならないことに注意。

DataFrameの行でループ

for index, row in df.iterrows():
  print(row['col'])

可視化

matplotlib - 時系列データならこれ
graphviz - グラフ描画。pygraphvizではなくgraphvizがおすすめ
seaborn - heatmapとclustermap