Pandas df.groupby() 関数
groupby()これは Pandas で最も強力なグループ化操作関数の一つであり、1つまたは複数の列の値に基づいてデータを異なるグループに分割し、各グループに対してさまざまな操作を行うことができます。
簡単に言うと、groupby()実現するのは「分割-適用-結合」(Split-Apply-Combine)というワークフローです:まず条件に応じてデータを分割し、各グループに関数を適用し、最後に結果を結合します。
これはデータ分析で非常に一般的で、例えば部門ごとの従業員の平均給与の集計、月ごとの売上の集計、地域ごとのユーザー数の集計などに使用されます。
基本構文とパラメータ
groupby()は DataFrame のメンバー関数であり、ドット演算子.を使用して呼び出します。呼び出した後は、GroupByオブジェクトが返されます。このオブジェクト自体は結果を直接表示せず、集約関数と組み合わせて使用する必要があります。
構文形式
DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, observed=False, dropna=True)
パラメータの説明
| パラメータ | 型 | 説明 | デフォルト値 |
|---|---|---|---|
| by | str、list または dict | グループ化に使用する列名または列名のリスト。辞書または関数の場合は、その結果に基づいてグループ化されます。 | None |
| axis | int | グループ化の軸方向。0 は行方向(デフォルト)、1 は列方向を表します。 | 0 |
| level | int または str | マルチインデックス(MultiIndex)の場合は、指定したレベルでグループ化します。 | None |
| as_index | bool | True の場合、グループ化列は戻り値のインデックスになります。False の場合、グループ化列は通常の列として保持されます。 | True |
| sort | bool | グループラベルを並べ替えるかどうか。False に設定するとパフォーマンスが向上します。 | True |
| group_keys | bool | 呼び出すapply()ときに、結果にグループキーをインデックスとして追加するかどうか。 |
True |
| observed | bool | True の場合、カテゴリ変数の実際の観測値のみが表示され、可能なすべての値は表示されません。 | False |
| dropna | bool | True の場合、NA/null 値を含むグループは破棄されます。 | True |
戻り値
- 戻り値の型:
DataFrameGroupBy或SeriesGroupByオブジェクト - 説明:返されるのはグループオブジェクトであり、最終結果ではありません。後続で集約関数(例:
sum()、mean()、count()など)を呼び出して、具体的な計算結果を得る必要があります。
例
簡単なものから複雑なものまでの一連の例を通じて、groupby()の使い方を徹底的にマスターしましょう。
例1:単一列によるグループ化
最も基本的な使い方は、ある列の値に基づいてグループ化することです。販売データテーブルがあり、地域ごとに総売上額を集計する必要があるとします。
例
# 簡単な販売データの DataFrame を作成する
# 地域、製品、売上高を含む表をシミュレートする
data = {
'地区': ['华北', '华东', '华南', '华北', '华东', '华南', '华北', '华东'],
'产品': ['A', 'B', 'C', 'B', 'A', 'C', 'A', 'B'],
'销售额': [1000, 2000, 1500, 1800, 2200, 1600, 1200, 2100]
}
# 创建 DataFrame
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()
# 「地区」列でグループ化し、各地区の総売上高を計算する
# as_index=True は地区をインデックスとして返します
grouped = df.groupby('地区', as_index=True)['销售额'].sum()
print(地区別にグループ化した後の総売上高:)
print(grouped)
print()
# as_index=False の場合、グループ化列は通常の列として保持されます。
grouped_df = df.groupby('地区', as_index=False)['销售额'].sum()
print("as_index=False の場合の結果:")
print(grouped_df)
実行結果の想定:
原始数据: 地区 产品 销售额 0 华东 B 2000 1 华南 C 1500 2 华北 A 1000 3 华东 B 1800 4 华南 C 2200 5 华北 A 1600 6 华东 A 1200 7 华南 B 2100 按地区分组后的总销售额: 地区 华东 7100 华南 7300 华北 3600 dtype: int64 as_index=False 时的结果: 地区 销售额 0 华东 7100 1 华南 7300 2 华北 3600
コードの解説:
df.groupby('地区')「地区」列の値に従ってデータを「华东」「华南」「华北」の3つのグループに分割します。['销售额'].sum()「销售额」列のみに対して合計集約を行うことを意味します。as_index=True(デフォルト値)の場合、返される Series は「地区」をインデックスとします;as_index=Falseの場合、返される DataFrame は「地区」を通常の列として保持し、後続の処理に適しています。
例2:複数列によるグループ化
複数の列で同時にグループ化する必要がある場合があります。例えば、地域と製品ごとに売上を集計する場合です。
例
# 创建销售数据
data = {
'地区': ['华北', '华东', '华南', '华北', '华东', '华南', '华北', '华东'],
'产品': ['A', 'B', 'C', 'B', 'A', 'C', 'A', 'B'],
'销售额': [1000, 2000, 1500, 1800, 2200, 1600, 1200, 2100]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()
# 「地区」と「製品」の2列でグループ化し、総売上高を計算する
# 使用列表指定多个分组列
grouped = df.groupby(['地区', '产品'], as_index=False)['销售额'].sum()
print(地域と製品ごとにグループ化した後の総売上高:)
print(grouped)
print()
# 使用 pivot_table 更直观地展示结果
pivot = df.pivot_table(values='销售额', index='地区', columns='产品', aggfunc='sum', fill_value=0)
print("使用 pivot_table 展示:")
print(pivot)
実行結果の想定:
原始数据: 地区 产品 销售额 0 华北 A 1000 1 华东 B 2000 2 华南 C 1500 3 华北 B 1800 4 华东 A 2200 5 华南 C 1600 6 华北 A 1200 7 华东 B 2100 按地区和产品分组后的总销售额: 地区 产品 销售额 0 华东 A 2200 1 华东 B 4100 2 华南 C 3100 3 华北 A 2200 4 华北 B 1800 使用 pivot_table 展示: 产品 A B C 地区 华北 2200 1800 0 华东 2200 4100 0 华南 0 0 3100
コードの解説:
['地域', '製品']リストを使用すると複数の列で同時にグループ化でき、結果は多階層インデックスになります。as_index=Falseの場合、グループ化列は通常の列として結果に保持され、確認や後続の処理が容易になります。pivot_table()pivot_table は同様のクロス集計機能を提供し、グループ化結果をより直感的に表示できます。
例3:辞書と関数を使ったグループ化
groupby()列名によるグループ化だけでなく、辞書や関数を使ってグループ化ルールを定義することもできます。これはカスタムのグループ化ロジックが必要な場合に非常に便利です。
例
# 创建学生成绩数据
data = {
'姓名': ['张三', '李四', '王五', '赵六', '孙七', '周八'],
'语文': [85, 92, 78, 88, 95, 82],
'数学': [90, 85, 92, 78, 88, 91],
'英语': [88, 90, 85, 92, 87, 89]
}
df = pd.DataFrame(data)
print("原始学生成绩数据:")
print(df)
print()
# 1. 使用字典进行自定义分组
# 「姓氏」に基づいてグループ化すると仮定します(張、李、王は1つのグループ、趙、孫、周は別のグループ)
def get_surname_group(name):
"""根据姓氏返回分组名称"""
if name in ['张三', '李四', '王五']:
return '第一组'
else:
return '第二组'
# 使用 apply 函数进行分组
grouped = df.groupby(get_surname_group).mean(numeric_only=True)
print("使用函数自定义分组(计算每组平均分):")
print(grouped)
print()
# 2. 辞書を使用して特定の列のグループ化をマッピングする
# 数値区間に基づいて国語の成績を「優秀」と「良好」の2つのグループに分ける
score_mapping = {
'语文': lambda x: '优秀' if x >= 90 else '良好'
}
# 国語列を条件でグループ化
grouped_by_score = df.groupby(lambda x: '优秀' if df.loc[x, '语文'] >= 90 else '良好').mean(numeric_only=True)
print("国語の成績でグループ化(>=90は優秀):")
print(grouped_by_score)
実行結果の想定:
原始学生成绩数据:
姓名 语文 数学 英语
0 张三 85 90 88
1 李四 92 85 90
2 王五 78 92 85
3 赵六 88 78 92
4 孙七 95 88 87
5 周八 82 91 89
使用函数自定义分组(计算每组平均分):
语文 数学 英语
姓名
第一组 85.000000 89.000000 87.666667
第二组 88.333333 85.666667 89.333333
按语文成绩分组(>=90为优秀):
语文 数学 英语
语文
优秀 93.500000 86.500000 88.500000
良好 83.250000 89.500000 88.750000
コードの解説:
- カスタム関数によるグループ化は、関数がグループ化に使用する値を返すだけで、複雑なグループ化ロジックを処理できます。
- 使用
numeric_only=Trueパラメータを使用すると、数値列のみに対して集約計算を行い、非数値列(例:姓名)に対する操作時のエラーを回避できます。 - 辞書マッピングを使用すると、「条件に応じて異なる列を異なるグループに分割する」という要件を実現できます。
例4:グループ化後の反復処理
場合によっては、各グループに対してより複雑なカスタム操作を行う必要があり、その場合はグループオブジェクトを反復処理できます。
例
# 创建销售数据
data = {
'地区': ['华北', '华东', '华南', '华北', '华东', '华南'],
'产品': ['A', 'B', 'C', 'B', 'A', 'C'],
'销售额': [1000, 2000, 1500, 1800, 2200, 1600]
}
df = pd.DataFrame(data)
print("生データ:")
print(df)
print()
# 各グループを走査して処理する
print("各グループの詳細情報:")
print("-" * 40)
for group_name, group_data in df.groupby('地区'):
print(f"\nグループ名: {group_name}")
print(f"このグループのデータ行数: {len(group_data)}")
print(f"このグループの売上総額: {group_data['销售额'].sum()}")
print(f"このグループの平均売上額: {group_data['销售额'].mean():.2f}")
print("-" * 40)
実行結果の予想:
原始数据: 地区 产品 销售额 0 华东 B 2000 1 华南 C 1500 2 华北 A 1000 3 华东 B 1800 4 华南 C 2200 5 华北 B 1800 每个分组的详细信息: ---------------------------------------- 分组名称: 华东 该组数据行数: 2 该组销售总额: 3800 该组平均销售额: 1900.00 ---------------------------------------- 分组名称: 华南 该组数据行数: 2 3700 1850.00 ---------------------------------------- 分组名称: 华北 该组数据行数: 2 2800 1400.00 ----------------------------------------
コード解析:
groupby()返されたグループオブジェクトは直接反復処理できます。各反復処理では、タプル(グループ名、そのグループのデータ)が返されます。- この方法を使用すると、各グループに対して任意の複雑なカスタム操作を実行できます。
- 実際のアプリケーションでは、この方法は複雑なレポートの生成やデータクレンジングによく使用されます。
ヒント:
groupby()返された GroupBy オブジェクトは「遅延実行」であり、結果をすぐには計算しません。集約関数を呼び出した場合のみ(例:sum()、mean()、count()など)または反復処理を行った場合にのみ、実際に計算が実行されます。
その他の拡張