네이버 부스트코스 강좌 정리입니다.
- 문서 간 유사도(코사인 유사도)를 통해 특정 문서의 범주를 분류해보기
- 총 80개의 문서, 야구선수/축구선수 기사로의 분류
import os
##########################################################################################################
def get_file_list(dir_name): # file name들을 가져오는 함수 # 폴더명 인자 # 폴더가 위치한 경로를 인자로
return os.listdir(dir_name) # 폴더 내 파일명을 리스트 형태로 반환
##########################################################################################################
# 현재 8명의 선수에 대해 각각 10개씩의 기사 (야구4,축구4)
# 기사 카테고리의 경우 선수별로 1_~~~.txt 형식으로 맨 앞 숫자로 누구의 기사인지 구분
def get_conetents(file_list): # 모든 파일의 상대경로 리스트를 인자로
y_class = []
X_text = []
class_dict = { # 야구선수와 축구선수에 대해 0,1의 클래스로 분류할것
1: "0", 2: "0", 3:"0", 4:"0", 5:"1", 6:"1", 7:"1", 8:"1"} # 파일명의 맨 앞 숫자로 분류
for file_name in file_list:
try:
f = open(file_name, "r", encoding="cp949") # winodw => cp949, 파일 읽기
category = int(file_name.split(os.sep)[1].split("_")[0]) # 파일명 맨앞 숫자 빼내어 int형으로
# os.sep => \,/
y_class.append(class_dict[category]) # 해당파일이 0,1의 클래스 중 어디에 속하는지 (class_dict에 맞추어 분류됨)
X_text.append(f.read()) # 해당파일의 text
f.close()
except UnicodeDecodeError as e:
print(e)
print(file_name)
return X_text, y_class # 모든 파일들에 대해 각각의 text와 종목클래스 정보 반환
def get_cleaned_text(words): #
import re
words = re.sub('\W+','', words.lower() ) # 각각의 단어들을 소문자로 바꾸고, 문장부호를 없에고 반환
return words
def get_corpus_dict(text): # 모든 text를 인자로 받음(80개)
text = [sentence.split() for sentence in text] # 각 글별로 split을 진행하여 text라는 리스트에 저장
# split()은 결과물을 리스트로 반환함
# 2차원 리스트로 저장됨. # [[글1의 단어들],[글2의 단어들],[글3의 단어들]....]
cleand_words = [get_cleaned_text(word) for words in text for word in words]
# [글1의 단어들]에서 단어들을 하나씩 뽑은 후 다시 글자 하나 단위로 뽑아 get_cleaned함수를 적용
# list comprehension에서 for문이 나란히 두개인경우 앞에 for문부터 실행. 아래와 같다
# for words in text:
# for word in words:
# get_cleaned_text(word)
from collections import OrderedDict # dict의 값을 순서대로 사용가능. # 원래 dict는 순서 없음.
corpus_dict = OrderedDict()
for i, v in enumerate(set(cleand_words)): # 중복제거하여 단어사전을 만듬
corpus_dict[v] = i # 각 단어별로 index를 지정
return corpus_dict # 각 단어를 key값으로 갖는 dict를 반환
def get_count_vector(text, corpus): # 문서별 단어빈도를 vector로
text = [sentence.split() for sentence in text]
word_number_list = [[corpus[get_cleaned_text(word)] for word in words] for words in text]
# get_corpus_dict와 같은 원리이지만 2차원 리스트로 반환함. # 각 문서별로 구분하기위해
X_vector = [[0 for _ in range(len(corpus))] for x in range(len(text))]
# 80 4030? 의 matrix 생성 # _ => 변수를 사용하지 않는다.(0으로 행렬을 채워넣는다)
for i, text in enumerate(word_number_list): # 각 문서별로 corpus_dict에 맞추어 빈도수 구해줌
for word_number in text:
X_vector[i][word_number] += 1
return X_vector # 문서별 단어빈도수까지 추가
import math
def get_cosine_similarity(v1,v2): # 문서 2개의 벡터를 넣어 코사인 유사도 계산
"compute cosine similarity of v1 to v2: (v1 dot v2)/{||v1||*||v2||)"
sumxx, sumxy, sumyy = 0, 0, 0
for i in range(len(v1)):
x = v1[i]; y = v2[i]
sumxx += x*x
sumyy += y*y
sumxy += x*y
return sumxy/math.sqrt(sumxx*sumyy)
def get_similarity_score(X_vector, source): # X_vector => 전체(80개)문서 벡터,source => target text vector
source_vector = X_vector[source] # target text를 몇번째 문서로 할것인가
similarity_list = []
for target_vector in X_vector:
similarity_list.append(get_cosine_similarity(source_vector, target_vector))
# ex) 10번째 문서와 나머지 문서간의 코사인 유사도를 계산하여 리스트형태로 반환
# 여기서는 1개와 나머지 80개(자기자신포함)의 유사도 계산 => 자기자신과의 코사인 유사도는 1
return similarity_list
def get_top_n_similarity_news(similarity_score, n): # 가장 높은 유사도를 가진 문서 n개
import operator
x = {i:v for i, v in enumerate(similarity_score)}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))
return list(reversed(sorted_x))[1:n+1] # 유사도 1은 제외
def get_accuracy(similarity_list, y_class, source_news):
source_class = y_class[source_news]
# target과 유사도가 가장 높은 n개의 문서들의 클래스를 이용하여 정확도 계산
# ex) 10개중 0이 8개면 80%
return sum([source_class == y_class[i[0]] for i in similarity_list]) / len(similarity_list)
# 실행
if __name__ == "__main__":
dir_name = "C:/Users/KIHyuk/Desktop/부스트코스/AI-python-connect-master/codes/ch_1/news/news_data" # 폴더명 * 폴더위치
file_list = get_file_list(dir_name) # 폴더 내에 파일명을 리스트로 return
file_list = [os.path.join(dir_name, file_name) for file_name in file_list] # 파일의 상대경로까지
# os.path => 각 os방식에 맞추어 경로 연결 (window => \, mac => /)
X_text, y_class = get_conetents(file_list)
# X_text => 모든 text 리스트
# y_class => 각 text 별 0,1 클래스
corpus = get_corpus_dict(X_text)
print("Number of words : {0}".format(len(corpus)))
X_vector = get_count_vector(X_text, corpus)
source_number = 10
result = []
for i in range(80):
source_number = i # 각 기사별로 나머지 기사와의 유사도 계산하여
similarity_score = get_similarity_score(X_vector, source_number)
similarity_news = get_top_n_similarity_news(similarity_score, 10)
accuracy_score = get_accuracy(similarity_news, y_class, source_number)
result.append(accuracy_score)
print(sum(result) / 80) # 전체 평균 정확도
'Python > 부스트코스_노트' 카테고리의 다른 글
Pythonic Code - Asterisk (0) | 2020.02.23 |
---|---|
Pythonic Code - map & reduce (0) | 2020.02.22 |
Pythonic Code - enumerate & zip (0) | 2020.02.22 |