1. 가설과 가설 검정
이변량 분석은 가설을 확인하는 것이다. 즉, 앞서 언급한 x와 y와의 관계를 확인한다. 이러한 과정을 가설 검정이라고 한다.
대세, 기존의 입장이 존재한다고 해보자. 이를테면 뉴턴의 만류인력의 법칙이 대세인데, 그것을 깨는 새로운 가설이 등장할 수도 있다. 그렇게 기존의 가설을 깨트리며 세운 우리의 주장을 대립가설이라고 한다. 우리는 표본으로부터 우리가 세운 가설을 확인하려고 한다. 만약 가설 검정해서 표본에서 이 가설이 맞는 것이 확인된다면, '모집단에서 맞을 거야'라고 우기고자 한다. 그런데 통계적으로 근거가 있는 우김이다. 대립가설은 주로 '차이가 있을 것이다' 혹은 '영향을 끼칠 것이다'로 이야기될 수 있다.
귀무가설은 우리가 세운 적은 없지만 그냥 기존에 있는, 관련이 없을 것이라고 얘기하는 가설이라고 이해하자.
어떤 데이터가 있는데 이게 어떤지 판단하려면 어떤 통계적인 요소가 있어야 하나?
내가 어떤 시험에서 점수를 80점을 받았다. 어떤 정보를 알면 내가 받은 80점이 높은 점수인지 알 수 있을까?
차이에 대한 분포와 어떤 기준이 있다면, 나는 이게 흔한 결과인지, 드문 결과인지 판단할 수 있을 것 같다.
즉, 어떤 숫자에 대해서 판단하려면 분포와 기준을 알아야 한다.
둘 중 어떤 그래프에서 차이가 더 확실하게 보이나? 왼쪽이다.
오른쪽은 차이값은 8로 똑같은데, 전체적으로 그래프가 전부 위로 더 올라와 있다.
오른쪽 분포라면 왼쪽보다는 차이가 있다, 없다라고 말하기가 애매해질 것 같다. 이처럼 분포가 있으면 어떠한 값에 대해서 판단하기가 더욱 쉬워진다.
그런데 한편으로는 어느 정도 분포까지면 차이가 확실하게 있고, 차이가 확실하게 없는지 기준이 애매할 수 있다는 생각도 든다. 그래서 기준도 함께 필요하다.
위 그래프를 볼 때, 8보다 10일 때 안쪽의 면적이 더 적다. 특정 값(관심있는 값)으로부터 차지하는 안쪽 면적을 p-value라고 할 때, 차이값이 클수록 p-value가 작아짐을 알 수 있다. 그런데 그러면 p-value가 어느 정도여야 차이가 있다고 할 것인가? 기준이 필요하다. 이때, 보통 0.05(5%) 혹은 좀 더 보수적인 기준으로 0.01(1%)를 사용한다. 이 기준을 우리는 '유의수준'이라고 한다. p-value의 면적이 작아야 차이값이 큰 것이니까, p-value가 0.05보다 작은가? 하고 판단해준다.
- 유의수준: 0.05(%) 혹은 0.01(1%)를 사용
한편, 양측검정과 단측검정을 구분하기도 하는데, 데이터 분석에서는 대부분의 경우가 다 양측검정이니 특별히 신경을 안 써도 된다. 우리는 주로 매장이 어디에 있냐가 판매량과 관련이 있는지 이게 궁금하다. (ex. 주택가에 있는 매장이 판매량이 더 높을까?) 모델링도, 데이터 분석도 다 양측검정의 입장이다. 차이가 있는지, 없는지. 이것만이 관심인 것이다.
위에서 계속 다뤘던 차이값의 공식 명칭은 '검정통계량'이다. 즉, 차이가 없는지 있는지 확인(=검정)하기 위한 차이값을 '검정통계량'이라고 하는데, 우리는 t통계량이랑 카이제곱 통계량, f통계량 등을 다루게 된다.
이들은 우리가 별도로 계산해주는 게 아니고, 함수 안에서 자동으로 계산이 되는데, 대체로 이들은 어떤 기준이 있고, 각각 기준 대비 차이로 계산된다. 기준과 대비했을 때 얼마나 차이가 있네? 하는 것이다. 이러한 계산된 통계량은 각자의 분포를 가지는데, 분포를 통해서 그 값이 차이가 큰지, 작은지를 판단 가능하며, 이를 손쉽게 판단할 수 있도록 계산해준 것이 p-value이다.
우리가 세운 가설(대립가설)을 검정한다는 말의 의미
이변량 분석에서 내가 세웠던 가설을 검정하겠다고 했다. x에 따라 y는 달라질 것이라고 했다면, 가설검정을 위해 필요한 함수를 돌릴 것이다. 그러면 p-value도 튀어나오고, 아까 말했던 통계량도 튀어나온다.
이때, p-value가 0.001이 나왔다면 '아, p-value는 검정통계량 밖의 면적인데, 작을수록 차이가 크다고 했지. 그런데 0.001? 그럼 0.05보다 작네? 기준(유의수준)으로 정한 5%보다 작으니까 차이가 있다! 우리가 세운 가설이 (모집단에서) 맞겠구나'라고 판단해볼 수 있다.
일차적인 목적은 p-value 가지고 차이가 있는지를 판단해보고, 그 뒤로는 대립가설이 맞았는지 그 의미를 생각해보자.
이러한 절차를 가설검정이라고 한다.
2. 이변량 분석(1): 숫자 → 숫자
온도와 아이스크림 매출액의 관계를 어떻게 파악할 수 있을까? 이처럼 숫자와 숫자 사이의 이변량 분석을 수행하는 방법은 두 가지 존재한다.
1) 산점도 시각화: sns.scatterplot() / sns.fairplot() / sns.jointplot() / sns.regplot()
먼저 그대로 점을 찍어서 그래프를 그려볼 수도 있다. 이처럼 두 숫자형 변수의 관계를 나타내는 그래프를 '산점도'라고 한다.
해당 산점도에서 온도와 판매액 간의 어떤 관계가 보이는가? 얼마나 강한 관계인가? 위처럼 숫자와 숫자를 비교할 때 중요한 관점은 직선'이다.
sns.scatterplot(x='Temp', y='Ozone', data = air)
plt.show()
이처럼 그래프를 그리면, 그래프로부터 정보를 파악해야 한다.
결과 해석
보면, 직선이 보인다. 즉, 온도가 오를수록 오존 농도도 상승하고 있음을 확인할 수 있다. 온도가 올라갈수록 오존 농도의 값의 범위가 점차 넓어지고 있는 것 같기도 하다. 뒤로 갈수록 한 값에 대한 세로 범위가 커진다. 이를 온도가 커질수록 오존 값의 분산이 커지고 있다고 표현할 수도 있을 것 같다.
그리고 특정 온도에서 높은 온도가 아님에도 이상치가 확인된다. 이를 통해 온도 외에도 다른 변수가 있는지 확인도 필요할 것 같다. 한편으로는 7-80도에서 다수 밀집된 정보가 확인되는데, 이 온도가 활발하게 오존으로 합성되는 온도인지 확인이 필요하다.
y에 대해서 각각 x에 대한 관계를 파악해보고 싶다면 다음과 같이 코드를 작성해줄 수 있다.
plt.figure(figsize=(10, 3))
plt.subplot(1, 3, 1)
sns.scatterplot(x='Temp', y='Ozone', data=air)
plt.subplot(1, 3, 2)
sns.scatterplot(x='Wind', y='Ozone', data=air)
plt.subplot(1, 3, 3)
sns.scatterplot(x='Solar.R', y='Ozone', data=air)
plt.tight_layout() # plt.tight_layout() 는 여러 그래프를 틀에서 나눠서 그릴때, 여백을 적절하게 잡아줘서 겹쳐지지 않게 해줘 하는 의미
plt.show()
그러나 이들 중 어떤 것이 가장 강한 관계를 가진 변수인지 눈으로 확인하기는 어려울 것 같다.
[참고] pairplot으로 한꺼번에 시각화할 수 있다.
pairplot() 으로 숫자형 변수들에 대한 산점도를 한꺼번에 그릴 수 있다.
그러나 변수가 많으면 많을수록 시간이 많이 걸린다는 단점은 있다.
- kind='reg' 옵션을 지정해주면 직선이 함께 그려지는데, 이것이 바로 '회귀선'이다.
plt.figure(figsize=(5, 5))
sns.pairplot(air, kind='reg')
plt.show()
[참고] jointplot으로 살펴보기
jointplot은 산점도와 각각의 히스토그램을 함께 보여준다.
sns.jointplot(x='Solar.R', y='Ozone', data = air)
plt.show()
[참고] 회귀선과 산점도를 같이 그려주는 regplot도 있다.
단점은 관계가 없음에도 무조건 직선을 그려주기에 관계가 있는 것처럼 착각할 수 있다는 점이다.
sns.regplot(x='Solar.R', y='Ozone', data = air)
plt.show()
2) 수치화: 상관계수, 상관분석
위처럼 눈으로 그래프를 살펴보며 관계를 파악하는 것은 쉬운 일이 아니다. 확실한 직선이 보이지 않는다면 더욱 그렇다.
이 때문에 관계를 숫자로 계산해서 비교하는 방법이 있다. 숫자 대 숫자의 관계일 때 둘의 관계를 이 직선의 관계를 수치화한 것을 상관계수라고 한다. 그리고 이 상관계수를 기반으로 둘의 관계를 분석해서 가설검정(test)하는 것이 바로 상관분석이다.
상관계수는 'r'로 표현된다. (correlation)
또한 -1에서 1사이의 값을 가지며, 상관계수끼리는 비교가 가능하다. -1과 1, 즉 양끝에 가까울수록 강한 상관관계를 나타낸다.
대략의 기준
▪ 강한 : 0.5 < 𝑟 ≤ 1
▪ 중간 : 0.2 < 𝑟 ≤ 0.5
▪ 약한 : 0.1 < 𝑟 ≤ 0.2
▪ (거의)없음 : 𝑟 ≤ 0.1
가장 강한 관계는 무엇이고, 가장 약한 관계는 무엇인가? 이는 얼마나 직선에 모여 있는가를 가지고 판단할 수 있다. 즉 x와 y의 관계를 얼마나 직선으로 잘 설명할 수 있는가에 따라 강한 관계/약한 관계임이 드러난다. 이때, 산점도에서 또렷한 패턴이 보인다면 강한 관계로 볼 수 있다. 특히 직선의 패턴이 보인다면 강한 관계이다.
import scipy.stats as spst
# 상관계수와 p-value
spst.pearsonr(air['Temp'], air['Ozone'])
첫 번째 나온 숫자는 상관계수이고, 두 번째 나온 수는 p-value이다.
p-value를 보면, e-22이다. 이는 10의 -22승이다. 0이 22개나 있다는 의미이므로 엄청나게 작은 값임을 알 수 있다.
따라서 p-value는 유의하다. '아. 관련이 있네. x-> y 가설이 맞네' 하고 판단하면 된다.
그러면 상관계수는? 0.6이므로 강한 상관관계에 해당한다.
주의점
위 코드를 실행할 때, 값에 NaN이 있으면 계산되지 않는다. 반드시 .notnull()로 제외하고 수행해야
# 결측치 제외하고 상관분석 진행하기
temp = air.loc[air['Solar.R'].notnull()]
spst.pearsonr(temp['Solar.R'], temp['Ozone'])
2-1) 데이터프레임 한꺼번에 상관계수 구하기
# 데이터프레임으로 부터 수치형 데이터에 대한 상관계수 구하기
air.corr()
2-2) 상관계수를 heatmap으로 시각화
plt.figure(figsize = (8, 8))
sns.heatmap(air.corr(),
annot = True, # 숫자(상관계수) 표기 여부
fmt = '.3f', # 숫자 포멧 : 소수점 3자리까지 표기
cmap = 'RdYlBu_r', # 칼라맵
vmin = -1, vmax = 1) # 값의 최소, 최대값
plt.show()
[참고] 상관계수가 0이지만 직선의 패턴이 아닌 것들을 주의하자.
직선의 패턴이 아닌 것들은 표현할 수가 없다. 상관계수가 다가 아니다. 직선의 관계가 아닐 수도 있기에 눈으로 확인해야 한다.
3. 이변량 분석(2): 범주 → 숫자
평일인지 주말인지에 따라 아이스크림 매출액에 차이가 있을까? 어떻게 비교하면 좋을까?
범주별 숫자를 비교할 때는 '범주별 평균 비교 방식'을 사용한다.
1) 시각화: sns.barplot()
우리가 세운 대립가설이 생존여부에 따라 나이에 차이가 있다. 라고 해보자.
평균을 비교할 때에는 barplot을 사용한다.
sns.barplot(x="Survived", y="Age", data=titanic)
plt.grid()
plt.show()
그래프 맨 뒤의 꼭지 부분은 신뢰구간(오차범위)를 가리킨다.
이는 평균값이 얼마나 믿을만한가?를 가리키는데, 좁을수록 믿을만하다고 보면 된다.
데이터가 많을수록, 그리고 편차가 적을수록 신뢰구간은 좁아지게 된다.
그래프 해석의 경우, 두 평균의 차이가 크고, 신뢰구간이 겹치지 않을 때 대립가설이 맞다고 볼 수 있다.
세 집단의 경우에도 동일한 함수를 사용하고, 해석 방법도 동일하다.
# Pclass(3 범주) --> Age
sns.barplot(x="Pclass", y="Age", data=titanic)
plt.grid()
plt.show()
2-1) 수치화: 범주 2개일 때의 t-test
평일과 휴일의 아이스크림 판매량을 어떻게 비교할까?
범주가 2개일 때에는 두 그룹 간 평균의 차이를 비교한다.
두 평균의 차이를 비교하기 위한 방법으로 t-test가 있는데, 이 방법을 통해 t통계량이 유의한지 검정하게 된다.
주의점: 결측치를 처리하고 사용해야 한다!
t-test를 사용할 때, 데이터에 NaN이 있다면 계산이 되지 않는다. .notnull() 등으로 NaN을 제외한 데이터를 사용하기 위해 처리해주어야 한다.
Survived → Age: 생존여부별로 나이에 차이가 있을까?
# 불러오기
import scipy.stats as spst
# 먼저 NaN이 있는지 확인해보자.
titanic.isna().sum()
세 열에서 결측치가 발견되고 있지만, 분석할 Survived, Age 열 가운데에서는 Age에서 177개의 결측치가 발견되었음을 확인할 수 있다. 만약 이를 제거하고 T검정을 하고 싶다면 다음과 같이 코드를 작성하면 된다.
# NaN 행 제외
temp = titanic.loc[titanic['Age'].notnull()]
# 두 그룹으로 데이터 저장
died = temp.loc[temp['Survived']==0, 'Age']
survived = temp.loc[temp['Survived']==1, 'Age']
# T-test
spst.ttest_ind(died, survived)
t-test의 결과는 다음과 같이 t통계량과, p-value 두 가지 값으로 나타난다.
이때, p-value가 유의수준인 0.05보다 작으면 두 집간 단 차이가 통계적으로 유의미하다고 판단하며,
t 통계량은 -2보다 작거나 2보다 크면, 그리고 이보다 더욱 절댓값이 커질수록 두 집단 간 평균 차이에 통계적으로 의미 있는 차이가 있다고 판단한다.
t통계량이란?
두 그룹의 평균 간 차이를 표준오차로 나눈 값이며, 두 평균의 차이로 이해해도 좋다.
2-2) 수치화: 범주가 3개 이상일 때의 anova(분산분석)
월, 화, 수, 목, 금, 토, 일 각 요일별 아이스크림 판매량을 어떻게 비교할까? 범주가 3개 이상일 때에는 전체 평균과 각 범주의 평균을 비교한다. 이때 기준이 전체 평균이 됨을 기억하자.
이러한 방법을 분산분석(ANOVA)이라고 하는데, ANalysis Of VAriance의 약자이다.
예를 들어, A반, B반, C반 학생들에게 각각 사과를 나눠줬다고 해보자.
이때 세 반이 받은 사과의 평균 개수가 서로 많이 다르다면(ex. A반은 평균 2개, B반은 평균 5개, C반은 평균 8개), '반마다 받은 사과가 정말 달랐어!' 하고 말할 수 있을까?
이걸 판단하기 위해서 두 가지 개념이 필요한데, 집단 간 분산과 집단 내 분산이라는 개념을 사용해볼 것이다.
집단 간 분산(그룹끼리 얼마나 다른가?)
A반 평균이 2개, B반 평균이 5개, C반 평균이 8개라면 반들끼리 평균이 차이가 있을 것이다. 이때 계산은 전체 평균에 대해서 각 반의 평균 차이를 비교한다. (전체평균 - 각 집단의 평균)을 구해서 얼마나 큰 차이가 존재하는지 확인하는 것이다.
집단 내 분산(같은 반 학생들끼리 얼마나 다른가?)
A반 학생 중 한 명은 2개, 다른 애는 4개를 받았다면, 같은 반 학생들끼리 차이가 있을 것이다. 이는 각 집단 안에서 평균과 개별 값들이 얼마나 다른지 볼 수 있다. 즉 (각 집단의 평균 - 개별 값)을 구해서 차이를 보는 것이다.
그림을 보면, 세 가지 경우가 있을 수 있다.
첫째는, 집단 간 분산 > 집단 내 분산인 경우이다. 이는 반들끼리 평균 차이가 더 큰 경우일 것이다.
A반 평균이 2개이고, B반 평균이 6개이고, C반 평균이 10개이며, 같은 반 안에서는 친구들끼리 비슷하게 받았다고 해보자.
이런 경우에는 반들끼리 받은 사과 개수의 평균 차이가 커서, 반마다 확실히 결과가 다르다고 해석할 수 있다. 즉, A반, B반, C반은 각각 아주 다른 양을 받았다는 것이다. 이는 중요한 차이라고 해석할 수 있다. (선생님이 의도적으로 차이를 줘서 나눠줬을 가능성이 있겠다.)
둘째는, 집단 간 분산 ≒ 집단 내 분산인 경우이다. 이는 반들끼리 차이도 있고, 같은 반 안에서도 차이가 있는 경우이다. A반 평균이 4개이고, B반 평균이 5개이고, C반 평균이 6개이다. 그런데 같은 반 친구들끼리도 A반에서 1, 4, 7개 등 너무나 서로 다른 개수로 받았다고 해보자.
이런 경우에는 반들끼리 평균 차이가 있긴 하지만, 같은 반 친구들끼리도 차이가 크다. 따라서 반들 사이의 차이가 명확하다고는 보기 어렵고, 따라서 반별 차이가 진짜 의미있어? 라고 했을 때 자신있게 '어!'라고 하기 애매한 상황이다. (그 차이가 단순한 우연일 가능성이 있겠다.)
셋째는, 집단 내 분산 > 집단 간 분산인 경우이다. 이는 같은 반 안에서 차이가 더 큰 경우이다.
A반 평균이 5개, B반 평균이 6개, C반 평균이 7개인데, A반 친구들이 1개, 9개, 5개 등 모두 제각각으로 받았다고 해보자.
이때는 오히려 반들끼리의 평균 차이보다 같은 반 친구들끼리의 차이가 더 크다. 따라서 반별의 차이라기보다는 개별적인 차이 때문에 결과가 들쑥날쑥한 것이다. (이는 반별로 큰 차이가 있다기보다는 그냥 친구들끼리 각자 다른 이유로 다르게 받았겠구나, 하고 해석할 수 있다)
이처럼 분산분석은 두 가지 분산(집단 간 VS. 집단 내)을 비교해서 결과가 과연 의미있게 차이가 있는지를 판단해주는 도구가 된다.
이러한 분산분석에서 집단 간 분산과 집단 내 분산을 비교할 때 사용하는 분포를 F분포라고 하는데, 모양이 다음과 같다.
F분포는 한쪽 방향으로 긴 꼬리를 가지며, 0 이상의 값만 나타난다. 분산은 음수가 될 수 없기 때문에 F값은 항상 0 이상으로, 오른쪽으로 꼬리를 가진다. F값은 보통 2 이상일 때 집단 간 차이가 있다고 해석한다.
왜 2 이상일 때 집단 간 차이가 있다고 해석할까?
F값은 (집단 간 분산 ÷ 집단 내 분산)인데, 만약 F값이 1에 가까우면 집단 간 분산과 집단 내 분산이 비슷하다는 것이다. 그런데 반대로 F값이 2 이상이면, 집단 간 분산이 집단 내 분산보다 더 크다는 뜻이다. 이는 앞선 그림에서 나타난 것처럼 반들끼리 명확한 차이가 있다는 신호이다!
한편, 상관분석과 마찬가지로 분산분석도 절대로 결측치가 있으면 안 되니, 결측치 처리를 꼭 해주자!
# 1) 분산 분석을 위한 데이터 만들기
# NaN 행 제외
temp = titanic.loc[titanic['Age'].notnull()]
# 그룹별 저장
P_1 = temp.loc[temp.Pclass == 1, 'Age'] # temp['Pclass']
P_2 = temp.loc[temp.Pclass == 2, 'Age']
P_3 = temp.loc[temp.Pclass == 3, 'Age']
spst.f_oneway(P_1, P_2, P_3)
p-value는 동일하게 판단하고, f 통계값의 경우 2-3 이상이면 차이가 있다고 판단한다.
F통계량의 57의 의미는?
1, 2, 3등급 내에서의 분산보다, 전체 평균과 그룹 사이의 평균 분산이 57배나 더 크다는 뜻이다. 즉 자기네들끼리 분산보다 그룹 평균끼리 비교했을 때 더 크다는 것이기 때문에, 겹치지 않고 완전 떨어져있다는 의미가 된다.
주의점
분산분석은 전체 평균대비 각 그룹간 차이가 있는지만 알려준다.
따라서 어느 그룹 간에 차이가 있는지는 알 수 없다.
그래서, 보통 '사후분석'을 진행한다.
검정통계량은 차이값이다.
차이라는 것은 빼다는 의미가 강하다. 어떤 기준이 있고, 그것으로부터의 차이이다. a-b면 앞의 것이 기준이다. a가 기준이다? 그럼 a가 기준이다. a를 기준으로 b가 얼마나 차이가 있냐? 하는 것이다. f는 전체 평균이 기준이다. 이 기준으로부터 얼마나 차이가 있냐? 차이값이다.
그 차이값의 분포가 있고, 분포를 기준으로 0이면 차이가 없다는 것이고, -나 +로 있다는 것은 차이가 크다는 것이고,
차이를 나타내는 값. 거기에 바깥에 위치하는 면적을 p-value구나. 이게 0.05보다 작으면 우리는 차이가 있다고 판단할거야. 라고 생각하자.
4. 이변량 분석(3): 범주 → 범주
타이타닉호 탑승객의 성별과 생존여부가 관련이 있는지 어떻게 알 수 있을까?
범주와 범주의 관계를 분석할 때에는 Pandas의 교차표(crosstab)를 먼저 만들어야 한다.
1) 교차표: crosstab()
# 두 범주별 빈도수를 교차표로 만들어 봅시다.
pd.crosstab(titanic['Survived'], titanic['Sex'])
한편, 비율로 변환해주는 nomalize 옵션에 따라 다음과 같이 표현할 수 있다.
normalize 옵션
• columns : 열 기준 100%
• index : 행 기준 100%
• all : 전체 기준 100%
# normalize = 'columns'
pd.crosstab(titanic['Survived'], titanic['Sex'], normalize = 'columns')
# normalize = 'index'
pd.crosstab(titanic['Survived'], titanic['Sex'], normalize = 'index')
# normalize = 'all'
pd.crosstab(titanic['Survived'], titanic['Embarked'], normalize = 'all')
2) 교차표 시각화: mosaic plot()
교차표로부터 시각화를 수행할 수 있으며, 모자이크 플롯으로 표현이 가능하다.
mosaic plot은 범주별 양과 비율을 나타내는 그래프로, 빨간 선은 전체 평균(전체 사망률 or 전체 생존율)을 의미한다.
# Pclass별 생존률
titanic['Survived'].mean()
# Pclass별 사망률
1- titanic['Survived'].mean()
# Pclass별 생존여부를 mosaic plot으로 그려 봅시다.
mosaic(titanic, [ 'Pclass','Survived'])
plt.axhline(1- titanic['Survived'].mean(), color = 'r')
plt.show()
plt.axhline(1- titanic['Survived'].mean(), color = 'r')의 의미?
- ax: 축
- hline: 수평선
전체 5건 중에 2명이니까 생존율은 0.4이다. 그러면 얘를 어떻게 계산할 수도 있나?
생존칼럼.mean() 하여 평균을 계산하면 전체(건수에 대한) 생존율이 된다.
그래프를 그리다보면, 경우에 따라 밑이 1이 되고 위가 0으로 되는 모자이크플롯이 있다.
그런 그래프면 1에서 빼지 않고 그땐 그대로 생존율로 구해주면 된다.
데이터가 쌓인 순서대로 보여주는 것이라서, 마음에 안들면 sortvalues로 정렬하고 다시 그려주자.
위 그림을 보면, pclass별로 생존에 따라 관련이 있나? 완전 있는 것으로 보인다.
만약 귀무가설(pclass에 따라 생존여부는 관련이 없다)이 참이라면 나올 수 있는 그래프는 어떤 형태인가?
전체평균 선을 기준으로 1등급 객실, 2등급 객실, 3등급 객실의 생존 사망 비율이 동일하다. 전체 평균 비율과 동일하게 잘려있다? 그러면 차이가 없는 것이다. 조금 차이가 있으면 비율 혹은 bar의 크기에 조금이라도 차이가 날 것이고, 많이 관련 있으면 널뛰기를 하게 된다.
2) 수치화: Chi-squared test
비만 체중 여부와 당뇨 여부가 아무런 관련이 없을 때, 빨간 박스에 나올 수 있는 숫자는 다음과 같다.
전체 비율인 20:80의 비율대로 해서 1:4로 각 데이터를 분배해주면 된다.
이처럼 귀무가설이 참(=아무런 관련이 없다)일 때 기대되는 빈도 수를 '기대빈도'라고 한다.
실제 값이 파란색 박스이고, 빨간색 박스가 기대빈도라면, 이 둘 사이의 차이는 얼마나 되나?
둘 사이의 차이값은 카이제곱 통계량으로 구할 수 있는데, 다음처럼 구해볼 수 있다.
# 1) 먼저 교차표 집계- normalize 하면 안 됨
table = pd.crosstab(titanic['Survived'], titanic['Pclass'])
print(table)
print('-' * 50)
# 2) 카이제곱검정
spst.chi2_contingency(table)
dof는 자유도로, 비교하는 두 개 feature의 각 범주 개수에서 각각 -1을 하여 곱한 값이다.
ex. Pclass --> Survived일 때, Pclass 범주가 3개이고 Survived 범주가 2개라면, (3-1) × (2-1) = 2가 된다. 그러므로, 2의 2 ~ 3배인 4 ~ 6 보다 카이제곱 통계량이 크면, 차이가 있다고 볼 수 있다.
카이제곱 통계량의 판단
- 클수록 기대빈도로부터 실제값에 차이가 크다는 의미다.
- 범주의 수가 늘어날수록 값은 커지게 되어 있다.
- 자유도의 약 2배보다 크면, 차이가 있다고 보자.
카이제곱 통계량은, 기대빈도에서 실제값을 뺀 것의 제곱을 하니까 차이가 클수록 카이제곱 통계량이 커진다. 그러니 통계량이 크면 차이가 크다.
그런데 다른 값과의 비교는 안 하는 것이 좋다. 그래프와 함께 그냥 '차이가 크구나'하면 좋다.
카이제곱 통계량은 독립되어있다고 보자.
5. 이변량 분석(4): 숫자 → 범주
숫자와 숫자의 관계를 분석하는 방법은 보통 시각화를 통한 방법을 활용하게 된다.
kde 그래프를 사용하여 다음과 같이 분석해볼 수 있다.
1) 시각화: sns.kdeplot()
추가 매개변수
- common_norm = False : 생존자, 사망자각각 kde plot 그리기
- multiple='fill’ : 모든구간에 대한 100% 비율로 kde plot 그리기
# common_norm = False
sns.kdeplot(x='Age', data = titanic, hue ='Survived',
common_norm = False)
plt.grid()
plt.show()
그래프를 보면, 생존자와 사망자 그래프가 만나는 부분이 5군데가 관찰된다. 이 접점을 기준으로 어느 그룹이 더 높게 나타나는지를 살펴보며 의미를 해석해볼 수 있다.
# multiple = 'fill'
sns.kdeplot(x='Age', data = titanic, hue ='Survived'
, multiple = 'fill')
plt.axhline(titanic['Survived'].mean(), color = 'r')
plt.show()
빨간 선이 전체 평균 생존율인데, 이 빨간 선과 겹치는 부분이 바로 전체 평균과 같은 지점이라고 볼 수 있다.
이를 기반으로 한 해석
- 약 15세 이하는 생존율이 전체 평균보다 높다.
- 20-30대는 생존율이 전체 평균보다 낮다
- 60-70대는 대부분 사망하였다.
한편, kde 그래프의 모양에 따라서 중요하게 해석해야 하는 부분이 있다.
그래프가 겹쳐있다면, 차이가 전혀 없다고 해석해야 하며, 약간 떨어져있다면 차이가 조금 있다. 두 분포가 멀리 떨어져 있따면 차이가 크다고 해석한다.
'데이터 분석 > 비즈니스 데이터 분석' 카테고리의 다른 글
개별 변수 분석(단변량 분석): 숫자형 변수 & 범주형 변수 (1) | 2024.09.27 |
---|---|
데이터 분석 방법론(CRISP-DM) (2) | 2024.09.27 |