메뉴 닫기

파이썬 pandas crosstab 교차표 완벽 가이드 normalize와 margins 사용법

파이썬 pandas crosstab 교차표 완벽 가이드 normalize와 margins 사용법

🧭 클릭 한 번으로 범주형 데이터를 표로 정리하고 비율까지 자동 계산하는 실전 스킬을 소개합니다

데이터를 분류해 비교하려다 엑셀에서 피벗을 반복하거나, 집계 공식을 매번 새로 쓰며 시간을 흘려보낸 경험이 한두 번이 아니죠.
pandas의 crosstab은 이런 수고를 줄이고, 범주형 변수의 관계를 한눈에 보여주는 교차표를 손쉽게 만들도록 도와줍니다.
간단한 함수 호출로 건수 합계부터 비율 계산, 전체 합까지 자동으로 정리할 수 있어 분석 리포트의 첫 화면을 빠르게 구축할 때 유용합니다.
특히 indexcolumns로 축을 지정하고, normalize로 비율을 계산하며, margins로 합계를 자동 추가하는 흐름을 익히면 분류 비교가 훨씬 명확해집니다.
오늘은 바로 그 핵심만 뽑아 실무에서 곧바로 적용할 수 있게 정리해 드립니다.

복잡한 전처리 없이도 교차표로 데이터의 분포, 편향, 패턴을 빠르게 확인하는 것이 가능해야 보고서의 방향을 일찍 잡을 수 있습니다.
이 글은 파이썬 pandas > 변환·정형화 > 교차표: crosstab(index, columns, normalize, margins)을 주제로, 최소한의 문법과 손에 익는 예시 중심으로 설명합니다.
설정이 헷갈리기 쉬운 비율 기준과 합계 행·열의 의미도 함께 짚어 오해를 줄이도록 구성했습니다.
데이터 분석 입문자도 따라 할 수 있도록 쉬운 표현을 유지하면서, 현업에서 바로 쓸 수 있는 체크리스트와 주의점까지 함께 담았습니다.



📊 교차표 개념과 crosstab 기본 문법

교차표는 두 개 이상의 범주형 변수를 행과 열로 배치해 빈도(건수) 또는 비율 분포를 한눈에 파악하게 하는 표입니다.
데이터의 편향, 상관 패턴, 이상치 의심 구간을 빠르게 확인하는 데 유용하며, 리포트 서두에서 상황을 요약하는 데 자주 활용됩니다.
pandas의 crosstab은 간결한 문법으로 교차표를 생성하고, 비율 계산(normalize)과 총합(margins)을 자동 추가할 수 있습니다.
핵심 축 지정은 indexcolumns로 수행하며, 이 두 인자를 통해 어떤 변수를 행·열로 둘지 명확히 결정합니다.

일반적으로 index에는 기준이 되는 주 변수를, columns에는 비교 대상 변수를 둡니다.
기본값은 건수 합계이며, 값 기반 집계를 원할 경우 valuesaggfunc를 함께 사용합니다.
비율이 필요할 때는 normalize 인자에 기준을 지정해 전체, 행, 열 단위로 비율을 계산할 수 있고, 합계 행·열을 추가하여 표 해석을 쉽게 하려면 margins=True를 지정합니다.

CODE BLOCK
import pandas as pd

# 예시 데이터프레임
# df.columns = ["gender", "purchase", "amount"]

# 1) 기본 교차표: 건수
pd.crosstab(index=df["gender"], columns=df["purchase"])

# 2) 값 기반 교차표: 합계(예: 구매금액 합)
pd.crosstab(index=df["gender"], columns=df["purchase"],
            values=df["amount"], aggfunc="sum")

# 3) 비율 교차표: 행 기준 비율
pd.crosstab(index=df["gender"], columns=df["purchase"],
            normalize="index")

# 4) 비율 + 합계 행/열 추가
pd.crosstab(index=df["gender"], columns=df["purchase"],
            normalize="index", margins=True, margins_name="All")

인자 설명
index 행 축으로 사용할 범주형 시리즈 또는 배열을 지정합니다.
columns 열 축으로 사용할 범주형 시리즈 또는 배열을 지정합니다.
normalize 비율 계산 기준을 선택합니다. all, index, columns 중 하나를 사용합니다.
margins True로 설정하면 합계 행과 합계 열을 추가합니다.

💎 핵심 포인트:

교차표의 기본은 축 배치입니다.
index가 행, columns가 열입니다.
비율은 normalize로 계산하고, 전체·행·열 중 어떤 기준인지 반드시 명시합니다.
총계를 함께 보고 싶다면 margins=True를 더하세요.

  • 🛠️indexcolumns에 범주형 변수가 맞는지 확인
  • ⚙️비율이 목적이면 normalize 기준(all, index, columns) 명확히 지정
  • 🔌요약 가독성을 위해 margins=Truemargins_name 활용

💡 TIP: 건수와 비율을 모두 보고 싶다면 동일한 index/columns로 두 개의 표를 만들고, 하나는 기본 건수, 다른 하나는 normalize를 지정해 나란히 배치하면 해석이 쉬워집니다.

⚠️ 주의: 누락값(NaN)이 많은 컬럼은 결과 해석을 왜곡할 수 있습니다.
필요 시 전처리(결측 대체 또는 필터링) 후 crosstab을 적용하세요.

🧱 index와 columns로 범주 결합하기

교차표의 뼈대는 indexcolumns를 어떻게 설정하느냐에 달려 있습니다.
행에는 보통 주 분석 대상을 두고, 열에는 그에 따른 세부 구분을 둡니다.
예를 들어 고객의 성별을 행으로, 상품 구매 여부를 열로 두면 성별에 따라 구매 여부가 어떻게 분포하는지 바로 확인할 수 있습니다.

복수의 변수를 동시에 조합해 교차표를 만들 수도 있습니다.
indexcolumns에 리스트 형태로 여러 변수를 전달하면, 다차원적 분류 결과를 손쉽게 요약할 수 있습니다.
이는 고객 세그먼트 분석, 실험군-통제군 비교, 지역별·연령대별 패턴 탐색에 매우 효과적입니다.

CODE BLOCK
# 단일 변수 교차표
pd.crosstab(index=df['gender'], columns=df['purchase'])

# 다중 변수 교차표 (행: 성별+연령대, 열: 상품 구매 여부)
pd.crosstab(index=[df['gender'], df['age_group']], 
            columns=df['purchase'])

💬 다중 index를 지정하면 행이 계층적 구조를 가지게 되어, 세부 집단별 비교가 가능해집니다.

구성 방식 설명
단일 index, 단일 columns 가장 기본적인 교차표, 두 변수의 빈도 비교
다중 index 여러 기준을 동시에 행에 배치해 세부 그룹을 나눔
다중 columns 열에서도 여러 변수를 지정해 복합 비교 가능

💎 핵심 포인트:

분석 목적에 따라 indexcolumns를 어떻게 배치할지가 달라집니다.
행에 ‘주 집단’, 열에 ‘조건 변수’를 둔다고 생각하면 이해하기 쉽습니다.

  • 🛠️
    단일 변수 비교라면 간단히 index, columns 한 개씩 지정
  • ⚙️
    여러 조건을 동시에 확인할 때는 리스트 형태로 다중 지정
  • 🔎
    결과 해석 시 행과 열이 계층 구조인지 반드시 확인



📐 normalize 옵션으로 비율 계산하기

교차표는 기본적으로 각 범주 조합의 빈도(건수)를 보여줍니다.
하지만 많은 경우 단순 건수보다 비율이 더 직관적으로 해석됩니다.
예를 들어, 전체 고객 중 특정 상품 구매자가 몇 퍼센트인지, 성별 그룹별로 선호도가 어떻게 달라지는지를 보려면 normalize 옵션을 활용해야 합니다.

pandas의 crosstab에서 normalize 인자는 다음과 같은 값을 가질 수 있습니다.

옵션 값 설명
all 전체 표 기준 비율 (전체 합 = 1)
index 행별 기준 비율 (각 행 합 = 1)
columns 열별 기준 비율 (각 열 합 = 1)
CODE BLOCK
# 전체 비율
pd.crosstab(index=df['gender'], columns=df['purchase'], normalize='all')

# 행 기준 비율 (성별별 구매 비율)
pd.crosstab(index=df['gender'], columns=df['purchase'], normalize='index')

# 열 기준 비율 (구매 여부별 성별 비율)
pd.crosstab(index=df['gender'], columns=df['purchase'], normalize='columns')

💎 핵심 포인트:

normalize 옵션은 비율 계산 기준을 지정합니다.
행 단위 패턴을 비교할 때는 index, 열 단위 비중을 확인할 때는 columns, 전체 비중은 all을 사용하세요.

💬 normalize를 지정하지 않으면 단순 건수 집계가 반환됩니다.
비율 해석이 필요한 경우 반드시 기준을 명확히 선택하세요.

  • 📊
    전체 비율 확인 → normalize=’all’
  • 📈
    행 단위 패턴 비교 → normalize=’index’
  • 📉
    열 단위 비중 확인 → normalize=’columns’

⚠️ 주의: 비율 계산은 소수점이 긴 값으로 표시될 수 있습니다.
보고용 자료에서는 round() 함수를 함께 사용해 적절히 반올림하는 것이 좋습니다.

margins 옵션으로 합계 추가하기

데이터를 표로 정리했을 때, 전체 합계 행과 열이 함께 표시되면 분석이 훨씬 수월해집니다.
pandas crosstabmargins 옵션은 바로 이 기능을 담당합니다.
기본값은 False이며, margins=True를 지정하면 표의 마지막 행과 마지막 열에 총계가 추가됩니다.

이때 합계 행·열의 이름은 기본적으로 All로 표시되지만, margins_name 인자를 활용하면 원하는 이름으로 바꿀 수 있습니다.
예를 들어 “합계”, “전체”와 같은 한글 레이블로 지정해 리포트 가독성을 높이는 방식이 자주 쓰입니다.

CODE BLOCK
# 합계 행과 열을 추가
pd.crosstab(index=df['gender'], columns=df['purchase'], margins=True)

# 합계 이름 지정
pd.crosstab(index=df['gender'], columns=df['purchase'], 
            margins=True, margins_name='합계')

💬 margins 옵션은 특히 프레젠테이션용 표를 만들 때 유용합니다.
전체 규모를 바로 확인할 수 있어 수치 해석이 간결해집니다.

옵션 동작
margins=True 합계 행과 열 자동 추가
margins_name 합계 행/열 이름 지정 가능 (기본값 All)

💎 핵심 포인트:

총계가 있어야 전체 대비 비율이나 비중을 빠르게 해석할 수 있습니다.
실무 보고서라면 margins를 적극적으로 사용하는 것이 좋습니다.


  • 전체 합계를 확인하고 싶다면 margins=True
  • ✍️
    보고용 표에서는 margins_name으로 레이블 커스터마이즈
  • ⚙️
    비율 교차표에서도 합계는 자동 계산되어 함께 제공

⚠️ 주의: 다중 변수 조합에서 margins를 켜면 표가 커져 가독성이 떨어질 수 있습니다.
필요에 따라 합계만 따로 계산해 추가하는 것도 방법입니다.



🧪 실전 예제와 해석 포인트

이제까지 살펴본 index, columns, normalize, margins를 종합해 실제 데이터를 예로 들어 보겠습니다.
가상의 고객 데이터에서 성별(gender)과 상품 구매 여부(purchase)를 기준으로 교차표를 만든다고 가정해 보겠습니다.

CODE BLOCK
import pandas as pd

data = {
    "gender": ["M","F","M","F","F","M","M","F"],
    "purchase": ["Yes","No","Yes","Yes","No","No","Yes","No"]
}
df = pd.DataFrame(data)

# 교차표 생성 (건수 + 합계)
table1 = pd.crosstab(index=df['gender'], columns=df['purchase'], margins=True, margins_name='합계')

# 행 기준 비율 + 합계
table2 = pd.crosstab(index=df['gender'], columns=df['purchase'],
                     normalize='index', margins=True, margins_name='합계')

print(table1)
print(table2.round(2))

성별 No Yes 합계
F 2 1 3
M 1 3 4
합계 3 4 7

위 결과를 보면 남성은 4명 중 3명이 구매하여 구매율이 75%에 달하며, 여성은 3명 중 1명만 구매하여 33% 수준임을 알 수 있습니다.
합계 행을 통해 전체 구매율은 약 57%라는 사실도 확인됩니다.
이처럼 crosstab은 단순 빈도뿐 아니라, 그룹별 패턴을 직관적으로 파악하는 데 매우 강력합니다.

💎 핵심 포인트:

교차표 해석 시에는 단순 건수와 비율을 모두 확인해야 합니다.
건수는 데이터의 크기를, 비율은 그룹 간 차이를 보여줍니다.

  • 🧾
    건수 교차표와 비율 교차표를 함께 비교하면 더 명확한 인사이트 확보
  • 📊
    합계 행·열은 전체 분포와 비율을 빠르게 파악하는 데 필수
  • 🔎
    작은 표본에서는 비율 해석 시 과대해석에 주의

⚠️ 주의: 교차표는 범주형 데이터에 적합합니다.
연속형 변수는 binning(구간 나누기) 후 적용해야 의미 있는 해석이 가능합니다.

자주 묻는 질문 (FAQ)

crosstab과 pivot_table의 차이는 무엇인가요?
pivot_table은 보다 유연하게 다양한 집계를 지원하는 반면, crosstab은 범주형 변수 간 빈도와 비율을 빠르게 요약하는 데 특화되어 있습니다.
normalize 옵션을 쓰면 합계가 항상 1이 되나요?
네, 기준을 전체, 행, 열 중 어디로 설정하든 합계가 1이 되도록 비율이 계산됩니다.
margins와 normalize를 동시에 쓸 수 있나요?
가능합니다. 비율 교차표에도 합계 행과 열이 추가되며, 이 경우에도 비율 기준을 따릅니다.
결측값이 있으면 어떻게 되나요?
기본적으로 NaN은 교차표에서 제외됩니다. 필요하다면 fillna 등 전처리 과정을 거친 후 사용하는 것이 좋습니다.
crosstab으로 숫자형 데이터를 집계할 수 있나요?
네, values와 aggfunc 인자를 지정하면 합계, 평균, 최대값 등 원하는 방식으로 숫자 데이터를 집계할 수 있습니다.
비율 교차표를 소수점 2자리까지만 표시하려면 어떻게 하나요?
round() 함수를 함께 사용하면 됩니다. 예: pd.crosstab(…, normalize=”index”).round(2)
crosstab 결과를 엑셀로 내보낼 수 있나요?
네, DataFrame 객체이므로 to_excel(), to_csv() 등의 메서드를 사용해 바로 내보낼 수 있습니다.
교차표가 너무 커질 때는 어떻게 해야 하나요?
범주 수가 많을 경우 시각화를 병행하거나 주요 그룹만 추출해 분석하는 것이 효과적입니다.

📊 pandas crosstab 활용 핵심 정리

pandas crosstab은 범주형 데이터를 비교하고 분포를 파악할 때 매우 유용한 도구입니다.
indexcolumns로 행과 열의 기준을 설정하고, normalize를 통해 건수를 비율로 변환하며, margins로 합계를 추가하면 분석의 완성도가 크게 높아집니다.
단순 빈도표를 넘어, 패턴 탐색, 그룹 간 차이 비교, 리포트 요약 등에 널리 쓰일 수 있습니다.

실무에서는 건수와 비율 교차표를 나란히 비교해 해석하는 방식이 효과적입니다.
또한 보고용 자료에서는 소수점 자리수를 조정하거나 합계 레이블을 직관적으로 바꾸어 가독성을 높이는 것이 좋습니다.
특히 고객 세분화, 설문조사 응답 분석, 마케팅 캠페인 성과 측정 등 다양한 분야에서 빠른 의사결정을 지원할 수 있습니다.

데이터 분석 입문자부터 전문가까지, 교차표는 가장 기본적이면서도 강력한 도구입니다.
pandas crosstab을 숙지해 두면 반복되는 분석 작업에서 시간을 절약하고, 설득력 있는 시각자료를 만들 수 있습니다.


🏷️ 관련 태그 : pandas, 파이썬데이터분석, 교차표, crosstab, 데이터전처리, 데이터시각화, 데이터프레임, 파이썬기초, 분석자동화, 데이터통계