반응형

1. TF-IDF 기본 이해

 TF-IDF(Term Frequency-Inverse Document Frequency)는 여러 문서 군이 있을 때 어떤 단어가 특정 문서 내에서 얼마나 중요한지를 나타내는 수치이다. 1) 문서의 핵심어를 추출하거나, 2) 검색 엔진에서 검색 결과의 순위를 결정하거나, 3) 문서들 사이의 비슷한 정도를 구하는 등에 사용 가능하다.

 TF-IDF는 특정 문서에서만 자주 등장하는 단어가 그 문서에서 중요도가 높다고 판단하지만, 그 단어가 모든 문서에서 자주 등장할 경우 중요도를 낮추는 방법이다. TF-IDF는 다음 식으로 구성된다.

 여기에서 t는 단어, d는 특정 문서, D는 모든 문서를 지칭한다. tf(t,d)는 그 특정 문서에서 t가 나타나는 빈도이다.

 

[TF 계산식]

 f(t,d)를 문서 d에서 단어 t의 총 빈도라고 하면, tf(t,d)는 다음과 같이 산출 가능하다. 

  • Binary : 0 (t가 d에 한번이라도 나타나는 경우), 1 (t가 한번도 나타나지 않는 경우)
  • Raw Count : f(t,d)
  • Term Frequency : 문서의 길이를 고려해서 조정한 값
  • logarithmically scaled : tf(t,d)=log(f(t,d)+1)
  • 증가 빈도 :  문서내 단어 빈도가 최고인 값을  나누어주는 방법으로, 일반적으로 문서의 길이가 상대적으로 긴 경우, 단어 빈도값을 조절하기 위해서 사용된다. 다음은 그 식이다. (여기에서 K는 0.5)

  • logarithmicall average :

 활용에 따라 적정한 방법을 사용하면 된다. 

 

 

[IDF 계산식]

idf는 한 단어가 문서집합에서 얼마나 공통적으로 들어가 있는지를 나타내는 값이다. idf(t,D) 산출식은 다음과 같다.

  • Unary: 1
  • IDF: 전체 문서 수를 해당 단어가 포함된 문서 카운트로 나누어서 로그처리한 값이다.
  • IDF Smooth:
  • IDF Max: 문서수 대신에, 전체 문서수중에서 가장 많은 빈도를 가진 단어의 빈도를 분자로 대체한 것
  • pIDF(Probabilistic):

 

 어떤 단어가 특정 문서 내에서 빈도가 높을 수록, 그리고 전체 문서중 그 단어를 포함시키는 문서가 적을 수록, 즉 흔하지 않을 경우에 TF-IDF값이 높아지고 TF-IDF값이 높으면 그 단어는 해당 문서에 중요하다는 뜻이 된다.

 

2. TF-IDF 구현하기

[Vocabulary 리스트 만들기]

TF-IDF를 구하기 해서는 Term List, 즉 Vocabulary List를 사전에 만들어야 한다. 여러 문서들에서 단어를 토크나이징 하는 것은 sentencepiece와 같은 툴을 사용하면 된다. (자세한 방법은 https://wikidocs.net/86657, https://paul-hyun.github.io/vocab-with-sentencepiece/ 를 참고하면 되겠다.) SentencePiece를 이용하면 학습한 모델을 가지고, 특정 텍스트 입력에 대해서 단어와 단어id를 encoding 해준다. 예를 들면 다음과 같다.

>>>import sentencepiece as spm
>>>sp=spm.SentencePieceProcessor()

>>> sp.load('naver.model')
True
>>>sp.encode_as_pieces('인터넷은 생활을 편리하게 해줍니다')
['▁인터넷은', '▁생', '활', '을', '▁편', '리', '하게', '▁해', '줍', '니다']
>>>sp.encode_as_ids('인터넷은 생활을 편리하게 해줍니다')
[3222, 473, 7506, 7188, 1473, 7169, 249, 9, 0, 241]
>>>sp.PieceToId('▁인터넷은')
3222
>>>sp.id_to_piece(473)
'▁생'

이후 포스팅 내용들은 sentencepiece의 vocab모델로 tf-idf를 구현하는 것을 설명하도록 하겠다.

 

[TF 구하기]

우선 DTM(Document-Term Matrix)를 구한다. 단어 사전이 |w| 이고 Document Size가 |D| 라고 한다면 TF-IDF는 다음과 같은 |w|X|D|의 2차원 매트릭스가 된다. 

 앞의 sentencepiece 와 같이 단어가 임베딩 되어 있는 상태 (즉 0부터 |w|-1까지)라고 하면 Document는 임베딩 단어의 리스트가 된다.

앞의 예 "인터넷은 생활을 편리하게 해줍니다"는 [3222, 473, 7506, 7188, 1473, 7169, 249, 9, 0, 241] 라는 리스트로 표현된다. TF를 Term-Frequency방식을 사용할 경우 TFM(Term-Frequency Matrix)은 다음과 같이 구할 수 있다.

 sp는 sentencepiece의 SentencePieceProcessor()로 생성하고 모델을 로드한 것이다. idLists에서는 문서 텍스트를 sp.encode_as_ids를 통해서 단어 인텍스로 구성된 리스트를 저장하게 된다. 그리고 해당 숫자들에 대해서 dictionary형태로 카운트 하고 rr이라는 배열의 해당 포지션에 문장의 term 숫자를 나눠서 저장한다.

 

[TF-IDF구하기]

 우선 IDF를 구하기 위한  각 vocab가 언급된 문서 수를 카운트 한다. 단어 사전이 |w|라면 |w| 만큼의 리스트에 각 vocab가 document에 언급된 경우 +1 해서 저장한다. 위의 코드에 dfResults부분을 추가한다.

 이후 앞서 구한 TF-Matrix에서 각 문서의 Term Index를 이용하여 해당 문서-단어의 TF-Matrix값을 이용해서 TF-IDF를 계산한다.

3. 문장유사도 구하기

tfidf를 다음과 같이 함수로 정의 한다. 이 함수는 sentencepiece의 vocab model, 문서 list를 받아서 tfidf행렬을 넘겨주는 함수이다.

이 함수로 문장의 유사도를 구해보도록 하겠다. tf-idf에서 문장의 열을 보면 단어벡터임을 알 수 있다. 따라서 두 문장의 벡터의 유사도를 비고해 보면 해당 문장의 유사도를 비교해 볼 수 있다. 다음은 두 리스트를 받아서 해당 리스트의 cosine 유사도를 넘겨주는 함수이다.

 다음은 3문장에 대해서 테스트해본 코드이다.

>>> documents=['인터넷은 우리 생활을 바꾸었습니다. 인터넷이 없는 세상은 생각하기 어렵습니다.','인터넷 중독에 빠진 학생들이 많이 있습니다. 이 학생들의 학업을 개선할 방법이 필요합니다','학생들이 해야 할 일은 학교 생활에 충실하고 학업에 매진하는 것입니다']
>>> cos_sim(tfidfMatrix[0],tfidfMatrix[1])
0.0723788595137935
>>> cos_sim(tfidfMatrix[0],tfidfMatrix[2])
0.07964538450629796
>>> cos_sim(tfidfMatrix[1],tfidfMatrix[2])
0.2892311753237792

문서 0과 1 문서 0과 2는 크게 유사한 부분은 없어 보이고 문서 1,2는 이들보다는 유사하다고 나왔다. 이는 "인터넷은", "인터넷이","인터넷"이 서로 다른 단어처럼 인식되어서라고 볼 수 있다. 

>>> sp.encode_as_pieces(documents[0])
['▁인터넷은', '▁우리', '▁생', '활', '을', '▁바꾸', '었', '습니다', '.', '▁인터넷이', '▁없는', '▁세', '상', '은', '▁생각', '하기', '▁어렵', '습니다', '.']
>>> sp.encode_as_pieces(documents[1])
['▁인터넷', '▁중', '독', '에', '▁빠', '진', '▁학생', '들이', '▁많이', '▁있습니다', '.', '▁이', '▁학생', '들', '의', '▁학', '업', '을', '▁개선', '할', '▁방법이', '▁필요합니다']
>>> sp.encode_as_pieces(documents[2])
['▁학생', '들이', '▁해야', '▁할', '▁일', '은', '▁학교', '▁생', '활', '에', '▁충', '실', '하고', '▁학', '업', '에', '▁매', '진', '하는', '▁것', '입니다'

이는 형태소 분석기등을 활용해서 개선이 가능해 보이지만, 형태소 분석기도 모든 단어를 커버하지 못하기 때문에 한계가 있을수 있다. 데이터가 많아서 모든 경우를 커버해주기를 바라는 것도..

반응형
Posted by alias
,