250x250
Notice
Recent Posts
Recent Comments
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 크롤링
- 네이버뉴스
- (깃)git bash
- tomoto
- db
- 지마켓
- Python
- 자바
- Websocket
- RESFUL
- word2vec
- Topics
- oracle
- java
- lda
- spring MVC(모델2)방식
- 게시판 만들기
- mysql
- 과학백과사전
- test
- 이력서
- 토픽추출
- 幼稚园杀手(유치원킬러)
- 파이썬
- Gmarket
- 방식으로 텍스트
- r
- jsp 파일 설정
- pytorch
- 코사인 유사도
Archives
- Today
- Total
무회blog
0003-scikit-learn,방식 004-003, 사이킷런 문서유사도, 3가지 방식 본문
In [1]:
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer, HashingVectorizer
from sklearn.metrics.pairwise import linear_kernel ,cosine_similarity
from konlpy.tag import Twitter
twitter = Twitter()
# 엑셀 vlookup 방식으로 title 과 content 내용을 출력 하기
import pandas as pd
pd.options.mode.chained_assignment = None
import numpy as np
np.random.seed(0) # 랜덤 난수를 지정하여 사용
from collections import Counter
# from gensim.models import Word2Vec
from gensim.summarization import summarize
# from rank_bm25 import BM25Okapi
from nltk import sent_tokenize, word_tokenize
from konlpy.tag import Hannanum
from konlpy.tag import Kkma
hannanum = Hannanum()
from kiwipiepy import Kiwi
kiwi = Kiwi()
kiwi.prepare()
Out[1]:
In [2]:
import time, timeit, os, sys , re , math
from datetime import datetime
# BM25 를 사용하여 코사인 유사도에서 측정된 단어의 문장을 뽑아 낸다.
start_now = int(time.time())
td = datetime.today().strftime("%Y%m%d")
tdd = datetime.today().strftime("%m%d")
now = datetime.now()
td_all = now.strftime('%Y%m%d%H%M%S')
In [3]:
class Cleaning_Text:
# tokenizer : 문장에서 색인어 추출을 위해 명사,동사,알파벳,숫자 정도의 단어만 뽑아서 normalization, stemming 처리하도록 함
def tokenizer_twitter(raw, pos=["Noun","Alpha","Verb","Number"], stopword=[]):
print('raw', type(raw))
print('pos', type(pos))
print('stopword', type(stopword))
return [
word for word, tag in twitter.pos(
raw,
norm=True, # normalize 그랰ㅋㅋ -> 그래ㅋㅋ
stem=True # stemming 바뀌나->바뀌다
)
if len(word) > 1 and tag in pos and word not in stopword
]
def tokenize_kiwi(sent):
res, score = kiwi.analyze(sent)[0] # 첫번째 결과를 사용
return [word
for word, tag, _, _ in res
if not tag.startswith('E')
and not tag.startswith('J')
and not tag.startswith('S')] # 조사, 어미, 특수기호는 제거
def token_word(documents): ## param List
texts = [
[word for word in document.split() if len(word) > 1]
for document in documents
]
return texts
def token_sent(text):
text = sent_tokenize(text)
if len(text) > 1:
text = text
else:
pass
text_token = text
return text_token
def listToText(inputList):
returnText = ''
for i in inputList:
returnText = returnText + i
rt2 = Cleaning_Text.text_cleaning(returnText)
return rt2
## # step_4, 공통 코드 , 텍스트 클리닝
def text_cleaning(text):
################################## gensim 사용을 위한 정규표현식 200624
hangul_path9 = '[가-힣]+\.' # 한글로 포함되다 .
hangul_path0 = '[가-힣]+\.[가-힣]{1}' # 한글 . + 한글 처리
hangul_path1 = '[가-힣]+\.[\d]{1}' # 한글 . + 숫자 처리 [0-9]
hangul_path2 = '[가-힣]+\.[a-z]{1}' # 한글 . + 영어 소문자
hangul_path3 = '[가-힣]+\.[A-Z]{1}' # 한글 . + 영어 대문자
hangul_path4 = '[가-힣]+\.[\S]{1}' # 한글 . + 비공백 [^ \t\n\r\f\v]와 같다.
hangul_path5 = '[가-힣]+\.[\s]{1}' # 한글 . + 공백 [ \t\n\r\f\v]와 같다.
hangul_path6 = '[가-힣]+\.[\W]{1}' # 한글 . + 숫자 + 문자가 아닌 것 [^a-zA-Z0-9]와 같다.
hangul_path7 = '[가-힣]+\.[\w]{1}' # 한글 . + 숫자 + 문자 [a-zA-Z0-9]와 같다.
hangul_path8 = '[가-힣]+\.[\b]{1}' # 한글 . + 단어 경계 (`\w`와 `\W`의 경계)
reg_path = hangul_path0 + '|' + hangul_path1 + '|'+ hangul_path2 + '|'+ hangul_path3 + '|'+ hangul_path4+ '|'+ hangul_path5
hangul = re.compile(reg_path) # 한글 + 모모로 포함되다 .
result = hangul.findall(text) # 정규식에 일치되는 부분을 리스트 형태로 저장, 단어 반환
result = list(set(result))
for x in result:
text = text.replace(x, x[:-1] + '\n' + x[-1:])
### 줄단위 좌우 공백 지우기 ,
text = text.replace('\n','_').split('_')
text = [x.strip() for x in text]
tts = ''
for i in text:
tts = tts + i + '\n'
text = tts
################################## gensim 사용을 위한 정규표현식 200624
text = re.sub('\[.+?\]','', text) # 대괄호 [] 이내 모든 문자 삭제
#이모티콘 제거
EMOJI = re.compile('[\U00010000-\U0010ffff]', flags=re.UNICODE)
text= EMOJI.sub(r'', text)
#이메일 주소 제거
email =re.compile('([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)')
text = email.sub('', text)
#URL 제거
url =re.compile('(http|ftp|https)://(?:[-\w.]|(?:%[\da-fA-F]{2}))+')
text = url.sub('', text)
#HTML 제거
html =re.compile('<[^>]*>')
text = html.sub('', text)
#특수문자를 공백으로 대체(문장을 살리기위헤 마침표는 남겨둠)
#special =re.compile('[^\w\s]')
#text = special.sub(' ', text)
special= ['*', '{', ',', ':', ']', '$', '+', '[', '#', '(', '%', '&', '}', '`', '‘', '’','·',
'=', ';', '>','>', '/', '"', '“', '”', '\\', '?', '~', "'", '<', ')', '^', '!', '_',
'|', '@','@','©','ⓒ', '℗','®','①', '-','▶','…','☞','▲','◆','■'] #'.', 빼고
for chr in special :
text=text.replace(chr,' ')
#특수문자 제거 후 생기는 중복된 공백 제거
while text.find(' ') > 0:
text = text.replace(' ',' ' ) # 중복된 공백 제거
#특수문자 제거 후 생기는 중복된 개행 제거
while text.find('\n\n') > 0:
text = text.replace('\n\n','\n' ) # 중복된 개행 제거
#좌우측 공백 삭제
text = text.strip()
return text
# 텍스트 정제 함수 : 분석에 불필요한 문자는 전부 제거합니다.
# 형태소 분석해서 용언(P), 체언(N)만 남김
def hannanum_get_infoText(read_text):
#resList = list()
resList=[]
#GetWordSet = set(['N'])
GetWordSet = set(['N','P'])
for read_text_line in read_text:
res=""
if len(read_text_line) > 0:
pos = hannanum.pos(read_text_line,ntags=9)
for keyword, type in pos:
# 키워드가 한글자 이상일 경우만
if len(keyword) > 1 :
# 용언(P), 체언(N)만 남김
if (type in GetWordSet):
if type == 'P': #용언일 경우 '다'를 붙여줌
keyword=keyword+'다'
resList.append(keyword)
return resList
scikit-learn 001 방식 체크¶
In [4]:
df_list = [pd.read_excel('./../test_data/test_Newsdata-100.xlsx', sheet_name = x) for x in range(6)]
df_list = [df_list[x][['subMenu', 'newsFrom', 'title', 'content', 'yoyag']] for x in range(6)]
df_list = [df_list[x].head(17) for x in range(6)]
df_ = pd.concat(df_list, axis=0)
data = df_.head(100).copy()
data['content'].isnull().sum() # 널값이 몇개있는지 체크
rawdata = data['content'].tolist()
In [5]:
tfidf = TfidfVectorizer(stop_words='english')
tfidf_matrix = tfidf.fit_transform(data['content']) # #第一个fit_transform是计算tf-idf,# 第二个fit_transform是将文本转为词频矩阵
cosine_sim = linear_kernel(tfidf_matrix, tfidf_matrix) # 코사인 유사도를 구합니다.
def get_recommendations(title, cosine_sim=cosine_sim):
# 선택한 타이틀로부터 해당되는 인덱스를 받아옵니다. 이제 선택한 것 가지고 연산할 수 있습니다.
idx = indices[title]
# 모든 타이틀 대해서 해당 타이틀 유사도를 구합니다.
sim_scores = list(enumerate(cosine_sim[idx]))
# 유사도에 따라 타이틀들을 정렬합니다.
sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
# 가장 유사한 10개의 타이틀를 받아옵니다.
sim_scores = sim_scores[1:11]
# 가장 유사한 10개의 타이틀의 인덱스를 받아옵니다.
title_indices = [i[0] for i in sim_scores]
# 가장 유사한 10개의 타이틀의 제목을 리턴합니다.
return data['content'].iloc[title_indices]
CountVectorizer 방식으로 테스트해보기¶
In [6]:
remarks = '''scikit-learn
CountVectorizer 방식
TfidfVectorizer 방식
HashingVectorizer 방식
1. 스코어 뽑기
2. n개 코사인 유사도 문장 뽑기
3. 돌아가는 시간 체크하기
4. 테스트 결과 기록하기(param 포함)
'입력데이터' : input_Text0
,'출력데이터' : srch
,'점수' : scoreList
,'sbMenuList' : sbMenuList
,'ttList' : ttList
,'유사도문장' : ctList
,'소요시간' : ends
,'비고' : remarks
'''
In [7]:
def get_vec2sentence():
# 문서목록에서 각 문서의 feature(문장의 특징) 노출수를 가중치로 설정한 BOW 벡터를 만든다.
vectorize = CountVectorizer(
tokenizer=Cleaning_Text.tokenize_kiwi ,
# tokenizer=Cleaning_Text.tokenizer_twitter ,
min_df=2 # 예제로 보기 좋게 1번 정도만 노출되는 단어들은 무시하기로 했다
# min_df = 0.01 : 문서의 1% 미만으로 나타나는 단어 무시 , # min_df = 10 : 문서에 10개 미만으로 나타나는 단어 무시
# max_df = 0.80 : 문서의 80% 이상에 나타나는 단어 무시 , # max_df = 10 : 10개 이상의 문서에 나타나는 단어 무시
)
# 문장에서 노출되는 feature(특징이 될만한 단어) 수를 합한 Document Term Matrix(이하 DTM) 을 리턴한다
X = vectorize.fit_transform(rawdata) # 인덱스 , tf-idf 기준의 DTM 값을 리턴한다.
print('fit_transform, (문장수 {}, feature_코퍼스 {})'.format(X.shape[0], X.shape[1]) )
dtm_bindo = X.toarray() # 5 행 7 열 에 대한 피쳐
features = vectorize.get_feature_names() # corpus_words
##### ##### ##### ##### ##### ##### ##### ##### #####
input_textSlice = [x for x in input_Text if len(x) > 1 if x in features]
##### ##### ##### ##### ##### ##### ##### ##### #####
df_features = pd.DataFrame(dtm_bindo, columns=features) # feature or topic 기준 , DTM 테이블 구성하기
# ####################################################################################################
srch = input_textSlice
print('srch',srch)
srch_dtm = np.asarray(X.toarray())[:, [
# vectorize.vocabulary_.get 는 특정 feature 가 dtm 에서 가지고 있는 컬럼의 인덱스값 을 리턴한다
vectorize.vocabulary_.get(i) for i in srch
]]
sbMenuList = []
ttList = []
ctList = []
scoreList = []
subMenuList = data['subMenu'].tolist()
titleList = data['title'].tolist()
rawdata # = data['content'].tolist()
cnt = len(srch)
score = srch_dtm.sum(axis=1)
# print(type(score))
print('dtm 표 디센딩 , 출현단어 인덱스 기준: ',score.argsort()[::-1]) # dtm 표 디센딩 , 출현단어 인덱스 기준
print('dtm 표 디센딩 , 출현단어 빈도수 기준: ', sorted(score, reverse=True)) # dtm 표 디센딩 , 출현단어 빈도수 기준
for i in score.argsort()[::-1][:cnt]: # argsort-큰값부터 순서대로 데이터의 위치를 반환, cnt 갯수만큼 리턴
if score[i] > 0: # score[i] 는 feature 합계의 인덱스 , i 는 디센딩으로 들어오는 스코어 인덱스
# print('{} 번째 문장: ,테스트단어 출현 빈도 {}, 해당문장 {}'.format(i, score[i],rawdata[i]))
original_tokenList = Cleaning_Text.tokenize_kiwi(input_Text0)
gensim_tokenList1 = Cleaning_Text.tokenize_kiwi(rawdata[i])
_topFreqOriginal = Counter(original_tokenList)
_topFreqGensim1 = Counter(gensim_tokenList1)
comMon = _topFreqOriginal & _topFreqGensim1
comMon = comMon.most_common(cnt)
biyur = round(len(comMon)/len(original_tokenList),2)
biyur = str(biyur)
scoreList.append(biyur)
sbMenuList.append(subMenuList[i])
ttList.append(titleList[i])
ctList.append(rawdata[i])
ends = int(time.time()) - start_time
dic = {
'입력데이터' : input_Text0
,'출력데이터' : input_textSlice
,'점수' : scoreList
,'sbMenuList' : sbMenuList
,'ttList' : ttList
,'유사도문장' : ctList
,'소요시간' : ends
,'비고' : remarks
}
df_vc = pd.DataFrame(dic)
return df_vc
# # 검색 문장에서 feature를 뽑아냄
# input_text = []
# input_Text0 = input()
# input_Text = Cleaning_Text.tokenize_kiwi(input_Text0)
# start_time = int(time.time())
# df_vc = get_vec2sentence()
# excelName = td_all + '_'+ 'get_cntVector' + '.xlsx'
# df_vc.to_excel(excelName)
# ends = int(time.time()) - start_time
# print('{}초 걸림'.format(ends))
# # 삼성전자의 라이프스타일 TV가 최근 서울 시내 핫 플레이스에서 모습을 드러내고 있다
TfidfVectorizer 방식으로 테스트해보기¶
In [8]:
def get_tf_idfvector():
## TfidfVectorizer 방식으로 가중치를 주어서 Bow 를 만들다
vectorize = TfidfVectorizer(
tokenizer=Cleaning_Text.tokenize_kiwi,
min_df=2,
sublinear_tf=True # tf값에 1+log(tf)를 적용하여 tf값이 무한정 커지는 것을 막음
)
X = vectorize.fit_transform(rawdata)
print('fit_transform, (sentence {}, feature {})'.format(X.shape[0], X.shape[1]))
print(type(X.toarray()))
print(X.toarray())
# 문장에서 뽑아낸 feature 들의 배열
features = vectorize.get_feature_names()
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
input_textSlice = [x for x in input_Text if len(x) > 1 if x in features]
df_tfi = pd.DataFrame(X.toarray(), columns=features)
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
# 검색 문장에서 feature를 뽑아냄
print(input_text)
srch = input_textSlice
print(srch)
# dtm 에서 검색하고자 하는 feature만 뽑아낸다.
srch_dtm = np.asarray(X.toarray())[:, [
# vectorize.vocabulary_.get 는 특정 feature 가 dtm 에서 가지고 있는 index값을 리턴한다
vectorize.vocabulary_.get(i) for i in srch
]]
sbMenuList = []
ttList = []
ctList = []
scoreList = []
subMenuList = data['subMenu'].tolist()
titleList = data['title'].tolist()
rawdata # = data['content'].tolist()
cnt = len(srch)
score = srch_dtm.sum(axis=1)
for i in score.argsort()[::-1][:cnt]:
if score[i] > 0:
print(i)
# print('{} / score : {}'.format(rawdata[i], score[i]))
scoreList.append(round(score[i],2))
sbMenuList.append(subMenuList[i])
ttList.append(titleList[i])
ctList.append(rawdata[i])
ends = int(time.time()) - start_time
dic = {
'입력데이터' : input_Text0
,'출력데이터' : input_textSlice
,'점수' : scoreList
,'sbMenuList' : sbMenuList
,'ttList' : ttList
,'유사도문장' : ctList
,'소요시간' : ends
,'비고' : remarks
}
df_idf = pd.DataFrame(dic)
return df_idf
# # 검색 문장에서 feature를 뽑아냄
# input_text = []
# input_Text0 = input()
# input_Text = Cleaning_Text.tokenize_kiwi(input_Text0)
# start_time = int(time.time())
# df_idf = get_tf_idfvector()
# excelName = td_all + '_'+ 'get_idf_vector' + '.xlsx'
# df_idf.to_excel(excelName)
# ends = int(time.time()) - start_time
# print('{}초 걸림'.format(ends))
# # 삼성전자의 라이프스타일 TV가 최근 서울 시내 핫 플레이스에서 모습을 드러내고 있다
HashingVectorizer 방식으로 테스트 해보기¶
In [9]:
def get_hashing_vectorizer():
## HashingVectorizer 방식으로 테스트 해보기 ,
## 대용량 텍스트를 벡터화 할때 많이 쓰인다, CountVectorizer, TfidfVectorizer 와 달리 벡터화 할때 모든 feature 에 대해 사전을 만들지 않고, 해싱함수를 통해 벡터안의 인덱스를 특정하도록 한다. 큰 사전을 만들 필요가 없어 메모리 소모가 적어 대용량 텍스트를 벡터화 할때 많이 쓰인다.
vectorize = HashingVectorizer(
tokenizer= Cleaning_Text.tokenize_kiwi
# tokenizer= Cleaning_Text.tokenize_kiwi ,
# n_features=7
# 기본 feature 수를 설정하며 기본값이 2의 20승이다.
# 테스트시 feature 를 7로 한정했으나, 아래 유사문장을 찾을때는 다시 n_features 주석처리 했다.
)
X = vectorize.fit_transform(rawdata)
# search 문장 벡터
srch_vector = vectorize.transform([
input_Text0
])
# linear_kernel는 두 벡터의 dot product 이다.
cosine_similar = linear_kernel(srch_vector, X).flatten()
sbMenuList = []
ttList = []
ctList = []
scoreList = []
subMenuList = data['subMenu'].tolist()
titleList = data['title'].tolist()
rawdata # = data['content'].tolist()
cnt = len(input_Text)
sim_rank_idx = cosine_similar.argsort()[::-1][:cnt]
input_textSlice = input_Text
for i in sim_rank_idx:
if cosine_similar[i] > 0:
# print(' score : {}'.format(cosine_similar[i]))
score = round(cosine_similar[i],2)
scoreList.append(score)
sbMenuList.append(subMenuList[i])
ttList.append(titleList[i])
ctList.append(rawdata[i])
ends = int(time.time()) - start_time
dic = {
'입력데이터' : input_Text0
,'출력데이터' : input_textSlice
,'점수' : scoreList
,'sbMenuList' : sbMenuList
,'ttList' : ttList
,'유사도문장' : ctList
,'소요시간' : ends
,'비고' : remarks
}
df_hash = pd.DataFrame(dic)
return df_hash
# # 검색 문장
# input_text = []
# input_Text0 = input()
# input_Text = Cleaning_Text.tokenize_kiwi(input_Text0)
# start_time = int(time.time())
# df_hash = get_hashing_vectorizer()
# excelName = td_all + '_'+ 'get_hashing_vectorizer' + '.xlsx'
# df_hash.to_excel(excelName)
# ends = int(time.time()) - start_time
# print('{}초 걸림'.format(ends))
# df_hash
# # 삼성전자의 라이프스타일 TV가 최근 서울 시내 핫 플레이스에서 모습을 드러내고 있다
In [10]:
if __name__ == "__main__":
# 검색 문장
input_text = []
input_Text0 = input()
input_Text = Cleaning_Text.tokenize_kiwi(input_Text0)
start_time = int(time.time())
df_vc = get_vec2sentence()
excelName = td_all + '_'+ 'get_cntVector' + '.xlsx'
df_vc.to_excel(excelName)
ends = int(time.time()) - start_time
print('get_cntVector {}초 걸림'.format(ends))
# 삼성전자의 라이프스타일 TV가 최근 서울 시내 핫 플레이스에서 모습을 드러내고 있다
start_time = int(time.time())
df_idf = get_tf_idfvector()
excelName = td_all + '_'+ 'get_idf_vector' + '.xlsx'
df_idf.to_excel(excelName)
ends = int(time.time()) - start_time
print('get_idf_vector {}초 걸림'.format(ends))
# 삼성전자의 라이프스타일 TV가 최근 서울 시내 핫 플레이스에서 모습을 드러내고 있다
start_time = int(time.time())
df_hash = get_hashing_vectorizer()
excelName = td_all + '_'+ 'get_hashing_vectorizer' + '.xlsx'
df_hash.to_excel(excelName)
ends = int(time.time()) - start_time
print('get_hashing_vectorizer {}초 걸림'.format(ends))
# 삼성전자의 라이프스타일 TV가 최근 서울 시내 핫 플레이스에서 모습을 드러내고 있다
'Python' 카테고리의 다른 글
clustering-test00-군집분류,및 분류예측기-002,한파트흐름 (0) | 2020.07.20 |
---|---|
clustering,-test00-군집분류,및 분류예측기,-001 (0) | 2020.07.20 |
0003-scikit-lear,방식으로 텍스트 ,코사인 유사도, 구하기-004-01 (0) | 2020.07.14 |
1차 텍스트유사도 3가지 , word2vec,doc2vec,LSI방식, 등 , 성공 src (0) | 2020.07.14 |
python: 200713-텍스트유사도, 문서유사도, 방식, 3가지 LSI,word2vec,doc2Vec ,SrcFile (0) | 2020.07.13 |
Comments