파이썬 판다스(pandas)에서 범주형 데이터 2개를 비교분석할 때 유용한 표, 교차분석표(crosstab)에 대해 알아보자.
이러한 교차분석표는 각 범주형 데이터의 개수를 행과 열로 cross해놓은 표를 의미한다.
다음은 pandas crosstab 공식 문서를 참고하였다.
pd.crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False)
- 필수 input
- index: 행으로 그룹화할 값 (array, series, list)
- columns: 열로 그룹화할 값 (array, series, list)
- Optional
- rownames: 행 이름
- colnames: 열 이름
- values: 두 행/열에 따라 집계할 값. 반드시 aggfunc와 함께 사용
- aggfunc: 집계 함수 ex. mean, sum 등
- margins: True로 지정 시 행/열의 소계값이 함께 산출
- margins_name: margins = True인 경우, 행/열의 소계를 뽑을 행/열을 지정(디폴트: 'All')
- dropna: NaN을 포함하지 않고 반환 (디폴트: True)
- normalize: 개수가 아닌 비율로 표시. 옵션은 3가지가 있다
- index: 행을 기준으로 비율 표시 (각 행의 합 = 100%)
- columns: 열을 기준으로 비율 표시 (각 열의 합 = 100%)
- all: 전체 기준으로 비율 표시 (각 데이터들의 합 = 100%)
예제 데이터로 어떻게 사용하는지 알아보자 :)
여기서 사용한 데이터는 캐글 Categorical Feature Encoding Challenge의 'train.csv' 데이터셋이다.
import pandas as pd
df = pd.read_csv('train.csv', index_col = 'id')
df.head()
데이터프레임 df에는 많은 컬럼들이 있는데, 여기서 활용할 컬럼은 nom_1과 target이라는 두 범주형 데이터이다.
nom_1는 총 6가지의 도형 값, target은 0, 1의 값을 가지고 있다.
각 값별로 행-열을 cross하여 개수를 셀 때 crosstab을 활용한다.
# 개수(빈도)
pd.crosstab(df['nom_1'], df['target'])
이렇게 교차표로 보니 각 값별로 몇 개나 있는지 한 눈에 들어와서 보기가 편하다.
이번엔 margins = True 옵션을 사용하자. 행/열 소계를 구해준다.
pd.crosstab(df['nom_1'], df['target'], margins = True)
# 이것도 동일
pd.crosstab(df['nom_1'], df['target'], margins = True, margins_name = 'All')
이렇게 'All' 이라는 새로운 값이 행, 열에 생긴다.
즉, 각 행별 합계 및 각 열별 합계값인 소계를 구해준다.
# 비율
나는 nom_1의 값에 따라 target이 1인 "비율"이 궁금하다. 그럼 normalize 옵션을 사용해보자.
pd.crosstab(df['nom_1'], df['target'], normalize = 'all')
먼저 normalize = 'all'을 사용하면 전체 기준으로 비율을 표시한다. 즉 저 셀값들을 전부 더하면 1 (100%)이 된다.
그러나 이는 내가 원하는 게 아니다. nom_1의 값에 따른 target의 비율이므로 normalize를 'nom_1'을 기준으로 해야 한다.
# 개수가 아닌 비율 - index 기준
pd.crosstab(df['nom_1'], df['target'], normalize = 'index')
위와 달라진 점을 눈치챘는가? index 즉, 'nom_1'를 기준으로 normalize하면 이렇게 행별 합이 1 (100%)이 된다.
이렇게 되면 'nom_1'이 Circle일 때 target이 1인 비율은 약 25%구나! 라는 것을 알 수 있다.
마찬가지로 normalize 기준을 columns로 할 수도 있다.
# 개수가 아닌 비율 - columns 기준
pd.crosstab(df['nom_1'], df['target'], normalize = 'columns')
columns를 기준으로 하면 'target' 별 'nom_1'의 값을 뽑는다.
즉 열별 합이 1 (100%)이 되며, target의 값이 0인 애들 중에 circle는 약 14%구나, polygon은 약 12%구나 등을 알 수 있다.
그리고 당연히 비율로 나타낸 상태에서도 margins 옵션을 사용해 소계를 뽑을 수 있다.
pd.crosstab(df['nom_1'], df['target'], normalize = 'columns', margins = True)
columns로 normalize하였으므로 각 열별 합이 1이다.
여기서 새로운 'All' 컬럼이 생겼는데, 이는 target의 값을 나누지 않고 nom_1 고유값들의 비율을 나타낸 것이다.
즉, Circle은 전체의 12%, Polygon은 전체의 12%를 차지한다는 의미!
# 백분율
pd.crosstab(df['nom_1'], df['target'], normalize = 'index')*100
뒤에 100을 곱해주면 손쉽게 백분율 값을 구할 수 있다.
마지막으로, 나는 nom_1의 각 고유값에 따른 target == 1인 비율을 구하고자 하였으므로...
ct = pd.crosstab(df['nom_1'], df['target'], normalize = 'index')*100
ct[1]
이렇게 crosstab을 'ct' 객체로 저장한 후 1번을 뽑으면 된다.
ct[1].values
values 옵션을 활용하면 쉽게 이 값들만 쏙 뽑을 수 있다.
'Skillset > Python, Git' 카테고리의 다른 글
[시각화] 파이썬 이중 Y축 그래프 그리기 (ax.twinx) (0) | 2022.07.12 |
---|---|
[pandas] 순서가 있는 범주형 데이터에 순서 지정하기 - CategoricalDtype (0) | 2022.07.11 |
[시각화] 파이썬 그래프 위에 글자 쓰기 (ax.patches, ax.text) (0) | 2022.07.09 |
python sample 함수 사용법과 예제 (0) | 2022.07.04 |
[pandas] Series & DataFrame에서 자주 사용하는 유용한 메서드 (2) (0) | 2022.06.27 |