반응형
https://inuplace.tistory.com/510?category=912534
- 위 링크에서 구현한 코드를 실행해보면 테스트 데이터에 대해 꽤나 좋은 정확도를 얻게 된다. (97% 상회)
- 하지만 이는 전체 데이터셋의 90%가 일반 별이고 10%가 펄서이기 때문이다. (따라서 테스트 데이터셋도 비슷한 비율을 가질 것이다.)
- 이런 경우 일반적 데이터에서 모델을 사용하면 정확도가 매우 떨어질 확률이 높다.
- 수업에 사용된 코드를 분석한 자료입니다.
균형 잡힌 데이터셋과 착시 없는 평가 방법
- 일반 별 데이터를 버리는 방법도 있지만 어렵게 구한 데이터를 버리는 것은 그리 좋은 방법이 아니다.
- 상대적으로 데이터가 적은 펄서 데이터를 중복 사용해 일반 별 데이터와의 크기를 맞춘다.
- 약간의 노이즈를 추가해 데이터를 중복 적용한다.
- 이런 과정을 진행하면 정확도는 떨어지지만, 데이터셋으로 인해 발생하던 정확도의 '착시현상'이 없어지면서 신경망의 추정 성능은 향상된다.
- 이 때문에 정확도 대신 신경망의 성능을 더 잘 보여줄 수 있는 평가 지표가 필요하다.
정밀도와 재현율
- 그에 따라 등장한 것이 정밀도와 재현율이다.
- 정밀도 : 신경망이 참으로 추정한 것 중 정답이 참인 것의 비율
- 재현율 : 정답이 참인 것들 중 신경망이 참으로 추정한 것의 비율
- F1값 : 정밀도와 재현율의 조화 평균 (2ab /(a+b))
- 미니배치 데이터는 정답이 참인지 거짓인지에 따라 T(True), F(False)의 두 집단으로 나누고 추정이 참인지 거짓인지에 따라 P(Positive), N(Negative) 두 집단으로 나눌 수 있다. 즉, 미니배치데이터를 TP, TN, FP, FN 네 집단으로 나눌 수 있는 것이다.
- 이를 이용해 정확도, 정밀도와 재현율을 수식으로 표현할 수 있다.
- $정확도 = {TP + FN \over TP + TN + FP + FN}$
- $정밀도 = {TP \over TP + FP}$
- $재현율 = {TP \over TP + TN}$
메인 함수 재정의
def pulsar_exec(epoch_count=10, mb_size=10, report=1, adjust_ratio=False):
load_pulsar_dataset(adjust_ratio)
init_model()
train_and_test(epoch_count, mb_size, report)
- 데이터를 불러올 때 adjust_ratio(불린값)을 추가하여 데이터를 중복적용해 불러올지를 결정하도록 한다.
데이터 적재 함수 재정의
def load_pulsar_dataset(adjust_ratio):
pulsars, stars = [], []
with open('../../data/chap02/pulsar_stars.csv') as csvfile:
csvreader = csv.reader(csvfile)
next(csvreader, None)
# rows = []
for row in csvreader:
if row[8] == '1': pulsars.append(row)
else: stars.append(row)
global data, input_cnt, output_cnt
input_cnt, output_cnt = 8, 1
star_cnt, pulsar_cnt = len(stars), len(pulsars)
if adjust_ratio:
data = np.zeros([2*star_cnt, 9])
data[0:star_cnt, :] = np.asarray(stars, dtype='float32')
for n in range(star_cnt):
data[star_cnt+n] = np.asarray(pulsars[n % pulsar_cnt], dtype='float32')
else:
data = np.zeros([star_cnt+pulsar_cnt, 9])
data[0:star_cnt, :] = np.asarray(stars, dtype='float32')
data[star_cnt:, :] = np.asarray(pulsars, dtype='float32')
- 기존의 rows 대신 pulsars와 stars에 데이터를 나눠담는다.
- 그리고 adjust_ratio가 false인 경우 기존에 했던 방식과 유사하게 data 변수를 초기화한다.
- 단, adjust_ratio가 true일 경우 stars 데이터를 담고 stars의 길이만큼 pulsars 데이터를 반복해서 담는다. (강제로 별 데이터와 펄서 데이터 개수를 동일하도록 조정한 것이다.)
정확도 계산 함수 재정의와 safe div
def safe_div(p, q):
p, q = float(p), float(q)
if np.abs(q) < 1.0e-20: return np.sign(p)
return p / q
- 나눗셈시 분모가 0이거나 타입이 안맞는 등의 이유로 오류가 발생할 수 있다.
- 따라서 float형으로 형변환을 해두고, 분모(q)의 절대값이 매우 작으면 분자(p)의 부호만 리턴해준다,
def eval_accuracy(output, y):
est_yes = np.greater(output, 0)
ans_yes = np.greater(y, 0.5)
est_no = np.logical_not(est_yes)
ans_no = np.logical_not(ans_yes)
tp = np.sum(np.logical_and(est_yes, ans_yes))
fp = np.sum(np.logical_and(est_yes, ans_no))
fn = np.sum(np.logical_and(est_no, ans_yes))
tn = np.sum(np.logical_and(est_no, ans_no))
accuracy = safe_div(tp+tn, tp+tn+fp+fn)
precision = safe_div(tp, tp+fp)
recall = safe_div(tp, tp+fn)
f1 = 2 * safe_div(recall*precision, recall+precision)
return [accuracy, precision, recall, f1]
- 앞서 언급한 tp, fp, fn, tn 값을 구하고 그를 통해 정확도(accuracy), 정밀도(precision), 재현율(recall), f1을 구한다.
- 해당 값들을 순서대로 리턴한다.
출력문 수정을 위한 실행함수 재정의
def train_and_test(epoch_count, mb_size, report):
step_count = arrange_data(mb_size)
test_x, test_y = get_test_data()
for epoch in range(epoch_count):
losses = []
for n in range(step_count):
train_x, train_y = get_train_data(mb_size, n)
loss, _ = run_train(train_x, train_y)
losses.append(loss)
if report > 0 and (epoch+1) % report == 0:
acc = run_test(test_x, test_y)
acc_str = ','.join(['%5.3f']*4) % tuple(acc)
print('Epoch {}: loss={:5.3f}, result={}'. \
format(epoch+1, np.mean(losses), acc_str))
acc = run_test(test_x, test_y)
acc_str = ','.join(['%5.3f']*4) % tuple(acc)
print('\nFinal Test: final result = {}'.format(acc_str))
- run_test 내부에서 처리되는 eval_accuracy 함수의 리턴값이 리스트로 변경됨에 따라 acc는 리스트의 형태를 갖게 된다.
- 따라서 그에 맞게 형식을 바꿔 출력해준다.
실행결과
- 중복 데이터 처리 X
Final Test : final result = 0.967,0.649,0.976,0.780
- 중복 데이터 처리 O
Final Test : final result = 0.915,0.919,0.909,0.914
- 정확도는 떨어지지만 F1값을 확실히 올라갔음을 확인할 수 있다.
- 정밀도도 약간 떨어졌지만 재현율이 급격히 상승했기 때문이다.
반응형
'🛠 기타 > Data & AI' 카테고리의 다른 글
[scikit-learn 라이브러리] PolynomialFeatures (다항회귀) (0) | 2020.07.28 |
---|---|
워드 임베딩 - GloVe 기초활용 (0) | 2020.07.28 |
단층 퍼셉트론 - 이진판단 구현 (0) | 2020.07.27 |
워드임베딩 - Word2Vec 기초활용 (0) | 2020.07.27 |
단층 퍼셉트론 - 이진판단 이론 (0) | 2020.07.24 |