テーブルデータを分析する時、2つの列の値の関係を調べたいことが良くあります。
対象の列がどちらも連続値をとるのであれば、散布図を書きますが、
これが連続値ではなく性別や都道府県、世代、アンケートのn段階評価などの時は、散布図はあまり適しません。
このような場合は、クロス集計を使うと便利です。
(wikipediaでは分割表と呼んでいるようです。)
pandasにクロス集計を行う専用の関数があるのでそれを紹介します。
(職場ではcsvに書き出してtableauに読み込ませてやることも多いのですが、pythonで完結できればそれはそれ便利です。)
ドキュメントはこちら。
pandas.crosstab
aggfuncに値を渡せば、数え上げ以外にも色々できることがあり、pivot_table的な使い方もできるのですが、
とりあえずダミーデータを用意してデータの数え上げでクロス表を作ってみましょう。
ABテストなどで頻繁に使いますからね。
import pandas as pd
import numpy as np
# ダミーデータ生成
df = pd.DataFrame(
{
"data1": np.random.randint(1, 6, 100),
"data2": np.random.choice(["foo", "bar"], 100),
}
)
# サンプル(5件)
print(df.sample(5))
# 出力
'''
data1 data2
71 2 bar
13 1 foo
7 5 bar
16 1 bar
56 2 foo
'''
# クロス集計
cross_df = pd.crosstab(df.data2, df.data1)
print(cross_df)
# 出力
'''
data1 1 2 3 4 5
data2
bar 10 13 8 12 8
foo 12 9 11 9 8
'''
とても楽にクロス集計ができました。
SQLでこれを実装しようとするとかなりの手間なので、地味に重宝しています。
完全に蛇足ですが、crosstabを知らなかった頃はこういうコードを書いていました。
indexとcolumnsだけ指定して値が全部0のデータフレームを作って、
元のデータの値を順番に数え上げています。
今思えばcrosstab知らなくても、もう少しまともな書き方がありそうです。
cross_df_2 = pd.DataFrame(
0,
index=set(df.data2),
columns=set(df.data1),
)
for _, row in df.iterrows():
cross_df_2.loc[row.data2, row.data1] += 1
print(cross_df_2)
# 出力
'''
1 2 3 4 5
foo 12 9 11 9 8
bar 10 13 8 12 8
'''