이변량 분석은 타겟(y)과 변수(x)와의 관계를 살펴보는 작업이다.
이 작업에서 우리가 세운 가설이 타당한 지를 확인한다.
귀무가설: X와 Y가 관계가 없다.
대립가설: 우리가 세운 가설로, X에 따라 Y가 차이가 있다.
X와 Y가 숫자냐, 범주냐에 따라서 사용하는 도구들이 달라진다.
아래 표를 참고하자(절대적인 기준은 아님).

이미지 출처: https://github.com/DA4BAM/image
상관관계를 분석하는 것으로, 숫자형(연속형)에 대해서 사용가능하다.
결측치가 존재할 경우 계산되지 않는다.
얼마나 직선으로 값들이 모여 있는지에 대한 수치화이다.
상관분석의 한계는 관계가 있지만 직선이 아닌 경우엔 해당 도구로 관계가 없다고 판단될 수 밖에 없다.상관계수는 r로 표현된다.
r은 -1 ~ 1 사이 값이다.
, 즉 -1 또는 1에 가까울수록 강한 상관관계를 나타낸다.
cf) 절대적인 기준이 아니며, 강사님 경험에 의한 대략적인 기준이다.
범주형 X와 숫자형(연속형) Y일 때 사용가능하다.범주형 X의 범주가 2개일 때 사용가능하다.결측치가 있으면 계산되지 않는다.t통계량은 두 평균의 차이를 표준오차로 나눈 값이다.-2보다 작거나 2보다 크면 차이가 있다고 본다(대립가설 채택). 범주형 X와 숫자형(연속형) Y일 때 사용가능하다.범주가 3개 이상일 때 사용가능하다.F통계량은 분산비이다.2~3 이상이면 차이가 있다고 본다(대립가설 채택).결측치가 존재하면 계산되지 않는다.숫자형(연속형) X와 범주형 Y일 때 사용할 가설검정 도구가 없다.p-value를 구하여 검정한다.5%(0.05)미만이면 차이가 있다고 본다(대립가설 채택).미봉책으로 너무 믿지는 말자.결측치가 존재하면 계산되지 않는다.범주형 X와 범주형 Y일 때 사용가능하다.
카이는 그리스문자 를 뜻한다.
카이제곱검정은 카이제곱 분포에 기초한 통계적 방법으로 범주형 변수들 사이에 어떤 관계가 있는 지를 수치화해준다.
관찰된 빈도가 기대되는 빈도와 유의하게 다른지를 검정한다.
기대빈도: 귀무가설이 참이면 나올 수 있는 값들카이제곱검정을 통해 얻는 카이제곱통계량은 클수록 기대빈도와 값 차이가 크다는 의미이다.
하지만 수식을 보면 범주 수가 많을수록 카이제곱통계량은 커지게 되어있음을 알 수 있다.
따라서 보통 자유도의 2~3배보다 크면 차이가 있다고 본다.
범주형 변수의 자유도: 범주 수 - 1
카이제곱검정에서 자유도: x변수의 자유도 * y변수의 자유도
(5 - 1) * (2 - 1) = 4이다.이제곱통계량이 자유도 4의 2~3배인 8~12보다 크면 차이가 있다고 볼 수 있다.import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
titanic = pd.read_csv('https://raw.githubusercontent.com/DA4BAM/dataset/master/titanic.0.csv')  # 타이타닉 데이터
air = pd.read_csv('https://raw.githubusercontent.com/DA4BAM/dataset/master/air2.csv')  # 뉴욕시 공기 오염도 데이터
데이터 출처: https://github.com/DA4BAM/dataset
x와 y분할과 train, val, test 셋분할은 여기서 생략하여 진행한다.
plt.scatter(air['Temp'], air['Ozone'])
plt.show()
또는
plt.scatter(x='Temp', y='Ozone', data=air)
plt.show()
sns.lmplot(x='Temp', y='Ozone', data=air)
plt.show()
sns.pairplot(air)
plt.show()
import scipy.stats as spst
튜플로 결과값을 출력한다.
첫 번째 값은 상관계수, 두 번째 값은 p-value이다.
결측치가 존재하면 계산되지 않는다.-1 또는 1에 가까울수록 강한 상관관계p-value는 5%(0.05)미만일 경우 x에 따라 y에 차이가 있다고 본다.spst.pearsonr(air['Temp'], air['Ozone'])
air.corr()
sns.heatmap(air.corr(), annot=True, annot_kws={'size': 10}, fmt='.2f', cmap='Blues', cbar=False)
plt.show()
범주(x)와 숫자(y) 관계를 살펴볼 때 중요한 관점은 평균비교이다.
이때 두 가지를 고려해야한다.
1. 평균이 그 집단을 대표할 수 있는가?
2. 평균이 믿을 만 한가?
이와 관련된 내용은 다음에 다룬다.
막대 그래프 가운데에 있는 직선은 error bar로 신뢰구간을 의미한다.
막대그래프의 높이는 평균을 의미한다.
error bar의 길이에 평균이 위치할 수 있다는 것으로, 길수록 신뢰도가 떨어진다.
대립가설을 기각하고 귀무가설 채택sns.barplot(x="Survived", y="Age", data=titanic)
plt.show()
sns.barplot(x="Pclass", y="Age", data=titanic)  # X와 Y 순서를 바꾸면 옆으로 눕힌 barplot이 됨
plt.axhline(titanic['Age'].mean(), color='r')  # 전체평균(기준)
plt.show()
t통계량은 두 평균의 차이를 표준오차로 나눈 값이다.
보통 t값이 -2보다 작거나, 2보다 크면 차이가 있다고 본다.
import scipy.stats as spst
결측치가 존재하면 계산되지 않는다.temp = titanic.loc[titanic['Age'].notnull()]  # 결측치 제외
died = temp.loc[temp['Survived']==0, 'Age']
survived = temp.loc[temp['Survived']==1, 'Age']
# t-test  # 인자1(평균) - 인자2(평균) = t통계량
spst.ttest_ind(died, survived)
statistic은 t통계량을 의미한다.
F통계량은 보통 2~3이상이면 차이가 있다고 본다.
# Na값이 있으면 F통계량, pvalue가 NaN
temp = titanic.loc[titanic['Age'].notnull()]
P_1 = temp.loc[titanic.Pclass == 1, 'Age']
P_2 = temp.loc[titanic.Pclass == 2, 'Age']
P_3 = temp.loc[titanic.Pclass == 3, 'Age']
# ANOVA
spst.f_oneway(P_1, P_2, P_3)
statistic은 F통계량(분산비)을 의미한다.
sns.histplot(x='Age', data=titanic, hue='Survived', bins=16)
plt.show()
common_norm=False를 할 경우, 그래프 각각의 면적 합이 1인 그래프로 그려진다.
True로 하는 것보다 False로 하는 게 분석에 더 적합하다.
cf) `common_norm=True가 디폴트로, 이 경우 모든 그래프 아래 면적 합이 1이다.
sns.kdeplot(x='Age', data=titanic, hue='Survived', common_norm=False)
plt.show()
x에 따라 y 클래스별 비율을 비교해볼 수 있다.
나이에 따라 생존여부 비율을 비교해볼 수 있다.sns.histplot(x='Age', data=titanic, bins=16, hue='Survived', multiple='fill')
plt.axhline(titanic['Survived'].mean(), color='r')
plt.show()
x에 따라 y 클래스별 비율을 비교해볼 수 있다.
나이에 따라 생존여부 비율을 비교해볼 수 있다.sns.kdeplot(x='Age', data = titanic, hue ='Survived', multiple = 'fill')
plt.axhline(titanic['Survived'].mean(), color = 'r')
plt.show()
숫자형 변수와 범주형 타켓에 맞는 가설검정 도구가 마땅히 없다.
로지스틱 회귀 모델은 미봉책이다.
따라서 너무 믿지는 말자.
결측치가 있으면 계산되지 않는다.p-value가 5%(0.05)미만이면 차이가 있다고 본다.
import statsmodels.api as sm
model = sm.Logit(titanic['Survived'], titanic['Age'])
result = model.fit()
print(result.pvalues)
범주형 x와 범주형 y를 비교분석하기 위해선 먼저 pd.crosstab()을 이용해 교차표를 만들어야한다.
시각화 결과가 아래와 같다면, 대립가설을 기각하고 귀무가설을 채택한다.
즉, x에 따라 y에 차이가 없다는 것을 의미한다.

이미지 출처: https://github.com/DA4BAM/image
# 먼저 집계
temp = pd.crosstab(titanic['Sex'], titanic['Survived'], normalize='index')
print(temp)
# temp = temp.reindex(['male', 'female'])  # 원하는 순서대로 정렬
# 집계 후 차트 그리기
temp.plot.bar(stacked=True)
plt.axhline(1 - titanic['Survived'].mean(), color = 'r')  # 전체 사망률
print('전체 생존율: ', titanic['Survived'].mean())
plt.show()
from statsmodels.graphics.mosaicplot import mosaic
x축은 각 x의 범주별 전체 데이터에 대한 비율을 나타낸다.
y축은 x의 각 범주별 y의 각 클래스 비율을 나타낸다.
mosaic(titanic, ['Sex', 'Survived'])
plt.axhline(1 - titanic['Survived'].mean(), color = 'r')  # 전체 사망률
plt.show()
mosaic(titanic, ['Sex', 'Pclass', 'Survived'])
plt.axhline(1 - titanic['Survived'].mean(), color = 'r')
plt.show()
import scipy.stats as spst
# 먼저 집계
table = pd.crosstab(titanic['Survived'], titanic['Sex'])
print('교차표\n', table)
print('-' * 35)
# 카이제곱검정
result = spst.chi2_contingency(table)
print('카이제곱통계량', result[0])  # 자유도의 2~3배보다 크면 차이가 있다는 것
print('p-value', result[1])
print('자유도', result[2])
print('기대빈도\n',result[3])  # 귀무가설이 참이면 나올 수 있는 값들
카이제곱통계량은 자유도의 2~3배보다 크면 차이가 있다.
p-value는 5%(0.05)미만이어야 차이가 있다고 본다.