TF-IDF 설명회

sunmkim·2022년 4월 17일
0
post-thumbnail

작성중인 게시물입니다. 4/17

🐭 Tf (term frequency)

TF란? 문서 안에서 한 단어가 얼마나 중요한지를 수치적으로 나타낸 가중치이다.
자연어 처리에서 정보수집, 텍스트 마이닝 및 유저 모델링의 가중치 계산에 자주 사용된다.
유저가 "큰 사과"를 검색했다고하자. 가장 먼저 "큰"과 "사과"를 포함한 문서를 추려낸다.
그 뒤에 각 문서에서 "큰" "사과"가 몇번씩 등장하는지 빈도를 계산한다. 이 값이 TF이다.
이 때 문장의 길이가 길 수록 단어가 많으니 큰,사과 가 더 자주 등장할 것이라 예상할 수 있으므로 빈도를 정규화 할 필요가 생긴다.

def computeTF(wordDic, bagOfWords):
	tfDict = {}
    bagOfWordsCount = len(bagOfWords):
    for word, count in wordDict.items()
    	tfDict[word] = count / float(bagOfWordsCount)
    return tfDict
        	

🐈 IDF (Inverse Document Frequency)

"큰 사과" 라는 단어에서 "큰"과 "사과"의 빈도를 계산하면 "큰"이 더 많을 것으로 예상할 수 있으며, 단순히 tf를 기준으로 순위를 계산한다면 "큰"이 많은 문서가 상위에 랭크될 가능성이 높다. 그러나 이는 무의미한 키워드이며,
사용자가 원하는 것은 "사과"이다. 이때 IDF를 도입하는데, 이는 전체 문서에서 특정 단어가 자주 언급될 수록 작아지고 적게 언급될수록 커진다.

def computeIDF(documents):
    import math
    N = len(documents)
    
    idfDict = {}
    for doc in documents:
        for word, val in doc.items():
            if val > 0:
                idfDict[word] = idfDict.get(word, 0) + 1
    
    for word, val in idfDict.items():
        idfDict[word] = math.log(N / float(val))
    return idfDict

🦍 TF - IDF

TF 와 IDF의 곱
여러가지 조합이 있다.

def computeTFIDF(tfBagOfWords, idfs):
	tfidf = {}
    for word, val in tfBagOfWords.items():
    	tfidf[word] = idfs[word] * val
    return tfidf

🦈 Example

빅뱅의 봄여름가을겨울

import os
import string
import math
import pandas as pd

# 모듈 선언

cwd = os.getcwd()

with open(f'{cwd}/fourseason.txt') as f:
    test_set = f.read().splitlines() 
docs = test_set

for doc in docs:
    print(doc)
    
이듬해 질 녘 꽃 피는 봄 한여름 밤의 꿈
가을 타 겨울 내릴 눈 1년 네 번 또다시 봄
정들었던 내 젊은 날 이제는 안녕
아름답던 우리의 봄 여름 가을 겨울
'Four seasons with no reason'
비 갠 뒤에 비애(悲哀) 대신 a happy end
비스듬히 씩 비웃듯 칠색 무늬의 무지개
철없이 철 지나 철들지 못해(still)
철부지에 철 그른지 오래, Marchin' 비발디
차이코프스키, 오늘의 사계를 맞이해
마침내, 마치 넷이 못내
Boy 저 하늘만 바라보고서
사계절 잘 지내고 있어 Good-bye
떠난 사람 또 나타난 사람
머리 위 저세상
난 떠나 영감의 amazon
지난 밤의 트라우마 다 묻고
목숨 바쳐 달려올 새 출발 하는 왕복선
변할래 전보다는 더욱더
좋은 사람 더욱더
더 나은 사람 더욱더
아침 이슬을 맞고 내 안에 분노 과거에 묻고
For Life
울었던 웃었던 소년과 소녀가 그리워 나
찬란했던 사랑했던 그 시절만 자꾸 기억나
계절은 날이 갈수록 속절없이 흘러
붉게 물들이고 파랗게 멍들어 가슴을 훑고
언젠가 다시 올 그 날
그때를 위하여 (그대를 위하여)
아름다울 우리의 봄 여름 가을 겨울
La la la la la la la la la la la
La la la la la la la la la la la
La la la la la la la la la la la
La la la la la la la la la la la
이듬해 질 녘 꽃 피는 봄 한여름 밤의 꿈
가을 타 겨울 내린 눈 봄 여름 가을 겨울

TF

def computeTF(wordDict, bagOfWords):
    tfDict = {}
    bagOfWordsCount = len(bagOfWords)
    for word, count in wordDict.items():
        tfDict[word] = count / float(bagOfWordsCount)
    return tfDict

docTfList = []
numOfWordsList = []

for doc in docs:
    bagOfDocs = doc.split(' ')
    numOfWords = {}
    for word in bagOfDocs:
        numOfWords[word] = numOfWords.get(word, 0) + 1
    docTF = computeTF(numOfWords, bagOfDocs)
    docTfList.append(docTF)
    numOfWordsList.append(numOfWords)

결과

for doc in docTfList:
    print(doc)
    
{'이듬해': 0.1111111111111111, '질': 0.1111111111111111, '녘': 0.1111111111111111, '꽃': 0.1111111111111111, '피는': 0.1111111111111111, '봄': 0.1111111111111111, '한여름': 0.1111111111111111, '밤의': 0.1111111111111111, '꿈': 0.1111111111111111}
{'가을': 0.1, '타': 0.1, '겨울': 0.1, '내릴': 0.1, '눈': 0.1, '1년': 0.1, '네': 0.1, '번': 0.1, '또다시': 0.1, '봄': 0.1}
{'정들었던': 0.16666666666666666, '내': 0.16666666666666666, '젊은': 0.16666666666666666, '날': 0.16666666666666666, '이제는': 0.16666666666666666, '안녕': 0.16666666666666666}
{'아름답던': 0.16666666666666666, '우리의': 0.16666666666666666, '봄': 0.16666666666666666, '여름': 0.16666666666666666, '가을': 0.16666666666666666, '겨울': 0.16666666666666666}
{"'Four": 0.2, 'seasons': 0.2, 'with': 0.2, 'no': 0.2, "reason'": 0.2}
{'비': 0.125, '갠': 0.125, '뒤에': 0.125, '비애(悲哀)': 0.125, '대신': 0.125, 'a': 0.125, 'happy': 0.125, 'end': 0.125}
{'비스듬히': 0.16666666666666666, '씩': 0.16666666666666666, '비웃듯': 0.16666666666666666, '칠색': 0.16666666666666666, '무늬의': 0.16666666666666666, '무지개': 0.16666666666666666}
{'철없이': 0.2, '철': 0.2, '지나': 0.2, '철들지': 0.2, '못해(still)': 0.2}
{'철부지에': 0.16666666666666666, '철': 0.16666666666666666, '그른지': 0.16666666666666666, '오래,': 0.16666666666666666, "Marchin'": 0.16666666666666666, '비발디': 0.16666666666666666}
{'차이코프스키,': 0.25, '오늘의': 0.25, '사계를': 0.25, '맞이해': 0.25}
{'마침내,': 0.25, '마치': 0.25, '넷이': 0.25, '못내': 0.25}
{'Boy': 0.25, '저': 0.25, '하늘만': 0.25, '바라보고서': 0.25}
{'사계절': 0.2, '잘': 0.2, '지내고': 0.2, '있어': 0.2, 'Good-bye': 0.2}
{'떠난': 0.2, '사람': 0.4, '또': 0.2, '나타난': 0.2}
{'머리': 0.3333333333333333, '위': 0.3333333333333333, '저세상': 0.3333333333333333}
{'난': 0.25, '떠나': 0.25, '영감의': 0.25, 'amazon': 0.25}
{'지난': 0.2, '밤의': 0.2, '트라우마': 0.2, '다': 0.2, '묻고': 0.2}
{'목숨': 0.14285714285714285, '바쳐': 0.14285714285714285, '달려올': 0.14285714285714285, '새': 0.14285714285714285, '출발': 0.14285714285714285, '하는': 0.14285714285714285, '왕복선': 0.14285714285714285}
{'변할래': 0.3333333333333333, '전보다는': 0.3333333333333333, '더욱더': 0.3333333333333333}
{'좋은': 0.3333333333333333, '사람': 0.3333333333333333, '더욱더': 0.3333333333333333}
{'더': 0.25, '나은': 0.25, '사람': 0.25, '더욱더': 0.25}
{'아침': 0.125, '이슬을': 0.125, '맞고': 0.125, '내': 0.125, '안에': 0.125, '분노': 0.125, '과거에': 0.125, '묻고': 0.125}
{'For': 0.5, 'Life': 0.5}
{'울었던': 0.16666666666666666, '웃었던': 0.16666666666666666, '소년과': 0.16666666666666666, '소녀가': 0.16666666666666666, '그리워': 0.16666666666666666, '나': 0.16666666666666666}
{'찬란했던': 0.16666666666666666, '사랑했던': 0.16666666666666666, '그': 0.16666666666666666, '시절만': 0.16666666666666666, '자꾸': 0.16666666666666666, '기억나': 0.16666666666666666}
{'계절은': 0.2, '날이': 0.2, '갈수록': 0.2, '속절없이': 0.2, '흘러': 0.2}
{'붉게': 0.16666666666666666, '물들이고': 0.16666666666666666, '파랗게': 0.16666666666666666, '멍들어': 0.16666666666666666, '가슴을': 0.16666666666666666, '훑고': 0.16666666666666666}
{'언젠가': 0.2, '다시': 0.2, '올': 0.2, '그': 0.2, '날': 0.2}
{'그때를': 0.25, '위하여': 0.25, '(그대를': 0.25, '위하여)': 0.25}
{'아름다울': 0.16666666666666666, '우리의': 0.16666666666666666, '봄': 0.16666666666666666, '여름': 0.16666666666666666, '가을': 0.16666666666666666, '겨울': 0.16666666666666666}
{'La': 0.09090909090909091, 'la': 0.9090909090909091}
{'La': 0.09090909090909091, 'la': 0.9090909090909091}
{'La': 0.09090909090909091, 'la': 0.9090909090909091}
{'La': 0.09090909090909091, 'la': 0.9090909090909091}
{'이듬해': 0.1111111111111111, '질': 0.1111111111111111, '녘': 0.1111111111111111, '꽃': 0.1111111111111111, '피는': 0.1111111111111111, '봄': 0.1111111111111111, '한여름': 0.1111111111111111, '밤의': 0.1111111111111111, '꿈': 0.1111111111111111}
{'가을': 0.2222222222222222, '타': 0.1111111111111111, '겨울': 0.2222222222222222, '내린': 0.1111111111111111, '눈': 0.1111111111111111, '봄': 0.1111111111111111, '여름': 0.1111111111111111}

IDF

def computeIDF(documents):
    import math
    N = len(documents)
    
    idfDict = {}
    for doc in documents:
        for word, val in doc.items():
            if val > 0:
                idfDict[word] = idfDict.get(word, 0) + 1
    
    for word, val in idfDict.items():
        idfDict[word] = math.log(N / float(val))
    return idfDict


idfs = computeIDF(numOfWordsList)
print(idfs)
{'이듬해': 2.8903717578961645, '질': 2.8903717578961645, '녘': 2.8903717578961645, '꽃': 2.8903717578961645, '피는': 2.8903717578961645, '봄': 1.791759469228055, '한여름': 2.8903717578961645, '밤의': 2.4849066497880004, '꿈': 2.8903717578961645, '가을': 2.1972245773362196, '타': 2.8903717578961645, '겨울': 2.1972245773362196, '내릴': 3.58351893845611, '눈': 2.8903717578961645, '1년': 3.58351893845611, '네': 3.58351893845611, '번': 3.58351893845611, '또다시': 3.58351893845611, '정들었던': 3.58351893845611, '내': 2.8903717578961645, '젊은': 3.58351893845611, '날': 2.8903717578961645, '이제는': 3.58351893845611, '안녕': 3.58351893845611, '아름답던': 3.58351893845611, '우리의': 2.8903717578961645, '여름': 2.4849066497880004, "'Four": 3.58351893845611, 'seasons': 3.58351893845611, 'with': 3.58351893845611, 'no': 3.58351893845611, "reason'": 3.58351893845611, '비': 3.58351893845611, '갠': 3.58351893845611, '뒤에': 3.58351893845611, '비애(悲哀)': 3.58351893845611, '대신': 3.58351893845611, 'a': 3.58351893845611, 'happy': 3.58351893845611, 'end': 3.58351893845611, '비스듬히': 3.58351893845611, '씩': 3.58351893845611, '비웃듯': 3.58351893845611, '칠색': 3.58351893845611, '무늬의': 3.58351893845611, '무지개': 3.58351893845611, '철없이': 3.58351893845611, '철': 2.8903717578961645, '지나': 3.58351893845611, '철들지': 3.58351893845611, '못해(still)': 3.58351893845611, '철부지에': 3.58351893845611, '그른지': 3.58351893845611, '오래,': 3.58351893845611, "Marchin'": 3.58351893845611, '비발디': 3.58351893845611, '차이코프스키,': 3.58351893845611, '오늘의': 3.58351893845611, '사계를': 3.58351893845611, '맞이해': 3.58351893845611, '마침내,': 3.58351893845611, '마치': 3.58351893845611, '넷이': 3.58351893845611, '못내': 3.58351893845611, 'Boy': 3.58351893845611, '저': 3.58351893845611, '하늘만': 3.58351893845611, '바라보고서': 3.58351893845611, '사계절': 3.58351893845611, '잘': 3.58351893845611, '지내고': 3.58351893845611, '있어': 3.58351893845611, 'Good-bye': 3.58351893845611, '떠난': 3.58351893845611, '사람': 2.4849066497880004, '또': 3.58351893845611, '나타난': 3.58351893845611, '머리': 3.58351893845611, '위': 3.58351893845611, '저세상': 3.58351893845611, '난': 3.58351893845611, '떠나': 3.58351893845611, '영감의': 3.58351893845611, 'amazon': 3.58351893845611, '지난': 3.58351893845611, '트라우마': 3.58351893845611, '다': 3.58351893845611, '묻고': 2.8903717578961645, '목숨': 3.58351893845611, '바쳐': 3.58351893845611, '달려올': 3.58351893845611, '새': 3.58351893845611, '출발': 3.58351893845611, '하는': 3.58351893845611, '왕복선': 3.58351893845611, '변할래': 3.58351893845611, '전보다는': 3.58351893845611, '더욱더': 2.4849066497880004, '좋은': 3.58351893845611, '더': 3.58351893845611, '나은': 3.58351893845611, '아침': 3.58351893845611, '이슬을': 3.58351893845611, '맞고': 3.58351893845611, '안에': 3.58351893845611, '분노': 3.58351893845611, '과거에': 3.58351893845611, 'For': 3.58351893845611, 'Life': 3.58351893845611, '울었던': 3.58351893845611, '웃었던': 3.58351893845611, '소년과': 3.58351893845611, '소녀가': 3.58351893845611, '그리워': 3.58351893845611, '나': 3.58351893845611, '찬란했던': 3.58351893845611, '사랑했던': 3.58351893845611, '그': 2.8903717578961645, '시절만': 3.58351893845611, '자꾸': 3.58351893845611, '기억나': 3.58351893845611, '계절은': 3.58351893845611, '날이': 3.58351893845611, '갈수록': 3.58351893845611, '속절없이': 3.58351893845611, '흘러': 3.58351893845611, '붉게': 3.58351893845611, '물들이고': 3.58351893845611, '파랗게': 3.58351893845611, '멍들어': 3.58351893845611, '가슴을': 3.58351893845611, '훑고': 3.58351893845611, '언젠가': 3.58351893845611, '다시': 3.58351893845611, '올': 3.58351893845611, '그때를': 3.58351893845611, '위하여': 3.58351893845611, '(그대를': 3.58351893845611, '위하여)': 3.58351893845611, '아름다울': 3.58351893845611, 'La': 2.1972245773362196, 'la': 2.1972245773362196, '내린': 3.58351893845611}

TF IDF

import pandas as pd
def computeTFIDF(tfBagOfWords, idfs):
    tfidf = {}
    for word, val in tfBagOfWords.items():
        tfidf[word] = idfs[word] * val
    return tfidf

result = []

for doc in docs:
    bagOfDocs = doc.split(' ')
    numOfWords = {}
    for word in bagOfDocs:
        numOfWords[word] = numOfWords.get(word, 0) + 1
    docTF = computeTF(numOfWords, bagOfDocs)
    
    tfidfDoc = computeTFIDF(docTF, idfs)
    result.append(tfidfDoc)

df = pd.DataFrame(result)
    

결과

	이듬해	질	녘	꽃	피는	봄	한여름	밤의	꿈	가을	...	다시	올	그때를	위하여	(그대를	위하여)	아름다울	La	la	내린
0	0.321152	0.321152	0.321152	0.321152	0.321152	0.199084	0.321152	0.276101	0.321152	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
1	NaN	NaN	NaN	NaN	NaN	0.179176	NaN	NaN	NaN	0.219722	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
2	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
3	NaN	NaN	NaN	NaN	NaN	0.298627	NaN	NaN	NaN	0.366204	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
4	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
5	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
6	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
7	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
8	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
9	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
10	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
11	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
12	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
13	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
14	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
15	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
16	NaN	NaN	NaN	NaN	NaN	NaN	NaN	0.496981	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
17	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
18	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
19	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
20	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
21	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
22	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
23	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
24	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
25	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
26	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
27	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	0.716704	0.716704	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
28	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	0.89588	0.89588	0.89588	0.89588	NaN	NaN	NaN	NaN
29	NaN	NaN	NaN	NaN	NaN	0.298627	NaN	NaN	NaN	0.366204	...	NaN	NaN	NaN	NaN	NaN	NaN	0.597253	NaN	NaN	NaN
30	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	0.199748	1.997477	NaN
31	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	0.199748	1.997477	NaN
32	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	0.199748	1.997477	NaN
33	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	0.199748	1.997477	NaN
34	0.321152	0.321152	0.321152	0.321152	0.321152	0.199084	0.321152	0.276101	0.321152	NaN	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN
35	NaN	NaN	NaN	NaN	NaN	0.199084	NaN	NaN	NaN	0.488272	...	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	NaN	0.398169
36 rows × 143 columns

github https://github.com/BGM-109/tf-idf-example

profile
파이토치하이

0개의 댓글