by Yngie

TF-IDF (Term Frequency - Inverse Document Frequency)

|

본 포스트의 내용은 고려대학교 강필성 교수님의 강의김기현의 자연어처리 딥러닝 캠프 , 밑바닥에서 시작하는 딥러닝 2 , 한국어 임베딩 , 자연어 처리 인 액션 책을 참고하였습니다.

TF-IDF

우리는 살면서 일어나는 많은 일을 동일한 우선순위에서 대하지 않습니다. 아래는 “IT기업에 고용된 개발자의 뇌 구조” 라는 제목의 이미지입니다. 설명을 돕기 위한 이미지일 뿐이니 진지하게 받아들이실 필요는 없습니다. 잠시 아래의 이미지를 보고 설명을 이어가도록 하겠습니다.

brain

이미지 출처 : newstars.tistory.com

위 그림에서도 알 수 있듯 개인에 따라 어떤 일을 대단히 중요하게 여겨지기도 하고, 어떤 일은 별로 중요치 않게 여기기도 합니다. 이를 자연어처리로도 그대로 가져올 수 있습니다. 문서 내에 있는 단어 중 어떤 단어는 굉장히 중요한 단어이고, 어떤 단어는 별로 중요치 않은 단어일 수 있습니다. 이번에 알아볼 TF-IDF는 더 중요하다고 생각되는 단어에 가중치는 부여하는 방법입니다.

TF-IDF(Term Frequency - Inverse Document Frequency) 는 우리가 이전에 알아본 Bag of Words 를 발전시킨 방법입니다. TF-IDF의 이름에서부터 알 수 있듯 가중치를 결정하는 두 가지 중요한 수치(Metric)가 있습니다. 첫 번째 알아볼 수치는 문서별 단어 빈도(Term frequency, TF) 입니다. 이 수치는 특정 문서에 등장하는 단어의 빈도를 나타냅니다. 이는 Bag of Words 에서 보았던 단어-문서 행렬의 빈도 표현과 같습니다. 문서별 단어 빈도를 측정하는 이유는 “해당 문서에 더 많이 등장하는 단어일수록 그 단어가 문서에서 차지하는 중요도가 커질 것”이라는 가정 때문입니다.

나머지 수치 하나는 단어별 문서 빈도(Document Frequency, DF) 입니다. DF는 특정 단어가 말뭉치 내에 있는 전체 문서 중 몇 개의 문서에 등장했는지를 나타내는 수치입니다. 단어 가중치에서 DF를 고려하는 이유는 무엇일까요? 처음에 뇌구조를 생각했던 것처럼 잠시 자연어처리를 벗어난 다른 주제로부터 DF가 중요한 이유를 알아보도록 합시다. 아래는 한 블로그에 올라온 점심 식단표입니다. (정확히는 훈련소 식단을 복원한 거라고 합니다.)

이미지 출처 : 네이버 블로그

위와 같은 식단표가 있다고 해봅시다. 4주차 목요일에 누군가가 “오늘 점심 메뉴 뭐야?” 라고 물었을 때 메뉴 하나만 대답한다면 일반적인 대답은 “돈까스” 혹은 “부대찌개” 정도일 것입니다. “밥” 혹은 “우유” 도 이들과 같이 점심 메뉴로 나오겠지만 이런 대답은 질문자가 원하는 것은 아니겠지요. “밥”“우유” 가 좋지 않은 대답인 이유는 무엇일까요? 그렇습니다. 다른 날 점심에도 매번 “밥”“우유” 가 나오는데 이게 “오늘 점심” 메뉴에선 별로 중요하지 않기 때문이죠. 각 식단을 하나의 문서로, 메뉴를 단어로 그대로 옮겨 적용해봅시다. 문서 속에서 “밥”“우유” 에 해당하는 단어는 어떤 것들이 있을까요?

영어에서는 [“is”, “can”, “the”] 같은 단어들이 이런 범주에 속합니다. 한글에서도 형태소 분석후 나오는 [‘의’,’가’,’이’,’은’,’들’] 등의 단어는 모든 문서에 등장합니다. 이렇게 과하게 많이 등장하는 단어는 불용어(Stop word)로 지정하여 분석 대상에서 제외하기도 합니다. 모든 문서에 자주 등장하지만 문서 입장에서 보면 크게 의미있는 단어는 아니기 때문입니다. 이런 불용어를 제거하고 난 다음에도 분석할 문서들에 자주 등장하는 단어들은 낮은 가중치를 주어야 할 것입니다.

결론적으로 모든 문서에 자주 등장하는, 즉 단어별 문서 빈도(DF)가 높은 단어는 낮은 가중치를 주어야 합니다. 그렇기 때문에 실제로는 DF의 수치에 역수를 해준 뒤 로그를 취한 수치인 IDF(Inverse Document Frequency) 를 사용합니다. 일반적으로 IDF에 로그를 취하는 이유는 단어의 출현 빈도가 지프의 법칙1을 따르기 때문입니다.

오늘의 목표인 TF-IDF는 이 두 수치를 곱한 것입니다. 이렇게 구해진 TF-IDF는 특정 단어(Term)가 해당 문서(Document)에 얼마나 중요한지를 나타내는 가중치가 됩니다. 수식으로 나타내면 다음과 같습니다.

[\text{TF-IDF(w)} = \text{TF(w)} \times \log_{10} \frac{N}{\text{DF(w)}}]

아래는 실제 4개의 문서(이코노미스트 칼럼 번역 자료)를 형태소 분석 후 문서-단어 행렬(DTM)을 만든 후 문서에 등장하는 일부 단어들의 TF를 기록한 것입니다. 가장 오른쪽 열에는 구해진 TF로부터 DF까지 기록하였습니다. (예시를 돕기 위해서 극적인 사례를 선택하였습니다.) 아래 표를 보며 TF-IDF를 더 잘 이해해봅시다.

DTM 문서1 (석유 관련) 문서2 (부동산 관련) 문서3 (콘텐츠 관련) 문서4 (기후 관련) DF
유가 27 0 0 0 1
원유 19 0 1 0 2
부동산 0 48 0 0 1
주택 0 38 0 0 1
콘텐츠 0 0 35 0 1
넷플릭스 0 0 35 0 1
기후 0 1 0 38 2
탄소 0 0 0 26 1
퍼센트 19 21 8 4 4
달러 24 21 26 14 4
미국 9 25 14 3 4
시장 4 28 22 6 4

위에서 각 단어를 위에서부터 분석해봅시다. 분석에 사용된 12개의 단어 중 “유가”, “원유” 는 석유와 관련된 칼럼에, “부동산”, “주택” 은 부동산과 관련된 칼럼에, “콘텐츠”, “넷플릭스” 는 콘텐츠와 관련된 칼럼에, “기후”, “탄소” 는 기후과 관련된 칼럼에 집중되어 있는 것을 알 수 있습니다. 이 중 “원유”“기후” 는 다른 문서에도 한 번씩 등장했네요. 나머지 네 단어인 “퍼센트”, “달러”, “미국”, “시장” 을 분석한 결과 이 단어들은 모든 문서에서 고르게 1번 이상 등장하고 있는 것을 알 수 있습니다. 심지어 석유와 관련된 문서1에서 “퍼센트” 라는 단어는 “원유” 라는 단어만큼 등장했습니다. 하지만 과연 문서1에서 “퍼센트” 라는 단어가 “달러” 라는 단어만큼 중요할까요? 답은 TF-IDF가 알려줄 것입니다. 아래는 위 표를 기반으로 문서별 단어의 TF-IDF를 구한 표입니다.

DTM 문서1 (석유 관련) 문서2 (부동산 관련) 문서3 (콘텐츠 관련) 문서4 (기후 관련) IDF
유가 16.26 0 0 0 $2\log2$
원유 5.72 0 0.30 0 $\log2$
부동산 0 28.90 0 0 $2\log2$
주택 0 22.88 0 0 $2 \log2$
콘텐츠 0 0 21.07 0 $2 \log2$
넷플릭스 0 0 21.07 0 $2 \log2$
기후 0 0.30 0 11.44 $\log2$
탄소 0 0 0 15.65 $2 \log2$
퍼센트 0 0 0 0 $\log1$
달러 0 0 0 0 $\log1$
미국 0 0 0 0 $\log1$
시장 0 0 0 0 $\log1$

위 표를 보면 아래 모든 문서에 등장하는 “퍼센트”, “달러”, “미국”, “시장” 의 TF-IDF는 0이 되었음을 알 수 있습니다. 이렇게 TF-IDF를 사용하면 한 문서에 자주 등장하는 단어에 대해서 중요도를 높일 수 있으면서도, 그 단어가 분석하려는 말뭉치 속 문서들에 골고루 등장할 경우 중요도를 낮추는 효과를 줄 수 있습니다.

다양한 TF-IDF 측정 방식과 활용

처음 TF-IDF라는 가중치 부여 방법이 고안되고 시간이 지나면서 이를 보정하기 위한 다양한 측정 방법이 생겨났습니다. 아래는 TF와 IDF를 측정하기 위한 다양한 방법을 담은 이미지입니다.

tf_var

idf_var

이미지 출처 : Information Retrieval Models

이들 중 가장 좋은 성능을 보이는 절대적인 방법이 있는 것은 아닙니다. 분석할 말뭉치나 TF-IDF를 적용할 태스크에 따라 가장 적절한 방법이 달라집니다. 아래는 일반적으로 가장 많이 사용되는 TF-IDF 방식을 나타낸 것입니다.

tf-idf

이미지 출처 : Information Retrieval Models

TF-IDF는 자연어처리 외에도 추천 시스템(Recommendation system) 등 다양한 분야에서 활용되고 있습니다. 이를 테면, 콘텐츠와 사용자간 행렬을 구성한 뒤 해당 콘텐츠가 특정 집단의 사용자에게 얼마나 중요한지에 대한 가중치를 부여하는 태스크 등에 사용됩니다.

  1. “지프의 법칙에 따르면 어떠한 자연어 말뭉치 표현에 나타나는 단어들을 그 사용 빈도가 높은 순서대로 나열하였을 때, 모든 단어의 사용 빈도는 해당 단어의 순위에 반비례한다. 따라서 가장 사용 빈도가 높은 단어는 두 번째 단어보다 빈도가 약 두 배 높으며, 세 번째 단어보다는 빈도가 세 배 높다. 예를 들어, 브라운 대학교 현대 미국 영어 표준 말뭉치의 경우, 가장 사용 빈도가 높은 단어는 영어 정관사 “the”이며 전체 문서에서 7%의 빈도(약 백만 개 남짓의 전체 사용 단어 중 69,971회)를 차지한다. 두 번째로 사용 빈도가 높은 단어는 “of”로 약 3.5% 남짓(36,411회)한 빈도를 차지하며, 세 번째로 사용 빈도가 높은 단어는 “and”(28,852회)로, 지프의 법칙에 정확히 들어 맞는다. 약 135개 항목의 어휘만으로 브라운 대학 말뭉치의 절반을 나타낼 수 있다.” -위키피디아 : 지프의 법칙(Zipf’s law) 

Comment  Read more

Bag of Words (BoW)

|

본 포스트의 내용은 고려대학교 강필성 교수님의 강의김기현의 자연어처리 딥러닝 캠프 , 밑바닥에서 시작하는 딥러닝 2 , 한국어 임베딩 , 자연어 처리 인 액션 책을 참고하였습니다.

단어를 벡터로 표현하기

자연어처리에서 우리가 처리하고자 하는 문서(Document)나 문장(Sentence)은 각각의 길이가 다릅니다. 많은 단어로 구성된 문서도 있고 적은 단어로 구성된 문서도 있지요. 서로 다른 길이인 문서를 컴퓨터에 집어넣기 위해서는 일정한 길이의 벡터로 변환해주어야 합니다. 컴퓨터에게 행렬 혹은 텐서 연산을 맡기기 위해서는 모든 벡터의 길이를 갖게 해주어야 하기 때문입니다. 테이블로 이루어진 정형 데이터의 경우에는 이미 모든 인스턴스의 길이가 같기 때문에 일정한 길이의 벡터로 변환할 필요가 없습니다. 하지만 비정형 데이터인 자연어의 경우 단어나 문서를 벡터로 표현(Representation)하는 것은 중요한 과제 중 하나입니다. 단어를 벡터로 표현하는 방법은 크게 두 가지로 나눌 수 있습니다. 첫 번째는 숫자 기반의 표현(Count-based representation) 입니다. 숫자 기반의 표현에는 이번 게시물의 주제인 Bag of Words, 그리고 이를 고도화한 TF-IDFN-gram 등이 있습니다. 두 번째는 분산 표현(Distributed representation) 입니다. 임베딩(Embedding) 이라고도 부르는 분산 표현 방식에는 Word2VecGloVe, Fasttext 등 다양한 방법이 있습니다. 이번 시간에는 숫자 기반의 표현에서 가장 기본이 되는 Bag of Words 에 대해 알아보도록 합시다.

Bag of Words

Bag of Words 는 문서를 여러 단어가 들어있는 가방(bag)처럼 생각하는 표현 방식입니다. 유튜브에 존재하는 왓츠 인 마이백(What’s in my bag?) 영상을 떠올려 봅시다. 해당 영상에서 유튜버는 자기 가방에 들어있는 물건을 하나씩 꺼내어 확인해주는데요. 이런 방식을 문서에 적용한 것이 Bag of Words 입니다. 아래 그림을 보며 설명을 이어나가겠습니다.

bag_of_words

이미지 출처 : dudeperf3ct.github.io

왓츠 인 마이백 영상에서 유튜버가 가방에 어떤 물건이 있는지를 확인하여 보여주는 것처럼, Bag of Words 에서도 문서로부터 단어를 하나씩 꺼내어 기록합니다. 위 그림처럼 문서 내에 있는 모든 단어에 대해 단어가 등장할 때마다 기록하는 방식입니다. Bag of Words 는 ‘이렇게 헤아린 단어의 빈도로부터 무언가를 추론할 수 있을 것이다’라는 전제를 바탕으로 합니다.

Term-Document Matrix

단어-문서 행렬(Term-Document Matrix, TDM) 을 만드는 것은 Bag of Words 의 처음이자 끝입니다. 단어-문서 행렬에서 열(Column)에 해당하는 부분은 우리가 분석하고자 하는 각각의 문서(Document)를 입니다. 행에 해당하는 부분은 문서 전체에 등장하는 단어(Term)가 됩니다. 그리고 각 문서에 해당 단어가 등장하는지 아닌지, 혹은 몇 번이나 등장하는지를 기록합니다. 경우에 따라서는 단어-문서 행렬을 전치시킨 문서-단어 행렬(Document-Term Matrix, DTM)을 사용하기도 합니다.

단어-문서 행렬은 단어를 어떤 방식으로 기록할 것인지에 따라 두 종류로 나뉩니다. 아래 이미지를 통해 두 방식을 비교할 수 있습니다.

tdm

이미지 출처 : Text-Analytics Github

위 그림에서 왼쪽에 있는 단어-문서 행렬은 이진 표현(Binary representation)을 사용하여 나타낸 것이고 오른쪽에 있는 단어-문서 행렬은 빈도 표현(Frequency representation)을 사용하여 나타낸 것입니다. 분석하고자 하는 문장이 길지 않기 때문에 두 방식간에 큰 차이는 없습니다. 유일한 차이는 2번 행에 해당하는 “Likes” 입니다. 이진 표현은 문서에 단어가 등장했는지 아닌지만을 나타내기 때문에 $S_1$ 에서의 값이 $1$ 이 됩니다. 반면에 단어가 등장한 횟수를 헤아리는 빈도 표현에서는 $S_1$ 에 “Likes” 가 2번 등장하기 때문에 $2$ 로 표현한 것을 볼 수 있습니다. 두 표현 중 빈도 표현이 이진 표현보다 더 많은 정보를 담고 있는 것은 사실입니다. 하지만 특정 태스크에서는 이진 표현이 더 좋은 결과를 보여줄 때도 있기 때문에 태스크에 맞는 표현 방식을 사용하는 것이 좋습니다.

단점과 의의

Bag of Words의 단점은 단어가 등장하는 순서, 즉 어순을 고려하지 않는다는 점입니다. 아래는 (비속어가 있긴 하지만) “한글의 위대함.jpg” 라는 제목으로 떠도는 이미지입니다.

bog

(맨 마지막 문장에 등장하는 “시발”만 “씨발”로 오타를 고친다면) 위 이미지에 나타난 11개 문장을 Bag of Words로 표현하면 모두 ”{ 영어는 : 1, 씨발 : 1, 이런거 : 1, 안되잖아 : 1 }” 로 나오게 됩니다. 실제로는 11개의 문장이 서로 다르지만 Bag of Words 로 표현하면 모두 같게 되는 것입니다. 다른 예시도 있습니다 “Mary loves John”“John loves Mary” 는 주어와 목적어가 반대이기 때문에 의미가 완전히 다른 문장입니다. 하지만 이 두 문장을 Bag of Words로 표현하면 모두 ”{ Mary : 1, loves : 1, John : 1 }” 로 같아져 버립니다. 이런 단점 때문에 단어 사이의 관계나 문맥의 의미가 중요한 태스크에 Bag of Words 를 사용하는 것은 적절하지 못할 때가 많습니다.

이런 단점에도 불구하고 Bag of Words는 이해하기 쉬우며 TF-IDF 나 N-gram의 기반이 되는 방법이 됩니다. 또한 단어를 벡터로 표현하는 가장 고전적인 방법이라는 의미도 가지고 있습니다.

Comment  Read more

품사 태깅 (Part-of-Speech Tagging, POS Tagging)

|

본 포스트의 내용은 고려대학교 강필성 교수님의 강의김기현의 자연어처리 딥러닝 캠프 , 밑바닥에서 시작하는 딥러닝 2 , 한국어 임베딩 책을 참고하였습니다.

POS Tagging

이번 게시물에서는 품사 태깅에 대해 좀 더 자세히 알아봅니다. 품사 태깅의 개괄적인 정보를 포함하여 어휘 분석과 구조 분석에 대한 내용은 이곳 에서 보실 수 있습니다.

Pointwise prediction

품사 태깅 알고리즘은 크게 3가지로 나눌 수 있습니다. 첫 번째는 점별 예측(Pointwise prediction) 모델 입니다. 이 방식은 해당 단어를 포함한 단어 시퀀스를 분류기에 넣으면 해당하는 단어의 품사를 예측하는 알고리즘입니다. 점별 예측 알고리즘의 예로는 최대 엔트로피 모델(Maximum Entropy Model) 과 서포트 벡터 머신이 있습니다. 각 단어의 품사를 따로 예측하기 때문에 Pointwise라는 이름이 붙었습니다. 아래는 점별 예측 모델을 통해 품사 태깅을 하는 과정을 도식화한 이미지 입니다.

pos1

이미지 출처 : Text-Analytics Github

이 중 최대 엔트로피 모델이 어떻게 작동하는지 알아보도록 합시다. 최대 엔트로피 모델은 접두사(prefix), 접미사(suffix) 및 주변 단어들로부터 해당 품사에 대한 정보를 얻어내는 방식입니다. 아래 표를 참고하여 쉬운 예시를 들어보겠습니다.

tagging_table

이미지 출처 : t1.daumcdn.net

만약 “playing” 이라는 단어의 품사를 매길 때, 해당 단어의 접미사가 “-ing” 이므로 위 표에서 VBG 를 할당하는 방식입니다. 아래는 최대 엔트로피 모델을 수식으로 표현한 것입니다. $p(t \vert C)$ 는 특정 문맥이 주어졌을 때 각 품사가 태깅될 확률입니다.

[p(t C) = \frac{1}{Z(C)} \exp(\sum^n_{i=1} \lambda_if_i(C,t)) \ p(t_1, \cdots , t_n w_1, \cdots , w_n) \approx \prod^n_{i=1} p(t_i w_i)]

위 식에서 $\lambda_i$ 는 가중치를 나타냅니다. 더 중요한 정보에 대해서 더 큰 값을 나타내게 됩니다. $Z(C)$ 는 적절한 확률 분포를 위한 정규화 상수(Normalization constant)입니다.

Probabilistic prediction

두 번째 분류는 확률 기반의 모델(Probabilistic models) 입니다. 확률 기반의 모델은 점별 예측 모델과 달리 문장 전체를 한꺼번에 입력받는다는 특징을 가지고 있습니다. 그리고 입력 문장에 하여 가장 확률이 높은 품사 조합을 할당하게 됩니다. 입력 문장을 $X$ , 할당되는 품사를 $Y$ 라고 하였을 때 확률 기반의 모델을 아래와 같은 수식으로 나타낼 수 있습니다.

[\text{argmax}_{Y}P(Y X)]

확률 기반의 모델 안에도 두 가지 소분류가 존재합니다. 히든 마르코프 모델(Hidden Markov model, HMM)과 같이 주어진 문자에 대해 가장 적절한 태그를 찾는 Generative sequence models 과 Conditional Random Field(CRF)와 같이 분류기로 전체 문장의 시퀀스를 예측하는 Discriminative sequence models이 있습니다.

이 중 Generative sequence model 에 대해 먼저 알아봅시다. 이 알고리즘은 베이즈 확률을 이용합니다. 첫 번째 토큰에 대한 태그를 먼저 달고 이후에 올 토큰에 대해서는 조건부 확률을 활용하여 품사를 할당하게 됩니다. 베이즈 룰(Bayes’ Rule)을 활용하여 확률 기반 모델의 수식을 아래와 같이 변형할 수 있습니다.

[\text{argmax}_{Y}P(Y X) = \text{argmax}_{Y} \frac{P(X Y)P(Y)}{P(X)} = \text{argmax}_{Y} {P(X Y)P(Y)}]

위 식에서 $P(X \vert Y)$ 는 단어와 품사 사이의 상관관계를 나타내는 Emission probabilities, $P(Y)$ 는 품사와 품사 사시의 상관 관계를 나타내는 Transition probabilities 입니다. 대표적인 Generative sequence model인 은닉 마르코프 모델(Hidden Markov Models, HMMs) 마르코프 가정, 즉 모든 토큰이 독립이라는 가정을 추가하여 $P(X \vert Y)$ 와 $P(Y)$ 를 구해냅니다. 수식으로는 아래와 같이 나타낼 수 있습니다.

[P(X Y) \approx \prod^{l}_{1} P_E(x_i y_i) \qquad
P(Y) \approx \prod^{l+1}_{i=1} P_T(y_i y_{i-1})]  

아래는 은닉 마르코프 모델을 사용하여 품사 태깅을 진행하는 과정을 이미지로 나타낸 것입니다.

pos2

이미지 출처 : Text-Analytics Github

다음으로는 Discriminative sequence model 중 대표적인 알고리즘인 Conditional Random Field(CRF)에 대해 알아봅시다. 이 방법은 성능이 좋기 때문에 트랜스포머를 활용한 Pretrained model에서도 가장 많이 사용되는 품사 태깅 알고리즘 입니다. Generative 방식은 $P(Y)$ 를 통해서 이전 토큰의 품사가 다음 토큰의 품사를 결정하는 데에 영향을 끼쳤습니다. 하지만 Discriminative 방식은 이전 시퀀스의 품사가 주는 영향을 제한하여 완화하였습니다. 그리고 연속적으로 품사를 태깅하는 것이 아니라 모든 문장을 보고 난 이후에 한번에 태깅합니다. 아래는 Generative와 Discriminative 방식을 비교한 이미지입니다.

pos3

이미지 출처 : people.cs.umass.edu

Neural Network based Models

신경망을 기반으로 품사를 태깅하는 모델(Neural Network based models)도 있습니다. 신경망 기반의 모델도 크게 두 가지로 나눌 수 있습니다. 첫 번째는 Window 기반의 모델입니다. 이 모델은 특정 크기의 Window를 선정하여 타겟 단어 주위의 단어로부터 타겟 단어의 품사를 예측합니다. 아래는 Window 기반의 모델을 도식화하여 나타낸 것입니다.

windowBased

이미지 출처 : Natural Language Processing (almost) from Scratch by Collobert

두 번째는 Sentence 기반의 모델입니다. 문장 내 단어들을 특성화한 뒤 문장을 특성으로 표현하여 신경망 모델에 넣어 품사를 태깅하게 됩니다.

sentenceBased

이미지 출처 : Natural Language Processing (almost) from Scratch by Collobert

신경망 모델 중에서는 RNN 가장 많이 쓰입니다. RNN에 대한 일반적인 설명은 이곳 에서 볼 수 있습니다. 아래는 RNN을 사용하여 각 단어의 품사를 태깅하는 과정을 이미지로 나타낸 것입니다.

rnnPos

이미지 출처 : Text-Analytics Github

최근에는 다양한 모델을 혼합하여 사용하기도 합니다. 아래는 장단기 기억망(LSTM)과 합성공 신경망(ConvNet), 그리고 CRF를 혼합하여 사용한 모델을 도식화한 것입니다.

hybridPOS

이미지 출처 : End-to-end Sequence Labeling via Bi-directional LSTM-CNNs-CRF by Ma and Hovy

Comment  Read more

어휘 분석과 구조 분석 (Lexical & Syntax Analysis)

|

본 포스트의 내용은 고려대학교 강필성 교수님의 강의김기현의 자연어처리 딥러닝 캠프 , 밑바닥에서 시작하는 딥러닝 2 , 한국어 임베딩 책을 참고하였습니다.

어휘 분석 (Lexical Analysis)

자연어처리(Natural Language Processing)의 대부분의 작업들은 기본 단위로 형태소(Morpheme)를 가집니다. 여기에서 말하는 형태소의 사전적 정의는 “의미를 가지는 요소로서는 더 이상 분석할 수 없는 가장 작은 말의 단위”입니다. 전체 말뭉치(Corpus)로부터 기본 단위인 형태소를 얻어내기 위해서는 어휘 분석(Lexical Analysis)이 필요합니다.

어휘 분석의 주요 태스크는 문장 분절, 토큰화(Tokenization), 품사 태깅(Part-of-Speech Tagging, POS Tagging)이 있습니다. 추가적으로 개체명 인식(Named Entity Recognition, NER) 이나 명사구 인식 등의 작업이 수행됩니다.

문장 분절 (Sentence splitting)

가장 먼저 문장 분절(Sentence splitting) 에 대해서 알아봅시다. 토픽 모델링(Topic Modeling)과 같은 몇 가지 태스크를 제외하면 문장 분절은 우리가 가장 먼저 수행해야 할 분석입니다. 문장을 분절할 때, 보통은 ”.” / “?” / “!” 등과 같은 문장 부호를 기준으로 나눕니다. 정제된 데이터라면 이런 문장 부호를 끝으로 문장이 끝나기 때문입니다. 하지만 이 문장 부호들이 항상 올바른 문장의 경계가 되는 것은 아닙니다.

다음의 예시들을 살펴봅시다. “Mr.Lee is going home.”, “원주율은 3.141592… 입니다.” 이 두 문장을 문장 부호를 기준으로 나누어 봅시다. 첫 번째 문장은 다음과 같이 분리될 것입니다. [“Mr.”, “Lee is going home.”] 두 번째 문장은 다음과 같이 분리될 것입니다. [“원주율은 3.”, “141592.”, “.”, “.”, “입니다.”] 두 경우 모두 제대로 문장 분절이 이루어지지 않는 것을 볼 수 있습니다. 또는 인용구를 포함하는 문장도 문장 부호를 분절의 기준으로 삼는데 문제가 됩니다.

이런 문제 때문에 룰베이스 알고리즘이나 분리된 문장을 모델에 학습시키는 방법을 사용합니다. 자연어처리 패키지인 NLTK(Natural Language Toolkit) 등에서는 문장 분절 기능을 제공하고 있습니다. 아래는 “자연어처리는 인공지능의 한 줄기 입니다. 시퀀스 투 시퀀스의 등장 이후로 딥러닝을 활용한 자연어처리는 새로운 전기를 맞이하게 되었습니다. 문장을 받아 단순히 수치로 나타내던 시절을 넘어, 원하는 대로 문장을 만들어낼 수 있게 된 것입니다.” 라고 적힌 파일을 문장별로 분절하는 예시 코드입니다. nltk 내에 있는 sent_tokenize 함수를 사용하여 문장을 분절하였습니다.

import sys, fileinput, re
from nltk.tokenize import sent_tokenize

if __name__ == "__main__":
    for line in fileinput.input(files="gdrive/My Drive/nlp_exercise/sent_tokenize_ex.txt"):
        if line.strip() != "":
            line = re.sub(r'([a-z])\.([A-Z])', r'\1. \2', line.strip())

            sentences = sent_tokenize(line.strip())

            for s in sentences:
                if s != "":
                    sys.stdout.write(s + "\n")

해당 코드를 실행하여 출력되는 값은 다음과 같습니다. 아래의 예시에서 원하는 대로 문장 분절이 된 것을 볼 수 있습니다.

“자연어처리는 인공지능의 한 줄기 입니다. 시퀀스 투 시퀀스의 등장 이후로 딥러닝을 활용한 자연어처리는 새로운 전기를 맞이하게 되었습니다. 문장을 받아 단순히 수치로 나타내던 시절을 넘어, 원하는 대로 문장을 만들어낼 수 있게 된 것입니다.”

토큰화 (Tokenization)

문장 분절을 했다면 토큰화(Tokenization) 를 통해 더 자세한 어휘 분석을 할 수 있습니다. 토큰화란 텍스트를 이후 자연어처리에 사용되는 토큰(Token) 이라는 기본적인 단위로 나누는 과정입니다. 일반적으로 공개되어 있는 토큰 분석기(Tokenizer)를 사용합니다. 여러 개의 토큰 분석기가 있고 같은 문장을 분석하더라도 각 분석기마다 내놓는 토큰의 결과가 다릅니다. 그렇기 때문에 자신이 수행하려는 태스크에 맞는 분석기를 선택하여 사용하는 것이 중요합니다. 아래는 MC tokenizer와 Scan tokenizer로 특정 문서를 토큰화한 결과입니다.

두 분석기로 추출한 토큰의 결과가 다릅니다. 예를 들어, MC tokenizer로부터 추출된 토큰에는 공백이 제거되지 않고 숫자와 구두점, 특수문자 등은 모두 제거된 것을 볼 수 있습니다. 반대로 Scan tokenizer로부터 추출된 토큰에는 공백이 모두 제거되었으나 숫자와 구두점, 특수문자가 그대로 존재하는 것을 볼 수 있습니다.

tokenizer

이미지 출처 : Text-Analytics Github

하지만 토큰화도 문장 분절과 마찬가지로 어려움이 많습니다. 대표적인 예시로 “pre-trained, C++”, “A/C” 과 같이 한 단어 내에 특수 문자가 있는 경우가 있습니다. 또한 ”:-)”, “ㅋㅋㅋㅋㅋㅋㅋㅋ” 과 같이 이모티콘이나 구어체의 경우 토큰을 구별하기 어렵습니다. 중국어와 같은 특정 언어의 경우 공백이 존재하지 않아 토큰을 구분하기 어렵기도 합니다.

형태 분석 (Morphological analysis)

어휘 분석의 또 다른 작업으로 형태 분석(Morphological analysis) 이 있습니다. 형태 분석의 목적은 단어의 의미를 훼손하지 않는 선에서 단어를 정규화(Normalize)하는 것입니다. 정규화를 진행하면 말뭉치에 전체에 있는 텍스트 데이터의 차원을 줄일 수 있습니다. 예를 들어, “I love her and she loves me.” 와 같은 문장을 토큰화 할 때 정규화를 하지 않으면, “love”“loves” 는 다른 토큰으로 취급됩니다. 한 문장에서는 별 문제가 없어 보이지만 말뭉치 전체에 대해서 정규화를 해주지 않는다면 데이터의 차원이 매우 커지게 되고 Sparsity가 크게 늘어나는 문제가 발생합니다.

형태 분석에는 두 가지 방법, 어간 추출(Stemming)표제어 추출(Lemmatization) 이 있습니다. 먼저 어간 추출은 단어에서 정보를 이끌어 내는 데 중점을 두고 있는 분석 방법입니다. 어간 추출은 규칙 기반(Rule-based) 알고리즘을 사용하여 단어들의 기본 형태를 찾고 나머지 접사 부분을 잘라내는 데 기반을 두고 있습니다. 단어의 품사에 상관없이 의미의 기본 형태만 남기고 잘라내기 때문에 간단하고 빠르다는 장점이 있습니다. 하지만 규칙 기반 알고리즘의 특성상 분석하는 언어에 종속적이며 아예 다른 단어가 하나의 기본형으로 귀결되는 경우도 있어 의미(Semantic)를 보존하지 못하는 문제가 발생하기도 합니다.

표제어 추출은 품사를 보정해주며 정규화를 진행합니다. 아래 그림을 보면 어간 추출과 표제어 추출을 직접적으로 비교할 수 있습니다. 어간 추출은 단어의 품사가 어떻든지 동일하게 잘라내버립니다. 어간 추출에 의해서는 “Innovation, Innovate, Innovative” 가 모두 하나의 형태인 “Innovat” 로 잘려나가는 것을 볼 수 있습니다. 하지만 표제어 추출은 “Innovation, Innovate, Innovative” 의 품사를 모두 보존한 채로 정규화 하는 것을 볼 수 있습니다. 표제어 추출은 품사를 고려하는 작업 때문에 어간 추출보다 속도가 느리다는 단점이 있습니다. 하지만 단어의 의미를 잘 보존하며 이미 만들어진 사전을 기반으로 분석하기 때문에 오류가 적다는 장점도 가지고 있습니다.

morpho

이미지 출처 : Text-Analytics Github

두 방법 중 “어떤 한 방법이 더 좋다” 고 평가할 수 있는 지표는 없습니다. 필요한 태스크에 따라 어간 추출과 표제어 추출의 장단점을 잘 고려하여 사용하여야 합니다. 일반적으로 속도가 중요시되고 의미의 비중이 적은 정보 검색 등의 태스크에는 어간 추출이 많이 사용됩니다. 하지만 텍스트 마이닝에서 수행되는 대부분의 태스크에서는 단어의 의미가 중요시 되기 때문에 표제어 추출이 자주 사용되는 편입니다.

POS Tagging

품사 태깅(Part-of-Speech tagging, POS tagging) 도 중요한 어휘 분석 작업 중 하나입니다. 품사 태깅은 POS Tagger를 사용하여 각 토큰에 해당하는 품사를 찾아주는 과정입니다. “I love you.”, “All you need is love.” 처럼 같은 단어( “love” ) 라도 다른 품사로 쓰일 수 있습니다. (앞 문장에서는 동사, 뒷 문장에서는 명사로 사용된 것을 볼 수 있습니다.)

머신러닝을 사용하여 품사 태깅을 하기 위해서는 수동으로 품사를 태깅한 말뭉치가 필요합니다. 이 때 훈련에 사용한 말뭉치와 비슷한 도메인 데이터에는 잘 작동하는 편이지만 다른 도메인에는 성능에 차이가 생기기도 합니다. 품사 태깅에는 의사 결정 트리(Decision Trees), 히든 마르코프 모델(Hidden Markov Models, HMM), 서포트 벡터 머신(Support Vector Machines, SVM) 등 다양한 머신러닝 알고리즘을 적용할 수 있습니다. 최근에는 Brill tagger 와 같은 트랜스포메이션 기반의 tagger가 많이 사용되고 있습니다.

개체명 인식 (Named Entity Recognition, NER)

품사 태깅과 마찬가지로 개체명 인식(Named Entity Recognition, NER)도 토큰 간의 관계를 파악하기 위한 어휘 분석 방법 중 하나입니다. 개체명 인식을 통해 텍스트 데이터 내에서 시간, 장소, 인물과 같은 특수한 개체(Entity)를 인식합니다. 예를 들어 “Get me a flight from New York City to San Francisco for next Thursday.” 라는 문장이 있다고 해 봅시다. 해당 문장에 개체명 인식을 수행하면 “New York City” 라는 단어는 출발 장소로, “San Francisco” 라는 단어는 목적지로, “Thursday” 라는 단어는 출발 시각으로 미리 인식하여 구분할 수 있습니다.

개체명 인식은 크게 두 가지 방법으로 수행됩니다. 첫 번째는 각 개체에 대한 사전을 구축하는 방법이고 두 번째는 규칙 기반의 알고리즘을 사용하는 방법입니다. 사전 구축 방식에는 미리 리스트를 구축하여 같은 개체를 매칭하는 List Lookup 방식이 있습니다. 이는 단순하고 빠르다는 장점이 있지만 리스트를 관리하거나 업데이트 하기가 어렵다는 단점도 있습니다.

개체명 인식을 위한 규칙 기반 알고리즘의 예시로는 Shallow parsing approach가 있습니다. 이 방법은 특정한 구조를 발견하면 그 구조에 따라 개체명을 할당하는 방식입니다. 예를 들어 “Cap word + Street, Boulevard, Avenue, Crescent, Road” 라는 구조를 발견하면 이것이 위치를 나타내는 개체임을 할당하게 됩니다.

이 두 가지 방법 외에도 머신러닝 기반의 알고리즘인 MITIE나 CRF++, CNN 등도 경우에 따라 사용하곤 합니다.

Syntax Analysis

구조 분석(Syntax analysis) 은 문장이 들어왔을 때 문법 형식에 맞도록 구조를 분석하는 과정입니다. 구조 분석에 사용되는 알고리즘은 파서(Parser)입니다. 파서 알고리즘은 두 가지 속성을 가지고 있습니다. 첫 번째 속성은 방향성(Directionality) 입니다. 이 방향성에 따라서 Top-down 방식으로 분석할 지, Bottom-up 방식으로 분석할 지를 결정하게 됩니다. 두 번째 속성은 탐색 전략(Search strategy)입니다. 이 속성은 트리를 옆으로 탐색할 것인지 아래쪽으로 파고들 것인지를 결정하게 됩니다. 이 두 특성에 따라 파서의 알고리즘이 달라지게 됩니다.

구조 분석을 표현하는 방식은 트리 방식과 리스트 방식이 있습니다. 아래 그림은 “John ate the apple” 을 분석할 경우 아래와 같이 나타낼 수 있습니다.

syntax_rep

이미지 출처 : Text-Analytics Github

구조 분석을 한다고 해서 항상 한 가지 트리만 생성되는 것은 아닙니다. 언어의 모호함 때문에 어떤 알고리즘 방식을 채택하는지에 따라서 같은 문장에서도 다른 트리가 생성됩니다. 여기서 말하는 언어의 모호함에는 어휘로부터 발생하는 모호함(Lexical ambiguity)과 구조로부터 발생하는 모호함(Structural ambiguity)이 있습니다. 아래는 “Time flies like an arrow” 라는 문장에 구조 분석을 수행했을 때 어휘의 모호함 때문에 발생할 수 있는 두 가지 트리입니다.

lex_ambi

이미지 출처 : Text-Analytics Github

구조로부터 발생하는 모호함에 의해서도 구조 분석 결과가 다르게 나타날 수 있습니다. 아래 이미지는 “John saw Mary in the park” 문장에 구조 분석을 수행한 결과를 트리로 나타낸 것입니다. 해당 문장만 보고는 “John”“Mary” 를 공원 안에서 본 것인지 공원 밖에서 본 것인지 알 수 없습니다. “Mary” 의 위치에 따라 구조 분석한 결과가 달라지는 것을 볼 수 있습니다.

str_ambi

이미지 출처 : Text-Analytics Github

Comment  Read more

모델 검증과 평가 (Validation & Evaluation)

|

본 포스트는 문일철 교수님의 인공지능 및 기계학습 개론 I 를 바탕으로 작성하였습니다.

Validation

가지고 있는 데이터셋을 학습 데이터와 테스트 데이터로 왜 나누어야 하는 지를 설명했을 때 나왔던 수험생을 다시 데려와 봅시다. 이전 게시물에서는 수능처럼 학생을 최종적으로 평가하기 위해서 약 20%의 테스트 데이터를 따로 빼두는 과정에 대해 설명하였습니다. 그런데 문제지만 풀다가 수능날 바로 시험을 보는 학생은 많지 않을 것입니다. 자의든 타의든 수능을 대비하기 위한 몇 번의 모의고사를 치르게 됩니다.

모의고사를 치는 이유는 무엇일까요? 수능이 끝나면 그 점수를 그대로 받아야 하는데 그 전에 자기가 부족한 부분은 어디인지, 어떤 상황에서 점수가 좋고 나쁜 지를 판단하기 위해서일 것입니다. 모의고사 결과를 보고 수능 전까지 필요한 부분을 점검하고 보완해나가게 되지요.

머신러닝 모델도 마찬가지입니다. 학습 데이터로 모델을 생성한 뒤에 중간과정 없이 테스트 데이터로 모델을 평가한다고 해봅시다. 이렇게 생성된 모델은 과적합이나 과소적합이 발생할 수 있습니다. 하지만 모델이 우리가 가지고 있는 모든 데이터를 봐버렸기 때문에 이 모델을 개선 후 다시 테스트할 수 있는 방도가 없습니다. 과적합이나 과소적합이 발생하지 않은 모델이라 하더라도 이 모델이 최선인지 더 나은 모델이 있는지 알 수 있는 방법 역시 없게 되지요.

모델에게도 테스트 데이터 전에 자신을 점검해 볼 수 있는 모의고사 같은 과정이 필요합니다. 머신러닝에서는 이를 검증(Validation)이라고 하고 검증에 사용하는 데이터셋을 검증 데이터셋(Validation dataset)이라고 합니다. 검증 데이터셋은 학습 데이터셋의 일부를 사용합니다. 다음으로 다양한 모델 검증 방법에 대해서 알아보겠습니다.

Various Validation

머신러닝 모델의 검증 방법은 크게 3가지로 나눌 수 있습니다. 첫 번째가 Holdout, 두 번째가 K-fold CV, 마지막이 LOOCV입니다. 각각에 대해 알아보도록 합시다.

Holdout

Holdout 검증은 가장 기본적인 모델 검증 방법입니다. 전체 데이터셋에서 테스트 데이터를 분리하고 남은 학습 데이터의 일부를 검증 데이터셋으로 또 분리하는 방법입니다. 즉, 전체 데이터를 3개(학습 데이터, 검증 데이터, 테스트 데이터)로 나누게 되는 것이지요. 이 방식은 가장 간단하지만 학습 데이터에 손실이 있기 때문에 데이터가 적은 경우에 사용하기 힘들고, 검증을 한 번 밖에 진행할 수 없다는 단점이 있습니다. 아래는 홀드아웃 방식을 적용했을 때 데이터가 나누어지는 방식입니다.

Holdout

이미지 출처 : datavedas.com

K-fold CV

홀드아웃 방식은 학습 데이터에 손실이 있고 검증을 한 번 밖에 할 수 없다는 단점이 있었습니다. 실제로는 이를 개선하기 위한 교차검증(Cross validation, CV) 방식을 사용합니다. 교차 검증은 최소 2번 이상의 검증을 진행하므로 각 검증 결과치의 평균을 모델의 검증 결과로 사용하게 됩니다.

교차 검증의 대표적인 방식으로 K-fold 교차검증(K-fold cross validation)이 있습니다. K-fold 교차 검증은 학습 데이터를 K개로 나눈 뒤 차례대로 하나씩을 검증 데이터셋으로 활용하여 K번 검증을 진행하는 방식입니다. 이 방법도 학습 과정마다 학습 데이터에 손실이 있기는 하지만, 결국 전체 데이터를 다 볼 수 있다는 장점이 있고 검증 횟수를 늘릴 수 있다는 장점도 있습니다. 다음은 $K=5$ 인 K-fold 교차검증이 진행되는 방식을 그림으로 나타낸 것입니다. 일반적으로는 $5 \leq K \leq 11$ 범위의 $K$ 를 설정하여 사용합니다.

k-fold

이미지 출처 : researchgate.net

LOOCV

LOOCV(Leave-one-out cross validation)는 K-fold 교차 검증의 극단적인 형태로, 학습 데이터셋이 극도로 작을 때 사용할 수 있는 교차검증 방법입니다. LOOCV는 오직 한 개의 인스턴스만을 검증 데이터셋으로 남겨 놓습니다(Leave-one-out). 검증 데이터가 하나이므로 학습 데이터가 총 $N$ 개라면 총 $N$ 번의 교차 검증을 진행하게 됩니다. 학습 데이터의 손실을 최소화 할 수 있지만, 샘플 데이터 수가 1000개만 되어도 총 1000번의 학습과 검증을 진행해야 하기 때문에 시간과 컴퓨팅 자원이 많이 소모된다는 단점이 있습니다. 아래는 LOOCV가 진행되는 방식을 그림으로 나타낸 것입니다.

loocv

이미지 출처 : smlee729.github.io

아래는 위 3개의 검증 방법을 비교하는 이미지입니다.

LOOCV

이미지 출처 : eda-ai-lab.tistory.com

Hyperparameter Optimization

검증을 통해서 과적합이 일어나는 지점을 찾는 것도 중요하지만, 성능이 좋은 모델을 찾는 것 역시 모델 검증을 해야하는 이유입니다. 더욱 성능이 좋은 모델을 만들기 위해 하이퍼파라미터 최적화를 해주어야 합니다. 하이퍼파라미터(Hyperparameter)는 학습 과정에서 모델이 알아서 바꾸는 파라미터 외에 모델을 만드는 사람이 지정하는 파라미터를 의미합니다. 대표적인 하이퍼파라미터의 예시로는 경사 하강법에서의 학습률(Learning rate), 정칙화(Regulation)의 정도를 조정하는 $\alpha$ 등이 있습니다. 모델마다 설정해주어야 하는 하이퍼파라미터가 다르기 때문에 사용하는 모델에 따라 필요한 하이퍼파라미터를 적당히 조정해주어야 합니다.

어떤 하이퍼파라미터가 최상의 결과를 낳는지 쉽게 알기 어렵고, 하이퍼파라미터의 조합에 따라서도 모델의 결과가 달라지기 때문에 검증 결과를 비교하여 최적의 하이퍼파라미터 조합을 찾아야 합니다. 최적의 하이퍼파라미터 조합을 찾는 방법은 크게 4가지로 나눌 수 있습니다.

말 그대로 수동(Manual)으로 하이퍼파라미터를 조정하는 방식입니다. 모델을 설계하는 사람이 경험에 의한 직관을 사용하여 최적의파라미터 조합을 설정합니다.

하이퍼파라미터마다 적용하고 싶은 값의 목록을 설정해둔 뒤에 그 조합을 모두 시행해보고 최적의 조합을 찾아내는 방식입니다. 직관적으로 이해하기가 쉽지만 조정할 하이퍼 파라미터가많아지면 학습 횟수가 많아지는 단점이 있습니다. 예를 들어, 학습률 $\eta = [0.001, 0.01, 0.1, 1]$ 로 4개, 정칙화 파라미터 $\alpha = [0.001, 0.01, 0.2, 3]$ 로 4개의 목록을 작성한 뒤에 각 조합에 대해 모두 학습을 수행하므로 총 $4 \times 4 = 16$ 번에 대한 학습 및 검증을 하게 됩니다.

조정하고 싶은 하이퍼파라미터 마다 조정하고 싶은 범위를 정합니다. 실제 학습 과정에서는 범위 내에 있는 임의의 값을 설정하여 각 파라미터에 대한 조합을 정합니다. Grid search는 지정한 값에 대해서만 학습과 검증을 시도하지만 Random search는 범위 내에 있는 임의의 값에 대하여 예상치 못한 조합을 시도해볼 수 있다는 장점이 있습니다. 아래는 Grid searc h 탐색법과 Random search 탐색법을 비교할 수 있는 이미지입니다.

search

이미지 출처 : nanonets.com

이 3가지 탐색법외에도 베이지안 최적화(Bayesian optimization) 등 다양한 하이퍼파라미터 탐색법이 있습니다. 베이지안 최적화에 대한 자세한 정보는 수아랩(Sualab) 기술블로그에 잘 정리되어 있습니다.

Evaluation

지금부터는 검증(Validation)과 테스트(Test) 단계에서 어떤 지표를 가지고 모델을 평가할 수 있는 지에 대해서 알아보겠습니다.

Confusion Matrix

분류(Classification)에서 가장 많이 사용되는 오차 행렬(Confusion matrix)에 대해서 알아보겠습니다. 오차 행렬은 각 인스턴스의 실제 클래스와 예측 클래스의 개수를 행렬의 성분에 채워넣은 것입니다. 아래 오차 행렬에서는 각 열에 예측 클래스를, 각 행에 실제 클래스를 배치하고 있습니다. (배치는 그리는 사람에 따라 달라질 수 있습니다)

CM

이미지 출처 : manisha-sirsat.blogspot.com

오차 행렬은 2행 2열로 구성되므로 총 4개의 성분이 있습니다. 위 오차 행렬에서 1행 1열의 성분은 True Positive(TP)이며 실제 Positive인 클래스를 Positive로 예측한 인스턴스의 개수를 나타냅니다. 1행 2열의 성분은 False Negative(FN)이며 실제 Positive인 클래스를 Negative로 예측한 인스턴스의 개수를 나타냅니다. 이 때 모델이 잘못 판단한 경우를 Type II Error라고 합니다. 2행 1열의 성분은 False Positive(FP)이며 실제 Negative인 클래스를 Positive로 예측한 인스턴스의 개수를 나타냅니다. 이 때 모델이 잘못 판단한 경우는 Type I Error라고 합니다. 마지막으로 2행 2열의 성분은 True Negative(TN)이며 실제 Negative인 클래스를 Negative로 판단한 인스턴스의 개수를 나타냅니다.

각 이름에 대해서는 “(클래스)로 예측해서 (맞은/틀린) 케이스”으로 기억하면 쉽게 기억할 수 있습니다. 예를 들어, False Positive의 경우는 “(Positive)로 예측해서 (틀린) 케이스”, True Negative는 “(Negative)로 예측해서 (맞은) 케이스” 라고 생각하면 됩니다.

스팸 메일 분류의 예를 들어 보겠습니다. 정상적인 메일을 Negative클래스, 스팸 메일을 Positive클래스라고 하면 TP는 스팸 메일을 스팸 메일로 분류한 경우, FN은 스팸 메일을 정상 메일로 분류한 경우입니다. FP는 정상 메일을 스팸 메일로 분류한 경우이며 TN은 정상적인 메일을 정상 메일로 분류한 경우입니다. 다음은 이 4개의 성분(TP, FN, FP, TN)을 활용한 정확도와 정밀도 및 재현율에 대해 알아보겠습니다.

Accuracy, Precision, Recall

가장 일반적으로 사용되는 것은 정확도(Accuracy)입니다. 정확도는 전체 데이터 중 제대로 판별한(True) 데이터의 비율로, 수치는 다음 수식을 사용하여 구할 수 있습니다.

[\text{Accuracy} = \frac{\text{TP+TN}}{\text{TP + TN + FP + FN}}]

데이터셋에서 클래스 비율이 한쪽으로 치우쳐진 경우에는 정확도가 모델의 성능을 제대로 표현하지 못하는 경우도 있습니다. 이런 경우에 대해서는 이후 예시를 통해 알아보겠습니다. 이렇게 정확도가 모델의 제 성능을 표현하지 못하는 경우에는 정밀도와 재현율을 사용합니다. 정밀도(Precision)는 Positive로 예측한 인스턴스 중에 제대로 판별한 비율을 나타냅니다. 재현율(Recall)은 실제 클래스가 Positive인 인스턴스를 얼마나 많이 골라냈는지를 나타내는 수치이며 민감도(Sensitivity)라는 말로도 표현합니다.

[\begin{aligned} \text{Precision} &= \frac{\text{TP}}{\text{TP + FP}}
\text{Recall} &= \frac{\text{TP}}{\text{TP + FN}} \end{aligned}]

위에서 사용했던 스팸 메일의 예를 들어 3개의 수치가 구해지는 과정을 알아보겠습니다. 아래는 총 1000통의 메일 중 스팸메일과 정상 메일을 분류한 예시입니다.

행(실제)/열(예측) Positive Negative Metric
Positive 5(TP) 45(FN) 0.1(Recall)
Negative 20(FP) 930(TN)  
Metric 0.2(Precision)   0.935(Accuracy)

위 표에서는 1000통의 메일 중 정상인 메일을 정상으로, 스팸인 메일을 스팸으로 판별한 건수는 각각 930건, 5건입니다. 1000통의 메일 중 정확하게 분류한 메일이 935통이므로 정확도는 $0.935$ 라고 할 수 있습니다. 93% 이상으로 정확하게 분류했지만 이 분류기를 좋은 분류기라고 할 수 있을까요? 오차 행렬을 다시 보면 이 모델이 얼마나 형편 없는(?) 분류기인지를 알 수 있습니다.

일단, 총 50개밖에 없는 스팸 메일 중에 무려 45통이 받은 메일함에 와있는 것을 볼 수 있습니다. 그리고 정상 메일 중 20개는 스팸 메일함에 가있어서 보지 못할 수도 있지요. 이럴 때 빛을 발하는 수치가 정밀도와 재현율입니다. 위 오차 행렬을 바탕으로 구한 분류기의 정밀도와 재현율은 다음과 같습니다.

[\begin{aligned} \text{Precision} &= \frac{5}{5+20} = \frac{1}{5} = 0.2
\text{Recall} &= \frac{5}{5+45} = \frac{1}{10} = 0.1 \end{aligned}]

정확도는 0.935라는 높은 수치가 나왔지만 Precision과 Recall은 이 분류기가 얼마나 성능이 떨어지는 지를 잘 보여주고 있습니다.

Precision-Recall Trade-off

어떤 것을 분류하느냐에 따라서 정밀도가 더 중요할 때도 있고, 재현율이 더 중요할 때도 있습니다. 위 스팸 메일 분류의 예시를 다시 가져와 보겠습니다. 위 분류기가 45개의 스팸 메일을 받은 편지함에 두었지만 사실 이런 것들은 손으로 직접 지워주면 됩니다. 단지 조금 귀찮을 뿐입니다. 하지만 스팸 메일함에 들어간 20개의 메일 중에서 면접 날짜나 비즈니스 미팅 날짜 확정처럼 중요한 메일이 있다고 해봅시다. 이용자는 이런 메일을 하나라도 못보면 큰일나게 됩니다. 그렇기 때문에 스팸 메일을 분류하는 분류기는 FP를 줄이는 것, 즉 정밀도를 더 중요하게 생각해야 합니다.

다른 예시로 암 환자의 X-ray 사진을 보고 분류하여 Positive이면 정밀 진단을 하고, Negative이면 무증상으로 분류하는 분류기를 만든다고 해봅시다. 이런 경우에는 어떤 수치가 더 중요해질까요? 이 분류기에서 FP로 분류된 인스턴스, 즉 암 환자가 아니지만 환자로 분류된 경우는 추후 정밀 검사를 통해서 다시 검사하면 됩니다. 하지만 FN으로 분류된 인스턴스, 즉 암 환자이지만 무증상으로 분류하면 큰일나게 됩니다. 그렇기 때문에 이런 경우는 FN를 줄이는 것, 즉 재현율을 더 중요하게 생각해야 합니다.

하지만 한 수치를 중요하게 생각하면 한 수치는 더 떨어지기 마련입니다. 예를 들어, Positive로 판별하는 기준을 빡빡하게 잡으면 정밀도가 높아집니다. 반대로 기준을 널널하게 잡으면 재현율이 늘어나게 됩니다. 스팸 메일 분류의 경우 기준을 빡빡하게 설정해서 스팸 메일로 분류되는 정상 메일이 없도록 해야하고, 암 환자 판별의 경우 기준을 널널하게 해서 정상으로 판별되는 환자가 없도록 해야 합니다.

이 수치를 설정하는 것이 바로 임계값(Threshold)입니다. 임계값을 크게 설정하면 정밀도가 올라가게 되고 작게 설정하면 재현율이 올라가게 되지요. 이런 현상을 정밀도-재현율 트레이드 오프(Precision-Recall Trade-off)라고 합니다. 어떤 분류기의 임계값에 따른 정밀도와 재현율을 그래프로 나타내면 다음과 같은 그림이 나오게 됩니다.

tradeoff

이미지 출처 : machinelearningaptitude.com

위 그래프 외에 재현율-정밀도 그래프를 그려 적당한 지점을 판단하기도 합니다. 아래는 재현율-정밀도 그래프의 예시입니다.

pre_vs_rec

이미지 출처 : sanyamkapoor.com

F-Score

F-score(F-measure)는 정밀도와 재현율 수치를 한 번에 보기 위해서 만들어진 수치입니다. 가장 일반적으로 사용되는 수치는 $F_1 \text{-score}$ 입니다. 이 수치는 정밀도와 재현율의 조화평균으로 정리하면 아래와 같은 수식으로 나타낼 수 있습니다.

[F_1 \text{-Score} = \frac{2 \times \text{Precision} \times \text{Recall}}{\text{Precision} + \text{Recall}}]

위 스팸 메일 분류기나 암 환자 판별기처럼 특정 수치가 부각되어야 할 때는 $F_1 \text{-score}$ 를 일반화한 $F_\beta \text{-score}$ 를 사용합니다. 가중치 $\beta$ 를 처리해준 것으로 정밀도가 강조되어야 할 때는 $\beta < 1$ [Ex) $F_{0.5} \text{-score}$]을 사용하고, 재현율이 강조되어야 할 때는 $\beta > 1$ [Ex) $F_2 \text{-score}$] 을 사용합니다. $F_\beta \text{-score}$ 의 수식은 아래와 같습니다.

[F_\beta \text{-Score} = \frac{(1+\beta^2) \times \text{Precision} \times \text{Recall}}{\beta^2 \times \text{Precision} + \text{Recall}}]

ROC Curve, AUC

분류 모델 성능 평가를 위해서 AUC(Area Under Curve) 역시 많이 사용됩니다. AUC는 말 뜻 그대로, ROC 곡선 아래의 넓이를 나타냅니다. 그렇기 때문에 AUC를 알아보기 위해서 ROC 곡선이 무엇인지 알아보겠습니다.

ROC 곡선(Receiver Operation Characteristic Curve)은 2차대전 때 통신 장비의 성능을 평가하기 위해서 나온 수치입니다. ROC곡선은 FPR(False Positive rate)을 X축으로 TPR(True Positive rate)의 그래프입니다. FPR과 TPR은 오차 행렬 내 4개의 요소를 사용한 수치이며 . 각 수치는 다음과 같이 구해집니다.

[\begin{aligned} \text{FPR} &= \frac{\text{FP}}{\text{FP+TN}}
\text{TPR} &= \frac{\text{TP}}{\text{TP+FN}} = \text{Recall} \end{aligned}]

FPR은 실제 Negative 클래스인 인스턴스를 얼마나 잘못 분류했는지를 나타내는 수치입니다. 그리고 TPR, 즉 재현율은 실제 Positive인 클래스인 인스턴스를 얼마나 제대로 분류했는 지를 나타내는 수치입니다.

위에서 사용했던 스팸 메일의 예를 사용해 FPR과 TPR이 어떻게 구해지는지 알아보겠습니다.

행(실제)/열(예측) Positive Negative Metric
Positive 5(TP) 45(FN) 0.1(TPR)
Negative 20(FP) 930(TN) 0.02(FPR)

[\begin{aligned} \text{FPR} &= \frac{20}{20+930} \simeq 0.02
\text{TPR} &= \frac{5}{5+45} = 0.1 \end{aligned}]

임계값(Threshold)을 변화시키면 FPR이 변하게 됩니다. 임계값을 매우 높게 하면 Positive로 판단하는 기준이 깐깐해지기 때문에 FP가 0이 되어 FPR이 0이 됩니다. 반대로 임계값을 매우 낮게 하면 Positive로 판단하는 기준이 낮아지기 때문에 TN이 0이 되어 FPR이 1이 됩니다. 이렇게 임계값에 따라 FPR을 0부터 1까지 변화시켜가며 그에 따라 TPR이 어떻게 변화하는지를 기록한 것이 ROC 곡선입니다. 아래는 ROC 곡선의 예시입니다.

roc_curve

이미지 출처 : machinelearningmastery.com

낮은 FPR, 즉 임계값이 높을 때에는 성능이 좋은 분류기에서만 높은 TPR이 나오게 됩니다. 임계값이 낮아지면 어떤 분류기라도 TRP이 높아지게 되므로 FPR이 증가함에 따라 TPR은 점점 1에 가까워지게 됩니다. 이렇게 그려진 ROC 곡선의 아랫부분의 면적을 구한 것이 AUC입니다. 그래서 더 좋은 분류기는 더 높은 AUC를 가지게 되지요. 아래는 여러 분류기의 ROC커브와 AUC를 비교한 것입니다. 완전 랜덤한 분류기는 붉은 점선과 같이 ROC곡선이 그려지기 때문에 AUC가 0이 되고, 완벽한 분류기는 언제나 TPR이 1이 되므로 AUC도 1이 되는 것을 볼 수 있습니다.

auc

이미지 출처 : glassboxmedicine.com

좋은 평가방법이란?

머신러닝에 “공짜 점심은 없다”라는 말이 있습니다. 모든 상황에 최적화된 모델은 없다는 이야기지요. 어떤 데이터에서는 좋았던 알고리즘이 다른 데이터로 가면 성능이 떨어지는 일은 부지기수입니다. 평가방법 역시 그러합니다. AUC나 $F_1\text{-score}$ 처럼 범용적으로 사용되는 수치는 있으나 수치가 높았던 모델이 실제 데이터에서 어떤 작용을 할 지는 알 수 없습니다. 그렇기 때문에 많은 수치를 측정해보고 가장 적정한 평가방법이나 평균적으로 높게 평가되는 모델을 찾아서 하는 것이 좋은 방법이 되겠습니다.

Comment  Read more