Pandas - [4단계] 데이터 집계/요약/그룹화

c.haha.e·2025년 8월 12일

STUDY

목록 보기
6/27

데이터 집계/요약/그룹화


1. 기초 집계 함수

  • 데이터프레임에서 빠르게 요약 통계(합, 평균 등) 구할 수 있는 함수들
함수기능/설명예시 코드
sum()합계df['col'].sum()
mean()평균df['col'].mean()
count()개수(결측치 제외)df['col'].count()
max()최댓값df['col'].max()
min()최솟값df['col'].min()
std()표준편차df['col'].std()
var()분산df['col'].var()
median()중앙값df['col'].median()
describe()전체 요약(평균, 사분위수 등)df.describe()
  • axis 옵션
    • axis=0(기본): 컬럼
      "위에서 아래로(세로 방향)" → 행(row)을 따라 연산 → 컬럼 단위 계산
    • axis=1: 행 "왼쪽에서 오른쪽으로(가로 방향)" → 열(column)을 따라 연산 → 행 단위 계산

      각 함수에서 axis의 의미

      함수axis=0 (기본)axis=1
      sum()각 컬럼의 합각 행의 합
      mean()각 컬럼의 평균각 행의 평균
      dropna()결측치 있는 행 삭제결측치 있는 열 삭제
      drop()행 삭제열 삭제
      sort_values()(컬럼명 기준 정렬, axis=0만)(axis=1은 거의 안 씀)
      apply()각 컬럼에 함수 적용각 행에 함수 적용

      예시 코드

      import pandas as pd
      df = pd.DataFrame({
          'A': [1, 2, 3],
          'B': [10, 20, 30],
          'C': [100, 200, 300]
      })
      
      # 1) axis=0 (컬럼별, 기본)
      print(df.sum(axis=0))
      # A      6
      # B     60
      # C    600
      # 각 컬럼의 합
      
      # 2) axis=1 (행별)
      print(df.sum(axis=1))
      # 0    111  (1+10+100)
      # 1    222  (2+20+200)
      # 2    333  (3+30+300)
      # 각 행의 합
      
      # 3) dropna() 예시
      df2 = pd.DataFrame({'A':[1, None, 3], 'B':[4, 5, None]})
      print(df2.dropna(axis=0)) # 결측치 있는 "행" 삭제 (default)
      print(df2.dropna(axis=1)) # 결측치 있는 "열" 삭제
      
      # 4) drop() 예시
      print(df.drop(index=0))          # 첫 번째 "행" 삭제 (axis=0)
      print(df.drop(columns='B'))      # 'B' 컬럼 삭제 (axis=1과 같음)
      print(df.drop('B', axis=1))      # 'B' 컬럼 삭제 (axis=1)
      

      정리 그림 (머릿속 이미지)

      
           axis=0 ↓
           ┌─────┐
           │  A  │
           │  B  │
           │  C  │
           └─────┘
      <-- axis=1
      
      • axis=0: 세로 방향, 각 컬럼(열)에 대해 함수 적용

      • axis=1: 가로 방향, 각 행(row)에 대해 함수 적용


        실무 TIP

      • sum, mean, std, min, max, apply, dropna, drop, fillna

        거의 모든 판다스 연산에서 axis를 바꿔가며 쓸 수 있음

      • 헷갈릴 때는

        • axis=0 → "컬럼별", "행을 따라", "세로 연산"
        • axis=1 → "행별", "열을 따라", "가로 연산" 이라고 기억하면 실수 줄일 수 있음

2. 그룹화(groupby) – 집계의 핵심

(1) 기본 사용법

import pandas as pd
df = pd.DataFrame({
    '성별': ['남', '여', '여', '남', '여'],
    '점수': [80, 90, 75, 85, 95],
    '학년': [1, 2, 1, 3, 2]
})

g = df.groupby('성별')
print(g['점수'].mean())
# 성별
# 남    82.5
# 여    86.7
  • 그룹 단위로 집계 결과(Series/DataFrame) 반환

(2) 여러 컬럼 그룹화

g = df.groupby(['성별', '학년'])
print(g['점수'].mean())
  • 계층적 인덱스(MultiIndex) 생성

(3) 집계 함수 다양하게 적용 – agg()

  • 하나의 groupby에 여러 집계 함수 적용
g = df.groupby('성별')['점수'].agg(['mean', 'max', 'min'])
print(g)
#     mean  max  min
# 성별
# 남   82.5   85   80
# 여   86.7   95   75
  • 컬럼별로 다른 함수 적용

g = df.groupby('성별').agg({'점수': ['mean', 'std'], '학년': 'max'})

(4) transform()

  • 그룹별로 집계한 값을 원래 데이터 형태로 다시 매핑

df['성별평균'] = df.groupby('성별')['점수'].transform('mean')
  • 원본 DataFrame과 같은 크기로, 각 행에 그룹별 값이 붙음(실무에서 많이 쓰임!)

(5) filter()

  • 그룹 전체를 조건으로 걸러낼 때
# 평균 점수가 85 이상인 그룹만 남김
df.groupby('성별').filter(lambda x: x['점수'].mean() >= 85)

(6) apply()

  • 그룹별로 임의의 함수를 적용하고, DataFrame으로 반환
  • apply 기본 사용법

df.apply(함수, axis=0 또는 1)
  • 함수: 적용할 함수 (직접 만들 수도 있고, 파이썬 내장 함수도 가능)
  • axis: 축 방향
    • axis=0세로 방향 (열 단위로) 적용
    • axis=1가로 방향 (행 단위로) 적용

Series에서는 axis를 지정하지 않아도 됨

def custom_func(grp):
    return grp['점수'].sum() / (grp['점수'].count() + 1)

df.groupby('성별').apply(custom_func)

(7) as_index 옵션

  • 기본적으로 groupby의 그룹 컬럼이 인덱스가 됨
# as_index = False 옵션

df.groupby('성별', as_index=False)['점수'].mean()
# 결과: '성별'이 컬럼으로 나옴(인덱스 아님
  • as_index=False 옵션으로 컬럼으로 유지 가능

    기본적으로 groupby그룹 컬럼을 인덱스로 만든다

    예시:
    import pandas as pd
    
    df = pd.DataFrame({
        '과일': ['사과', '사과', '바나나', '바나나', '바나나'],
        '가격': [1000, 1500, 500, 700, 800],
        '수량': [1, 2, 3, 2, 1]
    })
    
    result = df.groupby('과일').sum()
    print(result)
    결과:
    
            가격  수량
    과일
    바나나   2000   6
    사과    2500   3
    
    • groupby('과일') 했더니, 과일 컬럼이 인덱스로 변함

    • 그리고 가격, 수량은 그룹별로 합쳐짐

      요약: 기본 설정은 as_index=True 이기 때문에 그룹핑한 컬럼이 인덱스가 됨


      2. as_index=False를 주면, 그룹 컬럼을 인덱스가 아니라 컬럼으로 유지할 수 있다

      as_index=False예시:

      result = df.groupby('과일', as_index=False).sum()
      print(result)

      결과:

      
            과일    가격  수량
      0   바나나  2000   6
      1    사과  2500   3
    • 과일이 인덱스가 아니라, 그냥 컬럼으로 남음

    • DataFrame 구조도 더 깔끔하게 유지.


      3. 정리

      상황설명결과
      as_index=True (기본값)그룹핑 컬럼을 인덱스로 보냄결과에서 컬럼이 인덱스에 들어감
      as_index=False그룹핑 컬럼을 컬럼으로 유지결과에서 컬럼이 그대로 남아있음

      4. 왜 이게 중요할까?

    • as_index=True: 분석/집계용 테이블 만들 때 좋음 (ex: pivot, multi-index 분석)

    • as_index=False: 결과를 다시 다른 컬럼들과 합치거나 쉽게 가공할 때 유리함

      예시:

      # 그룹 결과를 원본 데이터랑 merge하고 싶을 때
      grouped = df.groupby('과일', as_index=False).sum()
      merged = pd.merge(df, grouped, on='과일')

      → 이럴 때 as_index=False가 없으면 합치기 어려움


3. Pivot Table (피벗테이블)

  • 엑셀 피벗테이블과 동일
  • 다차원 집계, 교차표 요약에 매우 유용

(1) 기본 사용법

pd.pivot_table(df, index='성별', values='점수', aggfunc='mean')
  • 여러 집계함수
pd.pivot_table(df, index='성별', columns='학년', values='점수', aggfunc='mean', fill_value=0)
  • index, columns에 각각 기준 넣기 가능
  • aggfunc에 여러 함수도 가능(리스트로)
  • 자세한 내용

    Pivot Table (피벗테이블)란?

    • Pandas에서 pd.pivot_table() 함수

    • 엑셀 피벗 테이블거의 같음

    • 데이터를 그룹핑해서 집계(aggregation)하고 요약(summary)하는 데 최적화

    • 특히 2개 이상의 기준(행+열)을 기준으로 통계치 계산할 때 아주 유용


      1. 기본 구조

      pd.pivot_table(dataframe, index=기준_행, columns=기준_열, values=대상_값, aggfunc=집계함수, fill_value=대체값)
      파라미터설명
      index행(세로)로 사용할 컬럼
      columns열(가로)로 사용할 컬럼
      values집계할 대상 값 (숫자형 컬럼)
      aggfunc적용할 집계 함수 (평균, 합계, 최대값 등)
      fill_value결과에 NaN이 나오면 이걸로 채워라

      2. 예시

      import pandas as pd
      
      df = pd.DataFrame({
          '성별': ['남', '여', '남', '여', '남', '여'],
          '학년': [1, 1, 2, 2, 3, 3],
          '점수': [80, 90, 70, 85, 88, 95]
      })
      print(df)

      df 내용

      성별학년점수
      0180
      1190
      2270
      3285
      4388
      5395

      3. 기본 피벗 테이블 사용

      pd.pivot_table(df, index='성별', values='점수', aggfunc='mean')

      결과:

      성별점수
      79.333333
      90.0

      → 성별로 점수 평균을 구함


      4. 여러 기준 넣기 (index + columns)

      pd.pivot_table(df, index='성별', columns='학년', values='점수', aggfunc='mean')
      

      결과:

      학년123
      성별
      80.070.088.0
      90.085.095.0

    • 행: 성별

    • 열: 학년

    • 값: 평균 점수으로 교차표를 만든 거야.


      5. 빈칸 NaN을 채우고 싶으면 fill_value=

      pd.pivot_table(df, index='성별', columns='학년', values='점수', aggfunc='mean', fill_value=0)
    • NaN 대신 0으로 채워준다.

    • 특히 데이터가 빠질 수 있는 경우에 유용.


      6. aggfunc 여러 개 적용할 수도 있어!

      pd.pivot_table(df, index='성별', values='점수', aggfunc=['mean', 'max', 'min'])

      결과:

      성별meanmaxmin
      79.3333338870
      90.09585
    • 성별별로 평균, 최대, 최소 점수를 모두 계산해서 보여줘.

      aggfunc에 리스트를 넣으면 여러 집계 결과를 한꺼번에 보여줄 수 있어.


      7. 간단 요약표

      항목설명예시
      단일 집계한 가지 기준으로 통계평균점수만
      다중 집계여러 기준으로 통계평균, 최대, 최소 동시에
      여러 index, columns행, 열 모두 기준 설정 가능성별+학년별 평균점수
      fill_valueNaN 대신 다른 값 채우기fill_value=0

4. Cross Tab (교차표, 빈도표)

  • 범주형 변수 간 교차 빈도표 생성
pd.crosstab(df['성별'], df['학년'])
  • 행: 성별, 열: 학년, 값: 빈도수(교차 개수)
  • margins=True: 행/열의 총합
  • normalize=True: 비율(%)로 변환
  • 옵션
normalize 옵션의미합계가 1 되는 기준
True전체 데이터 대비 비율전체 합계
'index'행별 (성별 그룹별) 비율행별 합계
'columns'열별 (학년 그룹별) 비율열별 합계

pivot_table vs crosstab 차이

항목pivot_tablecrosstab
용도수치 데이터 집계 (sum, mean 등)범주형 데이터 빈도수 계산
대상 데이터수치형 중심범주형 중심
집계 함수자유롭게 지정 (aggfunc=)기본은 count(빈도)

쉽게 말하면:

  • pivot_table은 숫자 평균/합 구할 때,
  • crosstab은 범주를 셀때.

5. MultiIndex (다중 인덱스) 다루기

  • groupby, pivot 등으로 계층형 인덱스(튜플처럼 여러 단계) 생성됨

(1) 인덱스 리셋

df_grouped = df.groupby(['성별', '학년'])['점수'].mean().reset_index()

(2) 인덱스/컬럼 계층 변경

  • .set_index(), .reset_index(), .stack(), .unstack()

    1. .set_index()

    특정 컬럼을 인덱스로 설정하는 메서드

    사용법

    df.set_index('컬럼명')

    예제

    import pandas as pd
    
    df = pd.DataFrame({
        '이름': ['홍길동', '이순신', '강감찬'],
        '나이': [30, 40, 50],
        '점수': [80, 90, 100]
    })
    
    df.set_index('이름')
    결과:
    이름나이점수
    홍길동3080
    이순신4090
    강감찬50100
    • '이름'이 인덱스로 설정되었고,

    • '나이', '점수'는 그대로 컬럼으로 남음.


      2. .reset_index()

      "인덱스를 풀어 컬럼으로 만들기" (원래 데이터처럼 돌리기)

      사용법

      df.reset_index()
    • 기존 인덱스 → 컬럼으로 이동

    • 인덱스는 0,1,2 숫자 인덱스로 초기화

      예제

      df2 = df.set_index('이름')
      df2.reset_index()

      결과:

      이름나이점수
      0홍길동3080
      1이순신4090
      2강감찬50100
    • '이름'이 다시 컬럼으로 복구됐어.

    • 인덱스는 기본 숫자 0,1,2로 초기화.


      3. .stack()

      "열(columns)을 행(index)으로 내려서 세로로 쌓기"

    • 컬럼들을 행으로 바꾼다.

    • 데이터가 좁고 길게(long format) 변함.

      사용법

      df.stack()

      예제

      df2 = df.set_index('이름')
      df2.stack()

      결과:

      이름
      홍길동나이30
      홍길동점수80
      이순신나이40
      이순신점수90
      강감찬나이50
      강감찬점수100
    • 원래는 한 행에 있던 여러 컬럼들이

    • 각각 따로 행(row)으로 내려왔어.


      4. .unstack()

      "행(index)을 열(columns)로 올리기"

    • 행을 넓은 형태로 펼쳐서

    • 넓고 짧은(wide format) 테이블로 바꾼다.

      사용법

      df.unstack()

      예제

      df2 = df.set_index('이름')
      df2.stack().unstack()

      결과:

      이름나이점수
      홍길동3080
      이순신4090
      강감찬50100
    • 다시 원래 형태로 복구!


      4개 메서드 요약 비교

      메서드핵심 기능쉽게 말하면
      set_index()컬럼을 인덱스로"이거 기준으로 정렬할게"
      reset_index()인덱스를 컬럼으로 복구"인덱스 풀고 다시 평평하게"
      stack()열을 행으로"가로 → 세로" 좁게 세우기
      unstack()행을 열로"세로 → 가로" 넓게 펼치기

    • set_index() : 기준을 세운다 (정리 기준)

    • reset_index() : 기준을 풀고 그냥 컬럼으로

    • stack() : 데이터를 세워서 (길게)

    • unstack() : 데이터를 눕혀서 (넓게)


      요약 한 줄

      set_index/reset_index는 "어떤 컬럼을 인덱스로 쓸지" 정하는 거고,

      stack/unstack은 "행과 열을 변환해서" 데이터를 세우거나 눕히는 거다!

  • 복잡한 데이터를 행/열로 변환할 때 사용

6. 실무 꿀팁/자주 쓰는 패턴

  • 집계 함수 여러 개를 한 번에
    df.groupby('성별')['점수'].agg(['mean', 'count', 'max'])
  • 결과를 컬럼에 저장하고 싶을 때transform() 사용
  • 빈도/비율 구하기
    df['성별'].value_counts(normalize=True)  # 비율
    pd.crosstab(df['성별'], df['학년'], normalize='index')  # 행비율
  • groupby 후 sort_values로 정렬
    df.groupby('성별')['점수'].mean().sort_values(ascending=False)
    옵션
    ascending=True (기본값)오름차순 정렬 (작은 값 → 큰 값)
    ascending=False내림차순 정렬 (큰 값 → 작은 값)

7. 실전 예제 전체 코드

import pandas as pd

df = pd.DataFrame({
    '성별': ['남', '여', '여', '남', '여'],
    '점수': [80, 90, 75, 85, 95],
    '학년': [1, 2, 1, 3, 2]
})

# 1. 전체 평균
print(df['점수'].mean())

# 2. 성별별 평균
print(df.groupby('성별')['점수'].mean())

# 3. 성별/학년별 평균
print(df.groupby(['성별', '학년'])['점수'].mean())

# 4. 여러 집계함수
print(df.groupby('성별').agg({'점수':['mean','max','min'], '학년':'count'}))

# 5. 성별별 점수 합계로 새 컬럼
df['성별합계'] = df.groupby('성별')['점수'].transform('sum')
print(df)

# 6. 피벗테이블로 요약
print(pd.pivot_table(df, index='성별', columns='학년', values='점수', aggfunc='mean', fill_value=0))

# 7. 교차표(빈도)
print(pd.crosstab(df['성별'], df['학년']))

8. 주요 함수/옵션 정리

함수/메서드주요 옵션/역할실무 활용 예시
groupby()그룹 기준, as_index, dropna분류/집계/그룹별 분석
agg()여러 집계함수, 컬럼별 다르게복합 집계 통계
transform()그룹 집계값을 원본 크기로새 컬럼에 그룹 기준값 매핑
apply()그룹별 임의 함수 적용복잡한 커스텀 통계
filter()그룹 기준 조건 필터링그룹 조건에 따라 행 전체 걸러내기
pivot_table()index, columns, values, aggfunc, fill_value다차원 피벗/집계/결측치 보완
crosstab()index, columns, normalize범주형 빈도, 비율
reset_index()인덱스 → 컬럼MultiIndex 해제, 후처리

핵심 정리

  • 집계/요약: sum, mean, count, describe 등으로 전체 요약
  • 그룹화: groupby → 집계(agg, transform, apply, filter 등)
  • 피벗/교차표: pivot_table, crosstab
  • MultiIndex 관리: reset_index 등으로 평면화
  • 실전: 분석 목적별로 조합/응용
profile
기록용 블로그

0개의 댓글