자동화된 실패 테스트(failing automated test)
를 먼저 만들기Red
, Green
, Refactor
3 단계
Red
baseline test
: 기준치가 될 최소한의 모델 성능 기준Green
Refactor
Given-When-Then (GWT)
패턴
Given
, 언제 When
, 그러고 나면 Then
3단계로 구성Given
When
action
Then
nose
를 이용한 테스트
pip3 install nose
Red
단계 테스트 코드 작성
NumberGuesser
클래스를 정의하지 않았기 때문에 에러 발생Green
단계로 넘어감def given_no_information_when_asked_to_guess_test():
# given (주어진 조건)
number_guesser = NumberGuesser()
# when (언제)
guessed_number = number_guesser.guess()
# then (그러고 나면)
assert guessed_number is None, 'there should be no guess.'
# 실행결과
jungahn@userui-MacBookPro-66 Chapter 1 % nosetests
E
======================================================================
ERROR: number_guesser_tests.given_no_information_when_asked_to_guess_test
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jungahn/.pyenv/versions/3.8.17/lib/python3.8/site-packages/nose/case.py", line 198, in runTest
self.test(*self.arg)
File "/Users/jungahn/Desktop/workspace/test-driven-machine-learning/TestDrivenMachineLearning/Chapter 1/number_guesser_tests.py", line 5, in given_no_information_when_asked_to_guess_test
number_guesser = NumberGuesser()
NameError: name 'NumberGuesser' is not defined
Green
단계 NumberGuesser
클래스와 guess
메소드 정의, import
구문 추가로 테스트는 성공# 아무 기능 없지만 최소한 테스트 실패는 하지 않는 코드
class NumberGuesser:
def guess(self):
return None
from NumberGuesser import NumberGuesser
def given_no_information_when_asked_to_guess_test():
# given
number_guesser = NumberGuesser()
# when
guessed_number = number_guesser.guess()
# then
assert guessed_number is None, 'there should be no guess.'
# 실행 결과 -> 테스트 성공은 한다.
jungahn@userui-MacBookPro-66 Chapter 1 % nosetests
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
import random
class NumberGuesser:
"""앞선 입력을 기억하고, 그중 랜덤하게 응답하도록 수정"""
def __init__(self):
self._guessed_numbers = []
def numbers_were(self, guessed_numbers):
self._guessed_numbers += guessed_numbers
def number_was(self, guessed_number):
self._guessed_numbers.append(guessed_number)
def guess(self):
if self._guessed_numbers == []:
return None
return random.choice(self._guessed_numbers)
[1,2,5]
입력을 기억시키고, 100회 예측을 수행[1,2,5]
중에서 있어야한다.def given_multiple_datapoints_when_asked_to_guess_many_times_test():
#given
number_guesser = NumberGuesser()
previously_chosen_numbers = [1,2,5]
number_guesser.numbers_were(previously_chosen_numbers)
#when
guessed_numbers = [number_guesser.guess() for i in range(0,100)]
#then
for guessed_number in guessed_numbers:
assert guessed_number in previously_chosen_numbers, 'every guess should be one of the previously chosen numbers'
assert len(set(guessed_numbers)) > 1, "It shouldn't always guess the same number."
초기에 [1,2,5]
로 학습하고, 추가로 0
을 학습하였을 때, 예측 값은 [0,1,2,5]
중에서 존재해야한다.
개 데이터세트에서 복원추출 회에서 모든 결과가 동일할 확률은
def given_a_starting_set_of_observations_followed_by_a_one_off_observation_test():
#given
number_guesser = NumberGuesser()
previously_chosen_numbers = [1,2,5]
number_guesser.numbers_were(previously_chosen_numbers)
one_off_observation = 0
number_guesser.number_was(one_off_observation)
#when
guessed_numbers = [number_guesser.guess() for i in range(0,100)]
#then
for guessed_number in guessed_numbers:
# 예측 범위는 추가로 학습된 0 도 포함해야한다.
assert guessed_number in previously_chosen_numbers + [one_off_observation], 'every guess should be one of the previously chosen numbers'
# 충분히 여러번 수행된 예측 값들은 항상 같은 결과를 가져오면 안된다.
assert len(set(guessed_numbers)) > 1, "It shouldn't always guess the same number."
충분히 많은 테스트를 했다면, 모든 예측값이 다 나올 것이라는 테스트
책에서는 실패 확률은 로 추정하였으나, 3개 값 중 복원 추출하는 것이므로 포함-배제의 원리 Inclusion-Exclusion Principle
로 접근해야함
로 매우 작아 0에 수렴하는 것은 동일
def given_a_one_off_observation_followed_by_a_set_of_observations_test():
#given
number_guesser = NumberGuesser()
print(number_guesser._guessed_numbers)
previously_chosen_numbers = [1,2]
one_off_observation = 0
number_guesser.number_was(one_off_observation)
number_guesser.numbers_were(previously_chosen_numbers)
# # 예측 범위는 추가로 학습된 0 도 포함해야한다.
all_observations = previously_chosen_numbers + [one_off_observation]
#when
guessed_numbers = [number_guesser.guess() for i in range(0,100)]
#then
for guessed_number in guessed_numbers:
# 예측 값은 예측 범위 내에서 존재해야.
assert guessed_number in all_observations, 'every guess should be one of the previously chosen numbers'
# 예측값 3개 범위에서 100회 수행했으므로 모든 예측값이 존재하는지 테스트 (실패 확률이 0은 아니지만 0에 수렴)
assert len(set(guessed_numbers)) == len(all_observations), "It should eventually guess every number at least once."
import math
def probability_not_all_cases_appear(N, k):
"""
Calculate the probability that not all cases appear at least once
in k draws with replacement from N distinct items.
Parameters:
N (int): The number of distinct items.
k (int): The number of draws.
Returns:
float: The probability that not all items appear at least once.
"""
probability_not_all = sum(
(-1) ** (i + 1) * math.comb(N, i) * (1 - i / N) ** k for i in range(1, N + 1)
)
return probability_not_all
# Example usage
N = 3
k = 100
print(probability_not_all_cases_appear(N, k))
linear regression
은 adjusted R2
(조정된 결정계수)ROC curve (Receiver operating characteristic)
, confusion matrix
등k-fold cross validation
도 많이 사용됨supervised learning
의 성능은 ROC curve
값을 사용 가능AUC (Area Under the ROC Curve)
: ROC curve
아래쪽 전체 영역의 면적inflection point
(변곡점) 위치를 파악,
unsupervised learning
은 cross-validation
기법을 통해 테스트