본문 바로가기
목차
Python/pandas

[Pandas] groupby() 메서드

by ds31x 2025. 8. 20.
728x90
반응형

https://datadoctorblog.com/2023/04/28/Py-Basic-Pandas-Groupby/

 

groupby() 메서드는 DataFrame의 데이터를 하나 이상의 키를 기준으로 그룹화(grouping) 하여, 각 그룹에 대해 집계(aggregation)·변환(transform)·필터(filter) 연산을 적용할 수 있게 해주는 도구임.

  • Split–Apply–Combine 패턴: 데이터를 나누고(split) → 그룹별 연산을 적용(apply) → 결과를 결합(combine)
  • groupby 자체는 DataFrameGroupBy 또는 SeriesGroupBy 객체를 반환하며, 집계(aggregation), 변환(transform), 필터(filter) 같은 후속 연산(주로 aggregate function임)이 필요
    • 참고로, DataFrameGroupBy의 obj 속성은 대상이 되었던 원본 데이터프레임을 가리킴.
    • 비슷하게, SeriesGroupBy의 obj 속성은 대상이 되었던 원본 시리즈를 가리킴.

참고로, 

  • aggregate function을 통과하면 나면 DataFrame 객체가 됨.
  • groupby() 이후에 "대상변수"로 특정 column을 지정하고 aggregate function (mean())을 수행하면 Series객체가 됨.

Signature

DataFrame.groupby(
    by=None,               # labels/column names/arrays/dict/callable
    axis=0,                # 0 = index (행 기준), 1 = columns (열 기준): deprecated예정.
    level=None,            # MultiIndex 레벨
    as_index=True,         # 그룹 키를 인덱스로 반환할지 여부
    sort=True,             # 그룹 키 정렬 여부
    # group_keys=True,       # apply 결과에 그룹 키 포함 여부: deprecated예정
    observed=False,        # categorical 그룹 시, 미등장 카테고리 포함 여부
    dropna=True            # NA 그룹 제거 여부
) -> DataFrameGroupBy | SeriesGroupBy

by 파라메터

  • 설명: 그룹핑 기준으로 컬럼명, 리스트, 배열, dict, callable(함수) 모두 가능.

주로, column name (str)과 여러 column names로 구성된 list객체, list형태로 그룹을 나타내는 배열을 넘겨주는 방식이 사용됨.

    • column name과 column names를 주로 사용.
    • list 객체를 이용한 배열을 사용할 때는
      • axis=0이면 배열의 item의 수가 DataFrame의 row수와 같아야 함: 배열의 각 item이 그룹키임.
      • axis=1이면 배열의 item의 수가 DataFrame의 column수와 같아야 함: 배열의 각 item이 그룹키임.
      • 단, axis는 Pandas2.3.1에서 groupby()에서 할당한 경우, FutureWarning이 발생함:
        "deprecated" 예정임.

다음은 예제를 위한 기본 DataFrame임.

import pandas as pd

# 1) 기본 예제 데이터
df = pd.DataFrame({
    "class": ["A","A","A","B","B","C","C","C","C"],
    "sex":   ["F","M","F","M","F","M","F","F","M"],
    "score": [80, 70, 90, 60, 75, 88, 92, 85, 73],
    "age":   [20, 22, 21, 24, 23, 26, 22, 21, 27],
})


by의 기본사용

가장 기본적인 그룹별 평균을 보는 예제로서 class별로 평균을 구함.
단, numeric_only=True를 해줘야만 동작함: categorical column sex 를 평균계산에서 제외해야 하므로.

print(df.groupby("class").mean(numeric_only=True))


그룹별로 처리하면서 결과물 중 특정 column의 값을 지정하여 확인 가능함.

다음은 "score"에 대해 "class"별로 평균을 보여줌.

# 단일 컬럼명
print(df.groupby("class")["score"].mean())


subgrouping

다음과 같이 "class"로 그룹을 짓고 이후 "sex"로 다시 그룹(sub-group)을 짓는 처리도 가능: multiple column grouping.

# 다중 컬럼명
print(df.groupby(["class","sex"])["score"].mean())


배열로 그룹지정

다음은 index 별로 그룹을 할당하는 배열을 list객체를 이용하여 그룹핑하는 예제임.
홀수번째 row와 짝수번째 row별 "score" 평균을 보여줌:

# 배열
row_groups = [i % 2 for i in range(len(df))]
print(df.groupby(row_groups)["score"].mean())


dict 객체

dict 객체를 사용하는 경우엔 axis와 같이 주어지는 경우도 가끔 있음.

  • axis=0: dict의 key는 인덱스 라벨, value는 그룹 키
  • axis=1: dict의 key는 컬럼 라벨, value는 그룹 키

axis=1 인 경우는 많이 쓰이지 않으나
column을 합쳐 처리해야 하는 경우 일부 사용되었음.
deprecated 예정이니 주의할 것.

 

다음은 index 들에 대해 그룹을 "A","B"로 할당한 후, 각 그룹별 합을 구함:

# dict + axis=0 (index 매핑)
df_idx = pd.DataFrame({"val":[10,20,30]}, index=["row1","row2","row3"])
map_idx = {"row1":"A","row2":"A","row3":"B"}
print(df_idx.groupby(map_idx, axis=0).sum())


다음은 자주 쓰이진 않으나 column들을 그룹짓는 방법임.
column중, "score""age""metrics"라는 그룹으로, "height""size"로 그룹지어 각각의 평균을 구함.

row의 수는 보존되나 column의 수는 2개로 줄어들게 됨: height는 단일 column이 하나의 그룹이니 값은 그대로임.

# dict + axis=1 (column 매핑)
df_cols = pd.DataFrame({
    "score":[80,70,90],
    "age":[20,22,21],
    "height":[170,180,160]
})
map_cols = {"score":"metrics","age":"metrics","height":"size"}
print(df_cols.groupby(map_cols, axis=1).mean())


Callable 객체

callable 객체(함수)도 사용가능함.
아주 복잡한 처리등이 필요할 때 사용 가능함.

다음은 index 라벨 길이에 따라 행들이 그룹화되고, 각 그룹별로 합을 값으로 가짐.

# 예제 DataFrame (인덱스 라벨이 길이가 서로 다름)
df_callable = pd.DataFrame(
    {"val":[1,2,3,4]}, 
    index=["aa", "bbb", "cccc", "aa"]
)

# callable 함수: index 라벨(x)의 길이를 그룹 키로 사용
out_callable = df_callable.groupby(lambda x: len(x)).sum()

print(out_callable)


axis 파라메터: deprecated 예정.

  • 설명: 그룹핑 방향 선택.
  • axis=0 (default): 행 기준 그룹핑 (가장 일반적)
  • axis=1: 열 기준 그룹핑 (dict 및 배열로 열 이름을 매핑할 때 사용)

앞서의 기본적 by 파라메터 설명의 예제에서 axis=0이 기본이므로 생략된 것임.

# axis=0
print(df.groupby("class", axis=0).mean(numeric_only=True))

  • 위의 예는 FutureWarning이 발생함.

앞서의 dict 객체를 by 파라메터로 사용한 예제도 확인할 것.


level 파라메터

  • 설명: MultiIndex에서 특정 level(레벨)로 그룹핑.
    • 이름 또는 정수 인덱스 둘 다 사용가능.
    • index가 list객체로 할당되어 다중 인덱스인 경우에 사용가능.

다음과 같이 .set_index()를 통해 다중 인덱스 설정된 DataFrame객체에서 사용가능.

df = pd.DataFrame({
    "class": ["A","A","A","B","B","C","C","C","C"],
    "sex":   ["F","M","F","M","F","M","F","F","M"],
    "score": [80, 70, 90, 60, 75, 88, 92, 85, 73],
    "age":   [20, 22, 21, 24, 23, 26, 22, 21, 27],
})

# MultiIndex 예제
df_mi = df.set_index(["class", "sex"]).sort_index()


다음은 정수 인덱스로 사용한 경우:

print(df_mi.groupby(level=0)["score"].mean())       # class 레벨


다음은 index 라벨 값으로 사용한 경우:

print(df_mi.groupby(level="sex")["score"].mean())       # class 레벨


as_index 파라메터

  • 설명: 그룹에 사용된 키 (by로 지정된)를 결과 반환 객체의 인덱스로 사용할지 여부

기본적으로는 as_index=True임:

print(df.groupby("class", as_index=True).mean(numeric_only=True))


as_index=False를 하는 경우는 중간결과물을 얻어 merge등을 할 때 사용하기 위해서임.

print(df.groupby("class", as_index=False).mean(numeric_only=True)) # as_index=False


sort 파라메터

  • 설명: 반환되는 객체의 row들을 그룹 키로 정렬할지 여부

기본적으로 sort=True

print(df.groupby("class", sort=True)["score"].mean())


sort=False 인 경우 (그룹 키로 정렬임):

print(df.groupby("class", sort=False)["score"].mean()) 

group_keys 파라메터: deprecated 예정.

deprecated 될 예정이므로 자세한 설명은 생략

  • 설명: apply 결과에 그룹 키 포함 여부

observed 파라메터

  • 설명: categorical 그룹에서 미등장 카테고리 포함 여부

일반적으로 등장하지 않는 cateogory는 빼고 처리함: observed=True

df_cat = df.copy()
df_cat["sex"] = pd.Categorical(df_cat["sex"], categories=["F","M","X"])  # X는 미등장

print(df_cat.groupby("sex", observed=True)["score"].mean())   # F, M

다음은  sex 열을 categorical column으로 만들고, 가질 수 있는 카테고리를 F,M,X 3가지로 만듬

여기서 결과는 다음과 같음

 


observed=False인 경우 등장하지 않는 category까지 다 보여줌:

print(df_cat.groupby("sex", observed=False)["score"].mean())  # F, M, X


dropna 파라메터

  • 설명: NA (Not Available) 그룹 제거 여부
    • 그룹키로 지정한 column의 데이터가 NA/NaN인 경우 해당 row를 그룹핑에서 제거.
    • dropna=False이면 NaN그룹이 하나 추가됨.

다음과 같이 그룹핑의 기준이 되는 "class"None인 row를 추가.

# DataFrame 복사 후, 특정 행(class 컬럼)을 None(=NA)으로 변경
df_na = df.copy()
df_na.loc[2, "class"] = None   # 3번째 행의 class 값 → NA
df_na


기본적으로 dropna=True임:

# dropna=True (기본값)
# - NA 값이 그룹 키일 경우, 해당 행은 그룹핑에서 제외
out_dropna_true = df_na.groupby("class", dropna=True)["score"].mean()
print(out_dropna_true)


다음은 dropna=False인 경우:

# dropna=False
# - NA 값도 하나의 그룹으로 취급
# - 즉, "class=None"인 행들이 모여 별도의 그룹으로 결과에 포함됨
out_dropna_false = df_na.groupby("class", dropna=False)["score"].mean()
print(out_dropna_false)


pivot_table과의 관계

pivot_table()은 groupby + agg + unstack 과정을 한 번에 처리하는 구문 설탕(syntactic sugar)

  • groupby()의 그룹핑 결과는 보통 MultiIndex 형태로 반환됨
  • MultiIndex는 예를 들어 class와 sex의 조합으로 구성됨.
  • 이를 사람이 읽기 좋은 가로 방향(wide form) 으로 변환할 때 unstack()을 사용.
  • 예를 들어 df.groupby(["class","sex"])["score"].mean().unstack("sex") 는 class를 행, sex를 열로 하는 표 형태를 만들어 줌.
    • 표에서의 item의 값은 score에 기반하며 class와 sex의 조합에 여러 score 가 있다면 평균을 취함.

다음 예제를 잘 살펴볼 것:

import pandas as pd

# 예제 데이터
df = pd.DataFrame({
    "class": ["A","A","B","B"],
    "sex":   ["F","M","F","M"],
    "score": [80, 70, 90, 60]
})

# 1) groupby 결과 (MultiIndex)
mean_long = df.groupby(["class", "sex"])["score"].mean()
print("=== groupby 결과 (long form, MultiIndex) ===")
print(mean_long)
print()

# 2) unstack으로 wide form 변환
mean_wide = mean_long.unstack("sex")
print("=== unstack 결과 (wide form) ===")
print(mean_wide)

출력은 다음과 같음:

=== groupby 결과 (long form, MultiIndex) ===
class  sex
A      F      80
       M      70
B      F      90
       M      60
Name: score, dtype: int64

=== unstack 결과 (wide form) ===
sex     F   M
class        
A      80  70
B      90  60
  • unstack()는 stacked 인 long form을 wide form으로 변경시킴.

같이보면 좋은 자료들

2025.08.20 - [Python] - [Term] pivot 이란?

 

[Term] pivot 이란?

1. pivot 이란?Pandas에서 pivot은 데이터의 모양(shape)을 바꾸는 기능 을 가리킴: reshaping특정 column의 값들을 row 인덱스(index)로,또 다른 column의 값들을 열(columns)로지정하는 테이블을 만들고, 해당 조합

ds31x.tistory.com

2025.08.19 - [Python] - [Pandas] pivot_table 메서드

 

[Pandas] pivot_table 메서드

.pivot()과 같이 reshaping이 가능한 메서드.차이점은 .pivot()은 행-열 조합에 중복되는 요소가 있는 경우 에러가 발생하나,.pivot_table()은 aggregation을 통한 하나의 대표값으로 처리가 가능함.groupby+aggrega

ds31x.tistory.com

2025.05.16 - [Python] - [ML] pandas.DataFrame 에서 EDA에 적합한 메서드 요약

 

[ML] pandas.DataFrame 에서 EDA에 적합한 메서드 요약

Pandas DataFrame에서 탐색적 데이터 분석(EDA)에 사용할 수 있는 주요 메서드들은 다음과 같음:2024.05.18 - [분류 전체보기] - [ML] Exploratory Data Analysis (EDA) [ML] Exploratory Data Analysis (EDA)Exploratory Data Analysis (

ds31x.tistory.com

 

728x90