1. 파일 읽어오는 함수
# 내 파일 읽어오기
from os import listdir
def fileids(path, ext="txt"):
return [path+file for file in listdir(path) if "사회" in file]
def filecontent(file):
with open(file, encoding="utf-8") as fp:
content = fp.read()
return content
def ngram(term, n=2):
return [term[i:i+n] for i in range(len(term) - n + 1)]
2. 불필요한 문자제거용 정규표현식
# 불필요한 문자열 제거
# 정규식, 길이, 구두점 제거
from string import punctuation
import re
pattern = dict()
# 구두점
pattern1 = re.compile(r"[{0}]".format(re.escape(punctuation)))
# corpus = pattern1.sub(" ", corpus)
pattern["punc"] = pattern1
# 불용어
pattern2 = re.compile(r"[A-Za-z0-9]{7,}")
# corpus = pattern2.sub(" ", corpus)
pattern["stopword"] = pattern2
# 이메일
pattern3 = re.compile(r"\w{2,}@\w{3,}(.\w{2,})+")
# corpus = pattern3.sub(" ", corpus)
pattern["email"] = pattern3
# 도메인
pattern4 = re.compile(r"(.?\w{2,}){2,}")
# corpus = pattern4.sub(" ", corpus)
pattern["domain"] = pattern4
# 한글, 숫자만 남기기
pattern5 = re.compile(r"[^가-힣0-9]+")
# corpus = pattern5.sub(" ", corpus)
pattern["nonkorean"] = pattern5
# 반복되는 공백문자
pattern6 = re.compile(r"\s")
# corpus = pattern6.sub(" ", corpus)
pattern["whitespace"] = pattern6
3. DTM만들기
from collections import defaultdict # 키가 없을 때 에러가 없도록 하기 위함
# 전체 처리해보기
DTM = defaultdict(lambda: defaultdict(int))
for file in fileids("./scraping/"):
with open(file, encoding="utf-8") as fp:
content = fp.read()
# 1. 문자열 가져오기
indexTerm1 = defaultdict(int)
indexTerm2 = defaultdict(int)
indexTerm3 = defaultdict(int)
indexTerm4 = defaultdict(int)
indexTerm5 = defaultdict(int)
indexTerm = defaultdict(int)
# 2. 불필요한 문자 제거
for _ in ["email", "punc", "stopword", "whitespace"]:
content = pattern[_].sub(" ", content)
# 3. 특징점 분리
for term in word_tokenize(content):
indexTerm1[term] += 1
for _ in indexTerm1:
for t in ma.pos(_):
indexTerm2[t] += 1 # 원시형태소 + 품사
DTM[file][t] += 1
if len(t[0]) > 1: # 음절 길이로 정규화
indexTerm3[t[0]] += 1 # 원시형태소
DTM[file][t[0]] += 1
if t[1].startswith("N"):
indexTerm4[t[0]] += 1 # 명사
DTM[file][t[0]] += 1
for n in ngram(t[0]): # N그램(바이그램)
indexTerm5[n] += 1
DTM[file][n] += 1
# DTM[file][term] += 1
4. TDM 만들기
- DTM의 역순( document이름, 단어 => 단어, document이름 )
TDM = defaultdict(lambda: defaultdict(int))
for idx, termList in DTM.items():
for term, freq in termList.items():
TDM[term][idx] = freq
5. 문서의 벡터값 구하기
- 각 단어에 대한 다차원에서 벡터값을 구한다
from math import log2, sqrt
TWM = defaultdict(lambda:defaultdict(float))
N = len(DTM)
DVL = defaultdict(float)
for idx, termList in DTM.items():
maxTF = max(termList.values())
for term, freq in termList.items():
# 데이터 벡터
TF = freq/maxTF
IDF = log2(N/len(TDM[term]))
TWM[term][idx] = TF*IDF
DVL[idx] += TWM[term][idx]**2
for idx, length in DVL.items():
DVL[idx] = sqrt(length)
6. Query도 모든 1~5번과정을 거치기
from nltk.tokenize import sent_tokenize
query = '서울시에 거래되는 아파트의 전세값은'
TQM = defaultdict(int)
QWM = defaultdict(float)
# 1. 문자열 가져오기
indexTerm1 = defaultdict(int)
indexTerm2 = defaultdict(int)
indexTerm3 = defaultdict(int)
indexTerm4 = defaultdict(int)
indexTerm5 = defaultdict(int)
QDTM = defaultdict(int)
# 2. 불필요한 문자 제거
for _ in ["email", "punc", "stopword", "whitespace"]:
query = pattern[_].sub(" ", query)
# 3. 특징점 분리
for _ in word_tokenize(query):
for t in ma.pos(_):
indexTerm2[t] += 1 # 원시형태소 + 품사
QDTM[t] += 1
if len(t[0]) > 1: # 음절 길이로 정규화
indexTerm3[t[0]] += 1 # 원시형태소
QDTM[t[0]] += 1
if t[1].startswith("N"):
indexTerm4[t[0]] += 1 # 명사
QDTM[t[0]] += 1
for n in ngram(t[0]): # N그램(바이그램)
indexTerm5[n] += 1
QDTM[n] += 1
QDTM[_] += 1
print(len(QDTM))
# QDTM => TQM
for term, freq in QDTM.items():
TQM[term] = freq
# TQM => QWM
alpha = 0.5
maxTF = max(TQM.values())
for term, ferq in TQM.items():
TF = alpha + (1-alpha)*(freq/maxTF)
DF = len(TWM[term]) if len(TWM[term]) > 0 else 1
IDF = log2(N/DF)
QWM[term] = TF*IDF
# 유사도
candidateList = defaultdict(float)
for term, weight1 in QWM.items():
for doc, weight2 in TWM[term].items():
innerProduct = weight1 * weight2
candidateList[doc] += innerProduct
for doc, sim in candidateList.items():
candidateList[doc] = sim/DVL[doc]
7. 벡터 유사도 출력
K = 10
for doc, sim in sorted(candidateList.items(), key=lambda x:x[1], reverse=True)[:K]:
print('문서이름:{0} / 유사도:{1:.4f}'.format(doc, sim))
#print(sent_tokenize(kobill.open(doc).read())[:3])
print()
print(sent_tokenize(filecontent(doc))[:3])
8. 유클리디언 거리 구하기
candidateList = defaultdict(float)
for term, docList in TWM.items():
for doc, weight1 in docList.items():
weight2 = QTWM[term]
candidateList[doc] += (weight1 - weight2) ** 2
for doc, sim in candidateList.items():
candidateList[doc] = sqrt(sim)
9. 유클리디언 거리 출력하기
from nltk.tokenize import sent_tokenize
K = 5
for doc, sim in sorted(candidateList.items(), key=lambda x:x[1], reverse=False)[:K]:
print("문서이름:{0} / 거리:{1:.4f}".format(doc, sim))
print(sent_tokenize(filecontent(doc))[:5])
print()
'데이터 분석가 역량' 카테고리의 다른 글
Day 25 ] Naive Bayes (0) | 2019.06.05 |
---|---|
Day 22 ] Classification (0) | 2019.05.30 |
Day 20] 내 파일로 분석해보기 (0) | 2019.05.29 |
Day 19 ] Deep Learning (0) | 2019.05.27 |
Day 18 ] 정보검색 - Vector 공간 (0) | 2019.05.27 |