파이썬으로 사후검정(Post Hoc Analysis)

출처: ca.sfu.ca , statedu

사후검정(Post Hoc Analysis)의 필요성

ANOVA 분석의 문제는 다르다는 것은 알지만, 어떤 집단간의 차이가 있는지는 알 수 없다는 것입니다. 그래서 만들어진 방법이 사후검정입니다.

post hoc은 라틴어로 "after this"의 뜻입니다.

사후검정에도 여러 종류가 있습니다. 그 중에서 대표적으로 쓰이는 3가지를 꼽으면 아래와 같습니다.

  • Tukey's HSD (Honest Significant Difference) test.
  • Duncan’s new multiple range test (MRT)
  • Scheffé’s Method

여기에서 명칭들은 모두 해당 방법을 개발한 학자의 이름을 따서 Tukey, Duncan, Scheffe라고 부르겠습니다. 각각을 민감도(sensitivity)로 구분하면 Scheffe < Tukey < Duncan 로 볼 수 있습니다.

다시말해, Duncan의 방법은 작은 차이에도 차이가 난다라고 하지만, Scheffe의 방법은 확실한 차이가 나야만 비로소 차이가 있다라고 판단합니다.

자연과학에서 실험을 할 경우에는 Tukey의 방법을 주로 이용하며, Duncan은 사회과학, 심리학 등과 설문조사인 경우에 많이 이용하고 있습니다.

Tukey' HSD test

저는 Tukey test를 파이썬으로 수행해보려고 합니다. 파이썬에서는 이미 statsmodels라이브러리에 구현이 되어 가져다 쓰기만 하면 됩니다.

이전 포스팅인 파이썬으로 ANOVA 분석 의 예제를 재사용 하겠습니다.

In [1]:
# 필요한 라이브러리를 불러옵니다.
import pandas as pd
import urllib
import matplotlib.pyplot as plt
import numpy as np

%matplotlib inline

# url로 데이터 얻어오기
url = "https://raw.githubusercontent.com/thomas-haslwanter/statsintro_python/master/ipynb/Data/data_altman/altman_910.txt"
data = np.genfromtxt(urllib.request.urlopen(url), delimiter=",")

# Sort them into groups, according to column 1
group1 = data[data[:, 1] == 1, 0]
group2 = data[data[:, 1] == 2, 0]
group3 = data[data[:, 1] == 3, 0]

# pandas로 데이터 불러오기
df = pd.DataFrame(data, columns=["value", "treatment"]).set_index("treatment")

# 예시 데이터 시각화 하기
plot_data = [group1, group2, group3]
ax = plt.boxplot(plot_data)
plt.show()
No description has been provided for this image

이 예제는 ANOVA 분석을 통해 통계적으로 유의한 차이가 있다는것을 알아 냈는데요. 이번에는 사후검정을 해보도록 하겠습니다.

statsmodelsTukey test를 하기 위해서는 dataframe의 형태를 변경해줘야 합니다. 하나의 컬럼은 분류할수 있는 이름(label)을 다른 컬럼은 실험값(values)를 가지고 있는 형태여야 하죠. 하지만 걱정할것은 없어요. pandas를 사용하면 간단하게 할 수 있습니다.

In [2]:
df.head()
Out[2]:
value
treatment
1.0 243.0
1.0 251.0
1.0 275.0
1.0 291.0
1.0 347.0

원래의 데이터 형태는 위와 같습니다. 이것을 reset_index() 기능을 사용해 index를 풀어줍니다.

In [3]:
df2 = df.reset_index()
df2.head()
Out[3]:
treatment value
0 1.0 243.0
1 1.0 251.0
2 1.0 275.0
3 1.0 291.0
4 1.0 347.0

데이터는 다 준비가 되었습니다. 이제 사후검증인 Tukey test을 해보겠습니다.

In [4]:
from statsmodels.stats.multicomp import pairwise_tukeyhsd

posthoc = pairwise_tukeyhsd(df2["value"], df2["treatment"], alpha=0.05)
print(posthoc)
Multiple Comparison of Means - Tukey HSD,FWER=0.05
===============================================
group1 group2 meandiff   lower    upper  reject
-----------------------------------------------
 1.0    2.0   -60.1806 -116.6056 -3.7555  True 
 1.0    3.0   -38.625  -104.8246 27.5746 False 
 2.0    3.0   21.5556   -43.2141 86.3252 False 
-----------------------------------------------

결과를 보면 그룹 1.0과 2.0에서만 통계적인 유의미성(P-value < 0.05)을 가질 수 있는것을 확인 할 수 있습니다. 이제 시각화를 통해 직관적으로 살펴보죠.

In [5]:
fig = posthoc.plot_simultaneous()
No description has been provided for this image

그림에서 볼 수 있듯이, 그룹 1.0과 2.0은 서로 겹치지 않는것을 볼 수 있습니다. 반면에 다른 경우에서는 겹치기 때문에 유의미한 차이가 없다고 할 수 있죠.

결론

  1. 분산분석(ANOVA)를 통해 3가지 그룹간에 통계적인 차이가 있다는 것을 증명했고,
  2. 사후검정을 통해 그룹 1.0과 2.0의 평균이 유의미한 차이가 있다는 것을 보았습니다.

카카오의 REST API 사용하기

0. 카카오 비전 API

카카오에서 최근에 흥미로운 서비스를 시작했습니다. 컴퓨터 비전(Computer Vision)으로 이미지 분석을 해주는 API를 카카오 비전을 공개한 것입니다. 카카오 비전은 이미지를 분석해서 콘텐츠 형태와 의미를 이해하고, 이미지를 활용할 수 있게 도와주는 API입니다. 현재 제공되는 API의 종류는 다음과 같습니다.

  • 얼굴 검출
  • 상품 검출
  • 썸네일 생성
  • 성인 이미지 판별

얼굴 인식은 컴퓨터 비전에서 특별히 새로운 기술은 아닙니다만, 저는 카카오에서 공개한 API의 성능을 한번 확인하고자 시도해 봤습니다. 카카오 비전에 대한 자세한 것은 이곳를 참고하세요.

1. 카카오 비전 API 준수사항

API 사용시 다음과 같은 사항을 준수해야 합니다.

  • 서버에서 호출하는 경우 REST API 키를 사용해 호출합니다.
  • 모든 API는 file 또는 image_url 중 하나의 값을 지정해야 합니다.
  • file에 업로드되는 이미지와 image_url에 지정되는 이미지는 png 또는 jpg 포맷만 지원합니다.

2. 활용 예제 살펴보기

카카오에서 간단한 파이썬 예제 코드를 제공하고 있습니다. 저는 거기에서 얼굴을 추출해 모자이크 처리하는 예제를 테스트 해보겠습니다. 작동원리를 간단하게 서술해 보면, 먼저 카카오 API로 사진상의 얼굴의 좌표를 인식하고 pillow 라이브러리를 이용해서 얼굴 부분의 이미지를 잘라냅니다. 그리고 리사이즈를 한뒤 원본 사진에 다시 붙여(모자이크처리) 넣습니다.

예제로 사용할 사진은 아래와 같이 준비했습니다.

  1. 원숭이 사진

monkey

  1. 단체사진

peoples

사용한 코드는 아래와 같습니다. 몇가지 설명을 덧붙이자면,

  • 본인의 API 키를 넣어야 작동합니다.
  • 변환할 사진 파일은 jpg 혹은 png 포멧이어야 합니다.
  • 사진 파일의 위치는 기본적으로 같은 폴더에 있으면 바로 작동하게 만들었습니다.
  • 모자이크 처리된 파일은 파일명에 mosaic_를 붙여서 생성됩니다.

코드를 kakao_api.py로 저장하고 터미널에서

python kakao_api.py -f ./.

라고 입력합니다.

In [1]:
import sys
import argparse
import requests
from PIL import Image
import glob
import os

API_URL = "https://kapi.kakao.com/v1/vision/face/detect"
# 아래 My Kakao api key, 본인 계정의 API 키로 변경해서 사용하세요.
MYAPP_KEY = "b5f1dde7995c36168402318b69308ef218614"


def detect_face(filename):
    headers = {"Authorization": "KakaoAK {}".format(MYAPP_KEY)}

    try:
        files = {"file": open(filename, "rb")}
        resp = requests.post(API_URL, headers=headers, files=files)
        resp.raise_for_status()
        return resp.json()
    except Exception as e:
        print(str(e))
        sys.exit(0)


def mosaic(filename, detection_result):
    image = Image.open(filename)

    for face in detection_result["result"]["faces"]:
        x = int(face["x"] * image.width)
        w = int(face["w"] * image.width)
        y = int(face["y"] * image.height)
        h = int(face["h"] * image.height)
        box = image.crop((x, y, x + w, y + h))
        # 모자이크 강도를 조절하려면 사이즈를 조절하세요.
        box = box.resize((20, 20), Image.NEAREST).resize((w, h), Image.NEAREST)
        image.paste(box, (x, y, x + w, y + h))
    return image


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Mosaic all of faces.")
    parser.add_argument(
        "-f",
        "--folder",
        type=str,
        nargs="?",
        default="./.",
        help="image file to hide faces",
        required=True,
    )
    args = parser.parse_args()
    # Make files lists
    files = glob.glob("*.jpg") + glob.glob("*.jpeg") + glob.glob("*.png")
    # make loop
    for i in files:
        head, tail = os.path.split(i)
        try:
            detection_result = detect_face(i)
            image = mosaic(i, detection_result)
            image.save(head + "mosaic_" + tail, "JPEG")
            print("! Add mosaic on : " + tail)
        except RuntimeError:
            print("! Face does not detected on : " + tail)

    print("!!  All process finished  !!")
!!  All process finished  !!

3. 결과 확인

  1. 원숭이 사진

  1. 단체사진

얼굴을 인식해서 모자이크 처리가 되는것을 볼수 있습니다. 첫 번째 원숭이 사진은 물론이고 단체사진의 얼굴도 인식을 잘 하는 것을 확인할 수 있습니다. 물론 모든 사진에서 성공적인 결과를 얻지는 못했습니다만, 얼굴 인식의 경우는 상당히 잘 작동합니다. 다른 API들도 테스트를 해보니 상품 검출 API는 아직 인식률과 오작동이 많습니다. 아마도 기술적으로 좀 더 어렵기 때문이겠죠. 테스트중에 알아낸 또 다른것은 사진 용량의 제한입니다. 사진 파일의 용량이 10MB 이상이면 에러메세지가 나오는데 아마도 제한을 걸어둔것 같습니다.