Pandas pd.crosstab() 関数
pd.crosstab()は、Pandas ライブラリ内でクロス集計(Cross Tabulation)を計算するための関数です。これは、2つ以上の変数の頻度や集計統計を計算し、Excelのピボットテーブルのような表を生成します。
クロス集計表は統計分析において非常に有用なツールであり、2つ以上のカテゴリ変数の関係を分析するためによく使用されます。例えば、部門ごとの男女従業員数を集計する場合です。
単語の意味: crosstab「cross tabulation」(クロス集計表)の略で、2つ以上の変数の同時分布を示す統計表です。
基本構文とパラメータ
pd.crosstab()Pandas ライブラリのトップレベル関数であり、クロス集計表の計算に使用します。
構文形式
pd.crosstab(index, columns, values=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False)
パラメータの説明
- パラメータ:
index- 型: 配列(array-like)、Series、またはリスト。
- 説明: 行インデックスとして使用するデータ。単一の列または複数の列(リスト)を指定できます。
- パラメータ:
columns- 型: 配列(array-like)、Series、またはリスト。
- 説明: 列インデックスとして使用するデータ。単一の列または複数の列(リスト)を指定できます。
- パラメータ:
values- 型: 配列(array-like)または None。
- 説明: 集計する値。指定する場合は、
aggfuncパラメータと組み合わせて使用する必要があります。
- パラメータ:
aggfunc- 型: 関数または文字列。
- 説明: 集計関数('sum'、'mean'、'count' など)。
values指定された場合に使用する必要があります。
- パラメータ:
margins- 型: ブール値。
- 説明: もし
Trueの場合、行と列の合計を追加します。デフォルトはFalse。
- パラメータ:
normalize- 型: ブール値、または 'all'、'index'、'columns'。
- 説明: もし
Trueの場合、値を合計で割って比率(0-1)を生成します。'index' または 'columns' を指定すると、行ごとまたは列ごとに正規化することもできます。
関数の説明
- 戻り値: 2つ以上の変数間のクロス関係を表す DataFrame を返します。
- 効果: 行と列がそれぞれ異なるカテゴリ変数を表し、セルに対応する頻度または集計値を表示する表を生成します。
実例
簡単な例から複雑な例までの一連のサンプルを通して、pd.crosstab()の使い方を完全にマスターしましょう。
例1:基本用法 - 2つのカテゴリ変数のクロス集計表
実例
import pandas as pd
# 1. 従業員データを作成
employees = pd.DataFrame({
'department': ['Sales', 'Sales', 'Sales', 'Engineering', 'Engineering', 'HR', 'HR', 'Sales', 'Engineering', 'HR'],
'gender': ['Male', 'Female', 'Female', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Male']
})
print("=== 従業員データ ===")
print(employees)
# 2. 部門と性別のクロス集計表(頻度)を計算
result = pd.crosstab(employees['department'], employees['gender'])
print("n=== pd.crosstab() 部門と性別のクロス集計表 ===")
print(result)
# 1. 従業員データを作成
employees = pd.DataFrame({
'department': ['Sales', 'Sales', 'Sales', 'Engineering', 'Engineering', 'HR', 'HR', 'Sales', 'Engineering', 'HR'],
'gender': ['Male', 'Female', 'Female', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Male']
})
print("=== 従業員データ ===")
print(employees)
# 2. 部門と性別のクロス集計表(頻度)を計算
result = pd.crosstab(employees['department'], employees['gender'])
print("n=== pd.crosstab() 部門と性別のクロス集計表 ===")
print(result)
実行結果の想定:
=== 员工数据 === department gender 0 Sales Male 1 Sales Female 2 Sales Female 3 Engineering Male 4 Engineering Male 5 HR Female 6 HR Male 7 Sales Female 8 Engineering Female 9 HR Male === pd.crosstab() 部门与性别交叉表 === gender Female Male department Engineering 1 2 HR 1 2 Sales 3 1
コードの解説:
- 結果の表は、各部門における男性と女性の従業員数を示しています。
例2:行と列の合計の追加と正規化
使用marginsパラメータを使用すると合計を追加できます。normalizeパラメータを使用すると比率の分布を確認できます。
実例
import pandas as pd
# 上記の従業員データを使用
employees = pd.DataFrame({
'department': ['Sales', 'Sales', 'Sales', 'Engineering', 'Engineering', 'HR', 'HR', 'Sales', 'Engineering', 'HR'],
'gender': ['Male', 'Female', 'Female', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Male']
})
# 1. 行と列の合計を追加
result_margins = pd.crosstab(employees['department'], employees['gender'], margins=True)
print("=== 合計を追加 (margins=True) ===")
print(result_margins)
# 2. 正規化 - 比率に変換
print("n=== 全体の正規化 (normalize=True) ===")
result_norm = pd.crosstab(employees['department'], employees['gender'], normalize=True)
print(result_norm.round(3))
# 3. 行ごとに正規化(各行の合計が 1 になるように)
print("n=== 行ごとの正規化 (normalize='index') ===")
result_norm_index = pd.crosstab(employees['department'], employees['gender'], normalize='index')
print(result_norm_index.round(3))
# 4. 列ごとに正規化(各列の合計が 1 になるように)
print("n=== 列ごとの正規化 (normalize='columns') ===")
result_norm_col = pd.crosstab(employees['department'], employees['gender'], normalize='columns')
print(result_norm_col.round(3))
# 上記の従業員データを使用
employees = pd.DataFrame({
'department': ['Sales', 'Sales', 'Sales', 'Engineering', 'Engineering', 'HR', 'HR', 'Sales', 'Engineering', 'HR'],
'gender': ['Male', 'Female', 'Female', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Male']
})
# 1. 行と列の合計を追加
result_margins = pd.crosstab(employees['department'], employees['gender'], margins=True)
print("=== 合計を追加 (margins=True) ===")
print(result_margins)
# 2. 正規化 - 比率に変換
print("n=== 全体の正規化 (normalize=True) ===")
result_norm = pd.crosstab(employees['department'], employees['gender'], normalize=True)
print(result_norm.round(3))
# 3. 行ごとに正規化(各行の合計が 1 になるように)
print("n=== 行ごとの正規化 (normalize='index') ===")
result_norm_index = pd.crosstab(employees['department'], employees['gender'], normalize='index')
print(result_norm_index.round(3))
# 4. 列ごとに正規化(各列の合計が 1 になるように)
print("n=== 列ごとの正規化 (normalize='columns') ===")
result_norm_col = pd.crosstab(employees['department'], employees['gender'], normalize='columns')
print(result_norm_col.round(3))
実行結果の想定:
=== 添加合计 (margins=True) === gender Female Male All department Engineering 1 2 3 HR 1 2 3 Sales 3 1 4 All 5 5 10 === 整体归一化 (normalize=True) === gender Female Male department Engineering 0.1 0.2 HR 0.1 0.2 Sales 0.3 0.1 === 按行归一化 (normalize='index') === gender Female Male department Engineering 0.333 0.667 HR 0.333 0.667 Sales 0.75 0.25 === 按列归一化 (normalize='columns') === gender Female Male department Engineering 0.2 0.4 HR 0.2 0.4 Sales 0.6 0.2
コードの解説:
- 正規化により比率の関係を分析しやすくなり、各部門における性別の相対的な分布を把握できます。
- 行ごとの正規化は、各部門内の性別の百分比分布を表示します。
- 列ごとの正規化は、各性別が各部門にどのように分布しているかの割合を表示します。
例3:複数の変数と集計関数
複数の行/列変数を使用でき、集計関数を使って統計値を計算できます。
実例
import pandas as pd
import numpy as np
# 1. 売上データを作成
sales = pd.DataFrame({
'region': ['North', 'North', 'South', 'South', 'East', 'East', 'West', 'West', 'North', 'South'],
'product': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'B', 'A'],
'quarter': ['Q1', 'Q1', 'Q1', 'Q1', 'Q2', 'Q2', 'Q2', 'Q2', 'Q2', 'Q2'],
'sales': [100, 150, 200, 180, 120, 160, 190, 170, 140, 210]
})
print("=== 売上データ ===")
print(sales)
# 2. 複数の行変数を使用
print("n=== 地域と製品のクロス集計表(頻度)===")
result_multi = pd.crosstab([sales['region'], sales['product']], sales['quarter'])
print(result_multi)
# 3. values と aggfunc を使用して売上額を計算
print("n=== 地域と四半期の売上額合計 ===")
result_sum = pd.crosstab(sales['region'], sales['quarter'], values=sales['sales'], aggfunc='sum')
print(result_sum)
# 4. 平均売上額を計算
print("n=== 地域と四半期の平均売上額 ===")
result_mean = pd.crosstab(sales['region'], sales['quarter'], values=sales['sales'], aggfunc='mean')
print(result_mean.round(1))
import numpy as np
# 1. 売上データを作成
sales = pd.DataFrame({
'region': ['North', 'North', 'South', 'South', 'East', 'East', 'West', 'West', 'North', 'South'],
'product': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'B', 'A'],
'quarter': ['Q1', 'Q1', 'Q1', 'Q1', 'Q2', 'Q2', 'Q2', 'Q2', 'Q2', 'Q2'],
'sales': [100, 150, 200, 180, 120, 160, 190, 170, 140, 210]
})
print("=== 売上データ ===")
print(sales)
# 2. 複数の行変数を使用
print("n=== 地域と製品のクロス集計表(頻度)===")
result_multi = pd.crosstab([sales['region'], sales['product']], sales['quarter'])
print(result_multi)
# 3. values と aggfunc を使用して売上額を計算
print("n=== 地域と四半期の売上額合計 ===")
result_sum = pd.crosstab(sales['region'], sales['quarter'], values=sales['sales'], aggfunc='sum')
print(result_sum)
# 4. 平均売上額を計算
print("n=== 地域と四半期の平均売上額 ===")
result_mean = pd.crosstab(sales['region'], sales['quarter'], values=sales['sales'], aggfunc='mean')
print(result_mean.round(1))
実行結果の想定:
=== 销售数据 ===
region product quarter sales
0 North A Q1 100
1 North B Q1 150
2 South A Q1 200
3 South B Q1 180
4 East A Q2 120
5 East B Q2 160
6 West A Q2 190
7 West B Q2 170
8 North B Q2 140
9 South A Q2 210
=== 区域和产品的交叉表(频次)===
quarter Q1 Q2
region product
East A 0 1
B 0 1
North A 1 0
B 1 1
South A 1 1
B 1 0
West A 0 1
B 0 1
=== 区域和季度的销售额合计 ===
quarter Q1 Q2
region
East NaN 280
North 250 140
South 380 210
West NaN 360
=== 区域和季度的平均销售额 ===
quarter Q1 Q2
region
East NaN 140.0
North 125.0 140.0
South 190.0 210.0
West NaN 180.0
コードの解説:
- 複数の行変数(リスト形式)を使用すると、多層インデックスのクロス集計表を作成できます。
- 各セルには、特定の地域と製品の組み合わせが特定の四半期に出現した回数が表示されます。
- values パラメータと aggfunc パラメータを使用すると、実際の数値の集計(合計、平均など)を計算できます。
例4:欠損値の処理
dropnaパラメータは、欠損カテゴリを含めるかどうかを制御します。
実例
import pandas as pd
import numpy as np
# 1. 欠損値を含むデータ
data = pd.DataFrame({
'A': ['a', 'a', 'b', np.nan, 'a', 'b'],
'B': ['x', 'y', 'x', 'x', np.nan, 'y']
})
print("=== 欠損値を含むデータ ===")
print(data)
# 2. デフォルトでは欠損値を含む組み合わせを除外
result_drop = pd.crosstab(data['A'], data['B'])
print("n=== デフォルトで欠損値を除外 (dropna=True) ===")
print(result_drop)
# 3. 欠損カテゴリを含める
result_keep = pd.crosstab(data['A'], data['B'], dropna=False)
print("n=== 欠損カテゴリを含める (dropna=False) ===")
print(result_keep)
import numpy as np
# 1. 欠損値を含むデータ
data = pd.DataFrame({
'A': ['a', 'a', 'b', np.nan, 'a', 'b'],
'B': ['x', 'y', 'x', 'x', np.nan, 'y']
})
print("=== 欠損値を含むデータ ===")
print(data)
# 2. デフォルトでは欠損値を含む組み合わせを除外
result_drop = pd.crosstab(data['A'], data['B'])
print("n=== デフォルトで欠損値を除外 (dropna=True) ===")
print(result_drop)
# 3. 欠損カテゴリを含める
result_keep = pd.crosstab(data['A'], data['B'], dropna=False)
print("n=== 欠損カテゴリを含める (dropna=False) ===")
print(result_keep)
実行結果の想定:
=== 包含缺失值的数据 ===
A B
0 a x
1 a y
2 b x
3 NaN x
4 a NaN
5 b y
=== 默认移除缺失值 (dropna=True) ===
B x y
A
a 1 1
b 1 1
=== 包含缺失值 (dropna=False) ===
B x y NaN
A
a 1 1 1
b 1 1 0
NaN 1 0 0
コードの解説:
- デフォルトでは
dropna=True欠損値を含む行と列を除外し、有効なデータのみを表示します。 - を使用すると
dropna=False欠損値を含む組み合わせの頻度を確認できます。
その他の拡張ヒント:
pd.crosstab()カテゴリ変数間の関係を分析するのに適しています。より複雑なデータ集計(複数の集計指標の計算など)が必要な場合は、pd.pivot_table()関数を使用してください。
Pandas のよく使う関数