특징어에 가중치를 부여하는 방법이 TF-IDF이다.
어떤 문서가 D개의 문장, N(전체 출현횟수, 단어종류아님)개의 단어로 구성되어 있을 때,
1. Term Frequency는 특정 단어 t가 문서안에서 얼마나 자주(n번) 나오는가를 나타내는 지표
2. Inverse Document Frequency는 특정 단어 t를 포함한 문장이 얼마나 자주(d번) 나오지 않는가를 나타내는 지표, 출현빈도가 낮을 수록 해당 단어의 IDF값이 커진다.
계산의 용이성을 위해 상용로그를 사용했을 뿐 log의 밑은 1보다 큰 임의의 실수면 된다.
3. TF-IDF는 TF와 IDF의 곱이다.
4. 예시
doc.txt
---------------------------------------------
해시계는 매우 단순한 장치다. 땅에 막대기 하나만 꽂으면 원시적 형태의 해시계가 뚝딱 완성된다. 북반구에서는 그림자가 시계방향으로 돈다. 이 그림자 위치를 따라가며 시간을 적당히 표시하면 된다. 그런데 막대를 꽂을 때, 천구의 북극을 향하도록 하거나 대충 북극성을 가리키게 기울이면 정확성이 한결 높아진다. 이렇게 하면 계절이 바뀌어도 그림자가 가리키는 시각이 달라지지 않는다. 가장 일반적인 해시계는 평평한 원판에 눈금이 표시된 것인데, 공원 같은 곳에서 쉽게 볼 수 있다. 이런 현태의 해시계는 그림자가 눈금판 주위를 도는 속도가 일정하지 않기 때문에 시간 표시 간격이 균일하지 않다. 해시계가 잘 맞지 않는 이유는 여러 가지이다. 지구의 공전 속도가 일정하지 않은 탓도 있고, 서머타임 제도 때문이기도 하다.
stop_word.txt
---------------------------------------------
.
는
이
가
하
#!/usr/bin/env python
# coding: utf-8
# In[164]:
import os
import math
import MeCab
mc = MeCab.Tagger("-Owakati")
# In[105]:
doc_lines = []
with open("doc.txt") as fh:
doc_lines = fh.read().replace(".", ".\n").split("\n")
# 형태소분석한 문장 저장
for i in range(len(doc_lines)) :
doc_lines[i] = doc_lines[i].strip()
doc_lines[i] = mc.parse(doc_lines[i]).replace("\n", "")
print(i, doc_lines[i])
# 마지막 공백라인 제거
if doc_lines[i] is "" :
doc_lines.remove(doc_lines[i])
0 해시계 는 매우 단순 한 장치 다 .
1 땅 에 막대기 하나 만 꽂 으면 원시 적 형태 의 해시계 가 뚝딱 완성 된다 .
2 북반구 에서 는 그림자 가 시계 방향 으로 돈다 .
3 이 그림자 위치 를 따라가 며 시간 을 적당히 표시 하 면 된다 .
4 그런데 막대 를 꽂 을 때 , 천구 의 북극 을 향하 도록 하 거나 대충 북극성 을 가리키 게 기울이 면 정확 성 이 한결 높 아 진다 .
5 이렇게 하 면 계절 이 바뀌 어도 그림자 가 가리키 는 시각 이 달라지 지 않 는다 .
6 가장 일반 적 인 해시계 는 평평 한 원판 에 눈금 이 표시 된 것 인데 , 공원 같 은 곳 에서 쉽 게 볼 수 있 다 .
7 이런 현태 의 해시계 는 그림자 가 눈금판 주위 를 도 는 속도 가 일정 하 지 않 기 때문 에 시간 표시 간격 이 균일 하 지 않 다 .
8 해시계 가 잘 맞 지 않 는 이유 는 여러 가지 이 다 .
9 지구 의 공전 속도 가 일정 하 지 않 은 탓 도 있 고 , 서머 타임 제도 때문 이 기 도 하 다 .
10
# In[189]:
# 단어별 사용횟수 저장
words_count = dict()
for line in doc_lines :
words = line.split()
for word in words :
words_count[word] = words_count.get(word, 0) + 1
# 전체단어출현횟수
total_word_count = 0
for k, v in words_count.items() :
total_word_count = total_word_count + v;
print("Total count : {}".format(total_word_count))
print("Word type count : {}".format(len(words_count)))
# 상위 5%는 stop word로 취급 커트라인 생성
freq_num = int(len(words_count) * 0.05)
print("freq num : {}".format(freq_num))
print()
# stop word 저장
stop_word = []
fh = open("stop_word.txt", "w")
# 가장많이 사용한 순으로 정렬
sorted_words_count = sorted(words_count.items(), key=lambda x:x[1], reverse=True)
for i in enumerate(sorted_words_count) :
#print(i)
print("{} : {} : {}".format(i[0], i[1][1], i[1][0]))
# 커트라인 이하는 stop word로 저장
if freq_num > i[0] :
stop_word.append(i[1][0])
fh.write("\n".join(stop_word))
fh.close()
Total count : 196
Word type count : 110
freq num : 5
0 : 10 : .
1 : 8 : 는
2 : 8 : 이
3 : 7 : 가
4 : 7 : 하
5 : 5 : 해시계
6 : 5 : 다
7 : 5 : 지
8 : 5 : 않
9 : 4 : 의
10 : 4 : 그림자
11 : 4 : 을
12 : 3 : 에
13 : 3 : 를
14 : 3 : 표시
15 : 3 : 면
16 : 3 : ,
17 : 3 : 도
18 : 2 : 한
19 : 2 : 꽂
20 : 2 : 적
21 : 2 : 된다
22 : 2 : 에서
23 : 2 : 시간
24 : 2 : 가리키
25 : 2 : 게
26 : 2 : 은
27 : 2 : 있
28 : 2 : 속도
29 : 2 : 일정
30 : 2 : 기
31 : 2 : 때문
32 : 1 : 매우
33 : 1 : 단순
34 : 1 : 장치
35 : 1 : 땅
36 : 1 : 막대기
37 : 1 : 하나
38 : 1 : 만
39 : 1 : 으면
40 : 1 : 원시
41 : 1 : 형태
42 : 1 : 뚝딱
43 : 1 : 완성
44 : 1 : 북반구
45 : 1 : 시계
46 : 1 : 방향
47 : 1 : 으로
48 : 1 : 돈다
49 : 1 : 위치
50 : 1 : 따라가
51 : 1 : 며
52 : 1 : 적당히
53 : 1 : 그런데
54 : 1 : 막대
55 : 1 : 때
56 : 1 : 천구
57 : 1 : 북극
58 : 1 : 향하
59 : 1 : 도록
60 : 1 : 거나
61 : 1 : 대충
62 : 1 : 북극성
63 : 1 : 기울이
64 : 1 : 정확
65 : 1 : 성
66 : 1 : 한결
67 : 1 : 높
68 : 1 : 아
69 : 1 : 진다
70 : 1 : 이렇게
71 : 1 : 계절
72 : 1 : 바뀌
73 : 1 : 어도
74 : 1 : 시각
75 : 1 : 달라지
76 : 1 : 는다
77 : 1 : 가장
78 : 1 : 일반
79 : 1 : 인
80 : 1 : 평평
81 : 1 : 원판
82 : 1 : 눈금
83 : 1 : 된
84 : 1 : 것
85 : 1 : 인데
86 : 1 : 공원
87 : 1 : 같
88 : 1 : 곳
89 : 1 : 쉽
90 : 1 : 볼
91 : 1 : 수
92 : 1 : 이런
93 : 1 : 현태
94 : 1 : 눈금판
95 : 1 : 주위
96 : 1 : 간격
97 : 1 : 균일
98 : 1 : 잘
99 : 1 : 맞
100 : 1 : 이유
101 : 1 : 여러
102 : 1 : 가지
103 : 1 : 지구
104 : 1 : 공전
105 : 1 : 탓
106 : 1 : 고
107 : 1 : 서머
108 : 1 : 타임
109 : 1 : 제도
# In[190]:
# 각 문장에 stop word 제거후 문장 반환
def remove_stopword(text) :
stop_word = []
with open("stop_word.txt") as f :
stop_word = f.read().split("\n")
line = []
for word in text.split() :
if word not in stop_word :
line.append(word)
return " ".join(line)
# stop word제거된 문장 list로 저장
clean_doc_lines = []
clean_words_count = {}
for line in doc_lines :
clean_line = remove_stopword(line)
print("before : {}".format(line))
print("after : {}".format(clean_line))
clean_doc_lines.append(clean_line)
print()
# stop word제거된 단어사용횟수 저장
for word in clean_line.split() :
clean_words_count[word] = clean_words_count.get(word, 0) + 1
before : 해시계 는 매우 단순 한 장치 다 .
after : 해시계 매우 단순 한 장치 다
before : 땅 에 막대기 하나 만 꽂 으면 원시 적 형태 의 해시계 가 뚝딱 완성 된다 .
after : 땅 에 막대기 하나 만 꽂 으면 원시 적 형태 의 해시계 뚝딱 완성 된다
before : 북반구 에서 는 그림자 가 시계 방향 으로 돈다 .
after : 북반구 에서 그림자 시계 방향 으로 돈다
before : 이 그림자 위치 를 따라가 며 시간 을 적당히 표시 하 면 된다 .
after : 그림자 위치 를 따라가 며 시간 을 적당히 표시 면 된다
before : 그런데 막대 를 꽂 을 때 , 천구 의 북극 을 향하 도록 하 거나 대충 북극성 을 가리키 게 기울이 면 정확 성 이 한결 높 아 진다 .
after : 그런데 막대 를 꽂 을 때 , 천구 의 북극 을 향하 도록 거나 대충 북극성 을 가리키 게 기울이 면 정확 성 한결 높 아 진다
before : 이렇게 하 면 계절 이 바뀌 어도 그림자 가 가리키 는 시각 이 달라지 지 않 는다 .
after : 이렇게 면 계절 바뀌 어도 그림자 가리키 시각 달라지 지 않 는다
before : 가장 일반 적 인 해시계 는 평평 한 원판 에 눈금 이 표시 된 것 인데 , 공원 같 은 곳 에서 쉽 게 볼 수 있 다 .
after : 가장 일반 적 인 해시계 평평 한 원판 에 눈금 표시 된 것 인데 , 공원 같 은 곳 에서 쉽 게 볼 수 있 다
before : 이런 현태 의 해시계 는 그림자 가 눈금판 주위 를 도 는 속도 가 일정 하 지 않 기 때문 에 시간 표시 간격 이 균일 하 지 않 다 .
after : 이런 현태 의 해시계 그림자 눈금판 주위 를 도 속도 일정 지 않 기 때문 에 시간 표시 간격 균일 지 않 다
before : 해시계 가 잘 맞 지 않 는 이유 는 여러 가지 이 다 .
after : 해시계 잘 맞 지 않 이유 여러 가지 다
before : 지구 의 공전 속도 가 일정 하 지 않 은 탓 도 있 고 , 서머 타임 제도 때문 이 기 도 하 다 .
after : 지구 의 공전 속도 일정 지 않 은 탓 도 있 고 , 서머 타임 제도 때문 기 도 다
# In[191]:
total_doc_count = len(clean_doc_lines)
total_word_count = 0
for k, v in clean_words_count.items() :
total_word_count = total_word_count + v;
print("Total doc count : {}".format(total_doc_count))
print("Total Word count : {}".format(total_word_count))
print()
sorted_words_count = sorted(clean_words_count.items(), key=lambda x:x[1], reverse=True)
for word, count in dict(sorted_words_count).items() :
tf = math.floor((count/total_word_count) * 1000) / 1000
doc_cnt = len([word for line in clean_doc_lines if word in line.split()])
idf = math.floor(math.log10(total_doc_count/doc_cnt) * 10000) / 10000
tf_idf = math.floor(tf * idf * 10000) / 10000
print("{:10} {:5} {:10} {:5} {:10} {:10}".format(word, count, tf, doc_cnt, idf, tf_idf))
Total doc count : 10
Total Word count : 156
해시계 5 0.032 5 0.301 0.0096
다 5 0.032 5 0.301 0.0096
지 5 0.032 4 0.3979 0.0127
않 5 0.032 4 0.3979 0.0127
의 4 0.025 4 0.3979 0.0099
그림자 4 0.025 4 0.3979 0.0099
을 4 0.025 2 0.6989 0.0174
에 3 0.019 3 0.5228 0.0099
를 3 0.019 3 0.5228 0.0099
표시 3 0.019 3 0.5228 0.0099
면 3 0.019 3 0.5228 0.0099
, 3 0.019 3 0.5228 0.0099
도 3 0.019 2 0.6989 0.0132
한 2 0.012 2 0.6989 0.0083
꽂 2 0.012 2 0.6989 0.0083
적 2 0.012 2 0.6989 0.0083
된다 2 0.012 2 0.6989 0.0083
에서 2 0.012 2 0.6989 0.0083
시간 2 0.012 2 0.6989 0.0083
가리키 2 0.012 2 0.6989 0.0083
게 2 0.012 2 0.6989 0.0083
은 2 0.012 2 0.6989 0.0083
있 2 0.012 2 0.6989 0.0083
속도 2 0.012 2 0.6989 0.0083
일정 2 0.012 2 0.6989 0.0083
기 2 0.012 2 0.6989 0.0083
때문 2 0.012 2 0.6989 0.0083
매우 1 0.006 1 1.0 0.006
단순 1 0.006 1 1.0 0.006
장치 1 0.006 1 1.0 0.006
땅 1 0.006 1 1.0 0.006
막대기 1 0.006 1 1.0 0.006
하나 1 0.006 1 1.0 0.006
만 1 0.006 1 1.0 0.006
으면 1 0.006 1 1.0 0.006
원시 1 0.006 1 1.0 0.006
형태 1 0.006 1 1.0 0.006
뚝딱 1 0.006 1 1.0 0.006
완성 1 0.006 1 1.0 0.006
북반구 1 0.006 1 1.0 0.006
시계 1 0.006 1 1.0 0.006
방향 1 0.006 1 1.0 0.006
으로 1 0.006 1 1.0 0.006
돈다 1 0.006 1 1.0 0.006
위치 1 0.006 1 1.0 0.006
따라가 1 0.006 1 1.0 0.006
며 1 0.006 1 1.0 0.006
적당히 1 0.006 1 1.0 0.006
그런데 1 0.006 1 1.0 0.006
막대 1 0.006 1 1.0 0.006
때 1 0.006 1 1.0 0.006
천구 1 0.006 1 1.0 0.006
북극 1 0.006 1 1.0 0.006
향하 1 0.006 1 1.0 0.006
도록 1 0.006 1 1.0 0.006
거나 1 0.006 1 1.0 0.006
대충 1 0.006 1 1.0 0.006
북극성 1 0.006 1 1.0 0.006
기울이 1 0.006 1 1.0 0.006
정확 1 0.006 1 1.0 0.006
성 1 0.006 1 1.0 0.006
한결 1 0.006 1 1.0 0.006
높 1 0.006 1 1.0 0.006
아 1 0.006 1 1.0 0.006
진다 1 0.006 1 1.0 0.006
이렇게 1 0.006 1 1.0 0.006
계절 1 0.006 1 1.0 0.006
바뀌 1 0.006 1 1.0 0.006
어도 1 0.006 1 1.0 0.006
시각 1 0.006 1 1.0 0.006
달라지 1 0.006 1 1.0 0.006
는다 1 0.006 1 1.0 0.006
가장 1 0.006 1 1.0 0.006
일반 1 0.006 1 1.0 0.006
인 1 0.006 1 1.0 0.006
평평 1 0.006 1 1.0 0.006
원판 1 0.006 1 1.0 0.006
눈금 1 0.006 1 1.0 0.006
된 1 0.006 1 1.0 0.006
것 1 0.006 1 1.0 0.006
인데 1 0.006 1 1.0 0.006
공원 1 0.006 1 1.0 0.006
같 1 0.006 1 1.0 0.006
곳 1 0.006 1 1.0 0.006
쉽 1 0.006 1 1.0 0.006
볼 1 0.006 1 1.0 0.006
수 1 0.006 1 1.0 0.006
이런 1 0.006 1 1.0 0.006
현태 1 0.006 1 1.0 0.006
눈금판 1 0.006 1 1.0 0.006
주위 1 0.006 1 1.0 0.006
간격 1 0.006 1 1.0 0.006
균일 1 0.006 1 1.0 0.006
잘 1 0.006 1 1.0 0.006
맞 1 0.006 1 1.0 0.006
이유 1 0.006 1 1.0 0.006
여러 1 0.006 1 1.0 0.006
가지 1 0.006 1 1.0 0.006
지구 1 0.006 1 1.0 0.006
공전 1 0.006 1 1.0 0.006
탓 1 0.006 1 1.0 0.006
고 1 0.006 1 1.0 0.006
서머 1 0.006 1 1.0 0.006
타임 1 0.006 1 1.0 0.006
제도 1 0.006 1 1.0 0.006