【Pandasデータ集計】crosstab()でカテゴリ間の関係を分析!クロス集計の基本と活用


 

データ分析では、複数のカテゴリカルデータ(分類されるデータ)の間にどのような関係性があるのか、その出現回数や頻度を把握することが非常に重要です。例えば、「性別と購買商品カテゴリの関連性」や「地域と人気サービス」など、異なるカテゴリ間でデータがどのように分布しているかを知りたい場合に役立ちます。

Pandasの**crosstab()関数**は、2つ以上のSeriesや配列から、**クロス集計表(または分割表、度数分布表)**を簡単に作成するための強力なツールです。この記事では、crosstab()の基本的な使い方から、知っておくと便利な応用例まで、短いサンプルコードと丁寧な解説を交えてご紹介します。


 

crosstab()とは?なぜクロス集計が必要なのか?

 

crosstab()関数は、与えられた複数の要素(Seriesや配列)の組み合わせにおける出現回数や割合をまとめた表を作成します。この表は、カテゴリ間の関係性や分布を視覚的に、そして数値的に理解するのに役立ちます。

なぜクロス集計が必要なのでしょうか?

  • カテゴリ間の関連性分析: 2つ以上のカテゴリ変数が互いにどのように関連しているかを一目で把握できます。

    • 例: どの年齢層がどのSNSを最も利用しているか?

  • データの特徴把握: データセット内の特定のカテゴリの組み合わせがどれくらいの頻度で出現するかを理解できます。

  • マーケティング戦略: 顧客の属性と購買行動の関連性を分析し、ターゲット戦略を立てるのに役立ちます。

  • 基礎統計量の算出: 質的データの頻度分布を把握する上で、非常に基本的な手法です。


 

crosstab()の基本的な使い方

 

crosstab()関数を使うには、クロス集計したい2つ以上のSeries(DataFrameの列)を引数に渡します。

 

2つのカテゴリのクロス集計(度数)

 

最もシンプルなのは、2つのカテゴリ変数の組み合わせの出現回数を集計することです。

Python
 
import pandas as pd

# サンプルDataFrameの作成
df = pd.DataFrame({
    '性別': ['男性', '女性', '男性', '女性', '男性', '男性'],
    '購買商品': ['A', 'B', 'A', 'C', 'B', 'A'],
    '地域': ['東京', '大阪', '東京', '福岡', '大阪', '東京']
})
print("オリジナルDataFrame:\n", df)

# '性別'と'購買商品'のクロス集計(度数)
crosstab_gender_product = pd.crosstab(df['性別'], df['購買商品'])
print("\n性別と購買商品のクロス集計:\n", crosstab_gender_product)

解説:

  1. pd.crosstab(df['性別'], df['購買商品']): 最初の引数(df['性別'])が行のインデックスに、2番目の引数(df['購買商品'])が列のヘッダーになります。

  2. 表の中の値は、各組み合わせ(例: 男性かつ商品A)が出現した回数を示します。


 

crosstab()の応用的な使い方

 

crosstab()は、度数だけでなく割合を算出したり、複数のカテゴリを組み合わせたりと、柔軟な集計が可能です。

 

割合(相対頻度)を算出する: normalize引数

 

normalize引数を使うと、出現回数ではなく、全体に対する割合、または行・列ごとの割合を算出できます。

  • normalize=True または normalize='all': 全体に対する割合

  • normalize='index': 行ごとの合計が1になる割合

  • normalize='columns': 列ごとの合計が1になる割合

Python
 
# 全体に対する割合
crosstab_norm_all = pd.crosstab(df['性別'], df['購買商品'], normalize=True)
print("\n性別と購買商品のクロス集計 (全体に対する割合):\n", crosstab_norm_all)

# 行ごとの割合 (性別ごとの商品購入比率)
crosstab_norm_index = pd.crosstab(df['性別'], df['購買商品'], normalize='index')
print("\n性別と購買商品のクロス集計 (性別ごとの割合):\n", crosstab_norm_index)

解説:

  • normalize=Trueでは、全てのセルの合計が1になります。

  • normalize='index'では、各行の合計が1になります。これにより、「男性の購買者のうち、商品Aを買った割合」のように、行カテゴリに限定した割合を把握できます。

 

複数のカテゴリでクロス集計する

 

行や列に複数のカテゴリを指定して、より複雑なクロス集計表を作成できます。リスト形式で指定します。

Python
 
# 行に'性別'と'地域'、列に'購買商品'のクロス集計
crosstab_multi_rows = pd.crosstab([df['性別'], df['地域']], df['購買商品'])
print("\n性別と地域、購買商品のクロス集計:\n", crosstab_multi_rows)

解説:

行の引数にリスト[df[‘性別’], df[‘地域’]]を渡すことで、行インデックスがMultiIndex(複数階層)になります。これにより、「男性で東京に住む人が商品Aを何回買ったか」といった詳細な集計が可能です。

 

値と集計関数を指定する: valuesaggfunc

 

デフォルトでは出現回数を数えますが、特定の列の値(例: 売上)を合計したり平均したりしたい場合は、valuesaggfunc引数を組み合わせます。

Python
 
# '性別'と'購買商品'でグループ化し、'価格'の平均を算出
# 商品名と価格は同じなので、ここでは価格列を直接使います
df_sales = pd.DataFrame({
    '性別': ['男性', '女性', '男性', '女性', '男性', '男性'],
    '商品': ['A', 'B', 'A', 'C', 'B', 'A'],
    '売上': [100, 150, 120, 80, 200, 110]
})

crosstab_agg_avg = pd.crosstab(
    df_sales['性別'],
    df_sales['商品'],
    values=df_sales['売上'],
    aggfunc='mean'
)
print("\n性別と商品ごとの平均売上:\n", crosstab_agg_avg)

解説:

  • values=df_sales['売上']: 集計の対象となる値の列を指定します。

  • aggfunc=’mean’: その値に対して適用する集計関数を指定します(’sum’, ‘max’, np.meanなども指定可能)。

    これにより、単純な度数ではなく、指定した値の集計結果が表に表示されます。


 

crosstab()groupby()の違い

 

crosstab()groupby()と似ていますが、使い分けのポイントがあります。

  • crosstab(): 主に2つ以上のカテゴリ変数の度数分布や関連性を簡潔に表示したい場合に最適です。特にnormalize引数による割合算出が強力です。Pandasの関数として提供されており、DataFrameやSeriesのメソッドではありません。

  • groupby(): 任意の数のカテゴリ変数でグループ化し、**様々な数値列に対して複雑な集計(合計、平均、最大/最小、カスタム関数など)**を行いたい場合に柔軟性があります。結果はMultiIndexのSeriesやDataFrameになることが多いです。

どちらを使うかは、目的とデータの構造によって選びましょう。単純なカテゴリ間の度数や割合の確認であればcrosstab()が非常に便利です。


 

まとめ

 

Pandasのcrosstab()関数は、複数のカテゴリカルデータ間の関係性をクロス集計表として可視化し、分析するための強力なツールです。基本的な度数分布の算出から、normalize引数による割合計算、複数のカテゴリを使った多次元集計、そしてvaluesaggfuncを組み合わせた値の集計まで、幅広い用途に対応できます。crosstab()を使いこなすことで、カテゴリデータの深い洞察を得て、より効果的なデータ分析を進めることができるでしょう。