[이솦] 파이선으로 배우는 AI 기초 18
알파고 알고 있는가? (언제적 알파고지..) 알파고는 딥러닝으로 만들어진 인공지능이라고 알고 있다. 그런데 생각보다 우리가 알고 있는 딥러닝이 아니다. 프로 바둑 기사들의 기보로 학습했다고 하지만 실제로는 그렇게 많지는 않다. 기본적으로 경우의 수에 기반한 탐색을 통하여 동작한다.
틱텍토라는 게임을 예시로 들어 내가 어떤수를 두면 상대방이 어떤 수를 둘 수 있는지를 모든 경우의 수를 찾아서 가장 좋은 경우를 선택하는 것이다.
바둑이라면 경우의 수가 더 많을 것이다. 그래서 바둑은 경우의 수를 계산하는것을 포기하고 딥러닝을 통해서 일정 범위만 학습해서 다음 수를 찾도록 배웠다.
오늘은 지금까지 배운 모든 명령을 활용해서 확률이 있는 게임을 증명 할것이다. (오호...) 모듈, 함수, 반복문 들을 다 사용할 것이다.
조건부 확률
오늘 만들것은 실제 퀴즈쇼와 관련이 있다. 미국 퀴즈쇼에서 유래한 몬티홀 문제인데 이 문제는 조건부 확률 문제이다. 이 퀴즈쇼에서는 1등에게는 추가적인 기회를 제공한다. 문이 3개 있고 그중 1개에는 상품이 있다. 참가자는 문을 하나 선택해서 상품을 얻게 된다.
재미있는게 하나 있는데 참가자가 문을 하나 선택하면 사회자는 나머지 문중에서 염수가 있는 문 하나를 열어서 확인시켜 준다. 지금 선택을 유지 할것인지 바꿀것인지 기회를 주는것이다. 당신의 선택은 어떻 것인가?
선택을 유지하는거 말고 바꾸는 것을 가정해서 계산해 보자.
상품이 1번이고 참가자가 1번을 선택했을때 사회자는 나머지 2개를 모두 열수 있다. 참가자가 1번을 선택하고 사회자가 2번(또는 3번)을 열고 선택을 바꿨을때 꽝이 될 확률은 1/3 * 1/2 라서 총 1/6이고 2번이 있으니 선택을 바꿔서 꽝이 될 확률은 1/3 이다.
상품이 2번이고 참가자가 1번을 선택하면 사회자는 3번을 열수 밖에 없다. 상품이 3번에 있고 참가자가 1번을 선택하면 사회자는 2번을 열수밖에 없다. 선택을 바꿔서 당첨될 확율를 1/3 이고 2번이 있으니 선택을 바꿔서 당첨될 확률은 2/3 이다.
즉 선택을 바꾼다는 전제을 한다면 처음엔 잘못된 선택을 해야 최종적으로 정답을 선택할 수 있다. (그러면 처음에 선택이 잘 못된지 어떻게 알지? 흠..) 처음에 꽝을 고를 확률은 2/3이다.
만약에 선택을 바꾸지 않는다면 확률은 1/3이고 처음부터 정답을 골라야만 한다. 그러므로 선택을 무조건 바꾸는 쪽이 더 유리하다. 왜냐면 선택을 무조건 바꾸기로 했을때 꽝을 고를 확율이 2/3으로 높음, 꽝를 고른 경우 바꾸면 반드시 당첨이다. 이것이 조건부 확률에 기반한 몬티 홀 문제이다.
정말로 그런지 증명해 보자.
조건부 확율을 이용한 머신러닝인 베이지언 분류기 라는 것이있다.
이건 베이즈 이론을 적용해서 데이터가 많지 않은 상황에서도 높은 정확도를 보일때가 많다.
P(H/E) 사후확율= P(H/E)P(H)사전확률 /P(E) H: 가설, E: 관찰데이터로 표현하며 사전확률과 사후 확률이라는 개념이 중요하다. 코로나 진단키트도 베이즈 이론을 적용하면 감염자 비율에 따라 예측도가 변한다. 감염자가 많을 경유 정확도가 증가하고 감염자가 적은 경우 정확도는 내려간다.
양성 예측도의 가변성
민감도 (90%) 특이도 (99%)기준
실제 감염자 비율 | 1% | 2% | 3% | 5% | 10% |
---|---|---|---|---|---|
양성예측도 | 47.6% | 64.7% | 73.6% | 82.6% | 90.9% |
*동일한 민감도, 특이도에서 실제 감염자 비율에 비례해 양성 예측도가 높아짐
민감도 90%는 90%의 확률로 찾아 낼수 있다는 얘기이고 특이도 99%는 안걸렸다고 말하는 사람중에서 안걸린 사람의 지수이다. 즉 100명을 진단해 보면 99명은 안걸렸다고 파악해 주는 것이다.
진단력이 99%라고 하더라고 실제 감염자 비율에 따라서 양성 예측도는 다르다. 베이지언 확률 이론에 따라 사전확률이 변하면 사후 확률이 변하기 때문이다. 베이지언 이론을 이용해서 만든게 베이지언 분류기 이다.
실습
라이브러리 randint, statistics 불러오기
함수 구현하기: 반복횟수 매개변수로 받기, 랜덤으로 선택하고 선택을 바꾸는 기능 구현,(매우 중요) 반복을 통해 성공횟수 실패 횟수 구하기,
함수의 활용: 매개변수에 반복수를 입력하여 함수 호출하기, 결과 호출하기
문제, 선택증에서 여러 난수가 필요하다.
from random import randint
def montyhall(cnt):
success = 0
fail = 0
for i in range(cnt):
# Step 1: 배치된 자동차의 위치 선택
car = randint(0, 2)
# Step 2: 플레이어가 선택한 문
choice = randint(0, 2)
# Step 3: 남은 문 중에서 염소가 있는 문을 호스트가 열어줌
# 플레이어가 선택하지 않은 문 중 자동차가 없는 문을 연다
remaining_doors = [i for i in range(3) if i != choice and i != car]
host_opens = remaining_doors[randint(0, len(remaining_doors) - 1)]
# Step 4: 플레이어가 선택을 바꾼다고 가정
# 남은 문 중에서 선택을 변경 (처음 선택과 호스트가 연 문을 제외한 문)
new_choice = [i for i in range(3) if i != choice and i != host_opens][0]
# Step 5: 새로운 선택이 자동차가 있는 문인지 확인
if new_choice == car:
success += 1
else:
fail += 1
success_rate = success / cnt
return [success, fail, success_rate]
result = montyhall(100000)
print("성공 %d번, 실패 %d번, 성공확률 %.2f%%입니다." % (result[0], result[1], result[2]*100))
이렇게 코드를 짜줄수 있다.
from random import randint
randint
함수 가져오기: 이 코드는random
모듈에서randint
함수를 가져옵니다. 이 함수는 주어진 범위 내에서 무작위로 정수를 반환합니다.
def montyhall(cnt): success = 0 fail = 0
montyhall
함수 정의: 이 함수는 몬티 홀 문제를 시뮬레이션합니다.cnt
는 시뮬레이션할 횟수(실험 횟수)를 의미합니다.
success
와fail
변수는 각각 성공 횟수와 실패 횟수를 기록합니다.
for i in range(cnt): # Step 1: 배치된 자동차의 위치 선택 car = randint(0, 2)
for
루프: 이 루프는cnt
만큼 반복되며, 매 반복마다 한 번의 몬티 홀 문제 시뮬레이션이 실행됩니다.자동차의 위치 선택:
car
변수는 0에서 2까지의 숫자 중 하나를 무작위로 선택하며, 이 숫자는 자동차가 위치한 문을 나타냅니다.
# Step 2: 플레이어가 선택한 문 choice = randint(0, 2)
플레이어의 선택:
choice
변수는 0에서 2까지의 숫자 중 하나를 무작위로 선택하며, 이는 플레이어가 처음 선택한 문을 나타냅니다.
# Step 3: 남은 문 중에서 염소가 있는 문을 호스트가 열어줌 # 플레이어가 선택하지 않은 문 중 자동차가 없는 문을 연다 remaining_doors = [i for i in range(3) if i != choice and i != car] host_opens = remaining_doors[randint(0, len(remaining_doors) - 1)]
호스트가 문을 엽니다:
remaining_doors
는 플레이어가 선택하지 않은 문들 중에서, 자동차가 없는 문들로 구성된 리스트입니다. 이 중 하나를 호스트가 엽니다.
remaining_doors
는 리스트 컴프리헨션을 사용하여 계산됩니다.
host_opens
는remaining_doors
리스트에서 무작위로 선택된 문을 의미하며, 호스트가 여는 문입니다.
# Step 4: 플레이어가 선택을 바꾼다고 가정 # 남은 문 중에서 선택을 변경 (처음 선택과 호스트가 연 문을 제외한 문) new_choice = [i for i in range(3) if i != choice and i != host_opens][0]
플레이어가 선택을 변경: 플레이어는 선택을 바꾸는 전략을 사용한다고 가정합니다. 선택을 바꾸는 경우, 처음 선택한 문과 호스트가 연 문을 제외한 나머지 문을 선택하게 됩니다. 이 문이
new_choice
변수에 저장됩니다.
# Step 5: 새로운 선택이 자동차가 있는 문인지 확인 if new_choice == car: success += 1 else: fail += 1
성공 여부 확인: 플레이어가 선택을 바꾼 후 선택한 문(
new_choice
)이 자동차가 있는 문(car
)과 일치하는지 확인합니다.
일치하면
success
를 1 증가시키고, 그렇지 않으면fail
을 1 증가시킵니다.
success_rate = success / cnt return [success, fail, success_rate]
성공 확률 계산: 성공 횟수(
success
)를 총 시도 횟수(cnt
)로 나누어 성공 확률을 계산합니다.결과 반환: 함수는 성공 횟수, 실패 횟수, 성공 확률을 리스트 형태로 반환합니다.
result = montyhall(100000) print("성공 %d번, 실패 %d번, 성공확률 %.2f%%입니다." % (result[0], result[1], result[2]*100))
함수 호출 및 출력:
montyhall
함수를 100,000번 시뮬레이션하도록 호출합니다.결과 출력: 함수에서 반환된 결과(
result
)를 사용해 성공 횟수, 실패 횟수, 성공 확률을 출력합니다. 성공 확률은 소수점 두 자리까지 출력되며, 퍼센트(%)로 표현됩니다.
이렇게 코드 설명을 넣을수 있다.
몬티홀 문제에서는 선택을 바꾸어 주는것이 좋다. (교수님 설명을 잘 하셨는데, 교수님이 코드를 가리셔서....)
요약
하나의 멋진 프로그램을 완성하기 위해서는 다양한 파이선 재료가 필요하다.
문법을 잘 익히는것도 중요하지만, 어떻게 표현할지를 익히는것이 더 중요하다.
조건부 확률 재미있게 공부했나요? 파이선 문법은 다 배웠는데 문법만이 프로그래밍의 전부는 아니다.
추가
베이지언 분류기에 대한 걸 더 알아보자.
베이지언 분류기(Bayesian classifier)는 베이즈 정리를 기반으로 하는 확률적 분류 기법입니다. 가장 널리 알려진 베이지언 분류기 중 하나는 나이브 베이즈 분류기(Naive Bayes classifier)입니다. 나이브 베이즈 분류기는 각각의 특징들이 독립적이라는 가정 하에 분류를 수행합니다. 이 가정은 실제 데이터에서는 성립하지 않을 수 있지만, 많은 경우에 유용하게 사용됩니다.
이제 예시로 나이브 베이즈 분류기를 사용하여 간단한 텍스트 분류 문제를 해결하는 파이썬 코드를 만들어보겠습니다.
sklearn
라이브러리를 사용하여 구현하겠습니다.문제 설명
주어진 문장이 긍정적인지(positive) 또는 부정적인지(negative)를 분류하는 간단한 텍스트 분류 문제를 다룹니다.
!pip install scikit-learn
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score
# 데이터 준비: 간단한 텍스트 데이터와 레이블 (긍정적/부정적)
documents = [
"I love this movie", # Positive
"This film was amazing", # Positive
"I really liked the acting", # Positive
"This was a terrible movie", # Negative
"I did not enjoy the film", # Negative
"The movie was boring", # Negative
]
labels = ["positive", "positive", "positive", "negative", "negative", "negative"]
# 텍스트 데이터를 벡터화 (단어 카운트를 기반으로)
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(documents)
# 학습 데이터와 테스트 데이터로 나누기 (80% 학습, 20% 테스트)
X_train, X_test, y_train, y_test = train_test_split(X, labels, test_size=0.2, random_state=42)
# 나이브 베이즈 분류기 모델 생성 및 학습
model = MultinomialNB()
model.fit(X_train, y_train)
# 테스트 데이터 예측
y_pred = model.predict(X_test)
# 정확도 평가
accuracy = accuracy_score(y_test, y_pred)
print(f"정확도: {accuracy*100:.2f}%")
# 새로운 문장 예측
new_sentences = ["I enjoyed the film", "The movie was bad"]
new_X = vectorizer.transform(new_sentences)
predictions = model.predict(new_X)
for sentence, prediction in zip(new_sentences, predictions):
print(f"문장: '{sentence}' -> 예측: {prediction}")
코드 설명
데이터 준비
documents
: 간단한 텍스트 데이터 리스트로, 각 문장은 긍정적(positive) 또는 부정적(negative)입니다.
labels
: 각 문장이 긍정적인지 또는 부정적인지를 나타내는 레이블 리스트입니다.벡터화
CountVectorizer
를 사용하여 텍스트 데이터를 숫자 형식의 벡터로 변환합니다. 이 과정에서는 텍스트에서 단어의 빈도를 계산하고, 각 문장을 단어 빈도 벡터로 변환합니다.데이터 분할
train_test_split
을 사용하여 데이터를 학습 데이터와 테스트 데이터로 나눕니다. 이 예제에서는 데이터의 80%를 학습용으로, 20%를 테스트용으로 사용합니다.모델 생성 및 학습
MultinomialNB
클래스는 나이브 베이즈 분류기 중에서 다항 분포 기반의 분류기를 구현한 것입니다. 이 모델을 생성하고, 학습 데이터(X_train
,y_train
)를 사용하여 학습시킵니다.예측 및 평가
테스트 데이터(
X_test
)에 대해 학습된 모델로 예측(predict
)을 수행하고, 실제 레이블(y_test
)과 비교하여 정확도를 계산합니다.
accuracy_score
함수를 사용하여 정확도를 출력합니다.새로운 문장 예측
새롭게 주어진 문장 리스트(
new_sentences
)에 대해 모델이 해당 문장이 긍정적인지 또는 부정적인지를 예측합니다. 벡터화 과정을 거쳐 예측한 결과를 출력합니다.출력 예시
예를 들어, 위 코드를 실행하면 다음과 같은 출력이 나올 수 있습니다:
정확도: 100.00% 문장: 'I enjoyed the film' -> 예측: positive 문장: 'The movie was bad' -> 예측: negative
이 코드에서 간단한 데이터셋을 사용했기 때문에 100% 정확도를 얻을 수 있지만, 실제 문제에서는 데이터의 복잡성에 따라 정확도가 달라질 수 있습니다.
이 예시는 나이브 베이즈 분류기를 이용한 텍스트 분류 문제의 간단한 예시입니다. 나이브 베이즈 분류기는 텍스트 분류 외에도 이메일 스팸 필터링, 문서 분류 등 다양한 문제에 효과적으로 적용할 수 있습니다.
오늘 내용중 코로나 진단에 대한 베이즈 이론을 조금더 자세히 알아보자.
베이즈 정리에 기반한 예측도와 관련된 개념을 이해하기 위해, 코로나 진단 테스트를 예시로 들 수 있습니다. 이 과정에서 사전 확률(즉, 감염 확률)이 테스트 결과(양성, 음성)에 어떻게 영향을 미치는지를 베이즈 정리를 통해 설명할 수 있습니다.
문제 설명
민감도(Sensitivity): 실제로 감염된 사람 중에서 테스트가 양성으로 나올 확률 (즉, 진짜 감염자를 찾는 확률).
특이도(Specificity): 실제로 감염되지 않은 사람 중에서 테스트가 음성으로 나올 확률 (즉, 비감염자를 정확히 음성으로 진단하는 확률).
이 테스트 결과에서 양성이라고 나왔을 때, 실제로 감염되었을 확률(양성 예측도)이 사전 확률(즉, 실제 감염자 비율)에 따라 달라진다는 것이 핵심입니다.
베이즈 정리 기반 계산
베이즈 정리를 사용하여 양성 예측도를 계산하는 공식은 다음과 같습니다:
양성 예측도=민감도×사전 확률민감도×사전 확률+(1−특이도)×(1−사전 확률)\text{양성 예측도} = \frac{\text{민감도} \times \text{사전 확률}}{\text{민감도} \times \text{사전 확률} + (1 - \text{특이도}) \times (1 - \text{사전 확률})}양성 예측도=민감도×사전 확률+(1−특이도)×(1−사전 확률)민감도×사전 확률
여기서:
사전 확률(P(H)): 전체 인구 중 실제 감염된 사람의 비율 (즉, 감염자 비율).
사후 확률(P(H/E)): 테스트에서 양성으로 나왔을 때 실제 감염되었을 확률 (즉, 양성 예측도).
파이썬 코드 예시
다음은 민감도, 특이도, 그리고 사전 확률(감염자 비율)을 사용하여 양성 예측도를 계산하는 파이썬 코드입니다:
def positive_predictive_value(sensitivity, specificity, prevalence): """ 양성 예측도를 계산하는 함수 :param sensitivity: 민감도 (감염자를 양성으로 정확히 진단할 확률) :param specificity: 특이도 (비감염자를 음성으로 정확히 진단할 확률) :param prevalence: 사전 확률 (전체 인구 중 감염자의 비율) :return: 양성 예측도 """ # 베이즈 정리를 사용한 양성 예측도 계산 ppv = (sensitivity * prevalence) / ( (sensitivity * prevalence) + ((1 - specificity) * (1 - prevalence)) ) return ppv # 민감도와 특이도 sensitivity = 0.90 # 90% 민감도 specificity = 0.99 # 99% 특이도 # 실제 감염자 비율 (사전 확률) prevalence_rates = [0.01, 0.02, 0.03, 0.05, 0.10] # 1%, 2%, 3%, 5%, 10% # 각 감염자 비율에 따른 양성 예측도 계산 및 출력 for prevalence in prevalence_rates: ppv = positive_predictive_value(sensitivity, specificity, prevalence) print(f"실제 감염자 비율 {prevalence*100}% -> 양성 예측도: {ppv*100:.2f}%")
코드 설명
positive_predictive_value
함수: 이 함수는 민감도, 특이도, 그리고 사전 확률(실제 감염자 비율)을 입력받아 양성 예측도를 계산합니다. 베이즈 정리를 사용하여 양성 예측도를 계산합니다.민감도와 특이도 설정: 민감도는 90%로 설정되고, 특이도는 99%로 설정됩니다. 이는 테스트의 성능을 나타냅니다.
실제 감염자 비율: 여러 사전 확률(즉, 실제 감염자 비율) 값을 리스트로 설정합니다. 예를 들어, 1%, 2%, 3%, 5%, 10% 등입니다.
각 감염자 비율에 대한 양성 예측도 계산: 루프를 사용하여 각 감염자 비율에 대해 양성 예측도를 계산하고 출력합니다.
출력 예시
코드를 실행하면 다음과 같은 결과를 얻을 수 있습니다:
실제 감염자 비율 1.0% -> 양성 예측도: 47.62% 실제 감염자 비율 2.0% -> 양성 예측도: 64.29% 실제 감염자 비율 3.0% -> 양성 예측도: 73.55% 실제 감염자 비율 5.0% -> 양성 예측도: 82.57% 실제 감염자 비율 10.0% -> 양성 예측도: 90.91%
결과 해석
양성 예측도는 감염자 비율(사전 확률)에 따라 달라진다: 감염자 비율이 낮을수록 양성 예측도가 낮고, 감염자 비율이 높을수록 양성 예측도가 높아집니다. 즉, 양성 판정이 실제 감염자일 확률이 감염자 비율에 따라 변합니다.
예를 들어, 감염자 비율이 1%일 때 양성 예측도는 47.62%입니다. 즉, 양성 판정을 받은 사람 중 약 47.62%만 실제로 감염된 것입니다. 반면에 감염자 비율이 10%로 높아지면 양성 예측도는 90.91%로 증가합니다.
베이즈 정리의 적용: 이 결과는 베이즈 정리의 핵심 개념인 사전 확률이 사후 확률에 미치는 영향을 보여줍니다. 감염자가 적을 때는 양성 예측도가 낮아지며, 감염자가 많을 때는 양성 예측도가 높아지는 것을 확인할 수 있습니다.
이를 통해, 진단 테스트의 성능 평가에서 감염자 비율이 중요한 역할을 한다는 것을 이해할 수 있습니다.