멀티캠퍼스 RNN수업5_자연어처리
1. Bag of words with CountVector(어간추출/멀티스레드/ Pipeline/wordcloud 추가)
어제 수행했던 내용에 어간추출을 수행하는 SnowballStemmer을 추가한 코드
#어제 작업
import re
from bs4 import BeautifulSoup
import pandas as pd
train = pd.read_csv("labeledTrainData.tsv", header=0, \
delimiter="\t", quoting=3)
train.shape
#(25000, 3)
train['sentiment'].value_counts()
# remove tag
rows = []
for t in train["review"]:
soup = BeautifulSoup(t, "html.parser")
for s in soup.select('br'):
s.extract()
rows.append(soup.get_text())
train["review"] = rows
example1 = train["review"][0]
letters_only = re.sub("[^a-zA-Z]",
" ",example1 )
lower_case = letters_only.lower()
words = lower_case.split()
import nltk
nltk.download('stopwords')
nltk.download('wordnet') # 온톨로지(보고 들은 모든 것)
from nltk.corpus import stopwords
stopwords.words("english")[:10]
#['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're"]
words = [w for w in words if not w in stopwords.words("english")]
# 처리 전
words[:10]
['stuff',
'going',
'moment',
'mj',
'started',
'listening',
'music',
'watching',
'odd',
'documentary']
추가 실행
## 추가
from nltk.stem.snowball import SnowballStemmer
stemmer = SnowballStemmer('english')
words = [stemmer.stem(w) for w in words]
# 처리 후 단어
words[:10]
['stuff',
'go',
'moment',
'mj',
'start',
'listen',
'music',
'watch',
'odd',
'documentari']
## 변경
def review_to_words( raw_review ):
# 1. HTML 제거
review_text = BeautifulSoup(raw_review).get_text()
# 2. 영문자가 아닌 문자는 공백으로 전환
letters_only = re.sub("[^a-zA-Z]", " ", review_text)
# 3. 소문자 변환
words = letters_only.lower().split()
# 4. 파이썬에서는 리스트보다 set으로 검색하는게 빠름
stops = set(stopwords.words("english"))
# 5. Stopwords 불용어 제거
meaningful_words = [w for w in words if not w in stops]
# 6. 어간추출(새롭게 추가)
stemming_words = [stemmer.stem(w) for w in meaningful_words]
# 7. 공백으로 구분된 문자열로 결합하여 결과를 반환
return( " ".join( meaningful_words ))
clean_review = review_to_words( train["review"][0] )
num_reviews = train["review"].size
num_reviews
#25000
## 추가
from multiprocessing import Pool
import numpy as np
#멀티쓰레드를 사용하기 위해서 2개 함수를 추가함
def _apply_df(args):
df, func, kwargs = args
return df.apply(func, **kwargs)
def apply_by_multiprocessing(df, func, **kwargs):
# 키워드 항목 중 workers 파라메터를 꺼냄
workers = kwargs.pop('workers')
# 위에서 가져온 workers 수로 프로세스 풀을 정의
pool = Pool(processes=workers)
# 실행할 함수와 데이터프레임을 워커의 수 만큼 나눠 작업
result = pool.map(_apply_df, [(d, func, kwargs)
for d in np.array_split(df, workers)])
pool.close()
# 작업 결과를 합쳐서 반환
return pd.concat(list(result))
## 추가(오래걸림)
%time clean_train_reviews = apply_by_multiprocessing(train['review'], review_to_words, workers=4)
%time clean_test_reviews = apply_by_multiprocessing(test['review'], review_to_words, workers=4)
사이킷런의 CountVectorizer를 통해 피처 생성
# create bag of words with scikit-learn
# 변경
print ("Creating the bag of words...\n")
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(analyzer = "word", \
tokenizer = None, \
preprocessor = None, \
stop_words = None, \
ngram_range=(1,3), # 1글자~3글자까지 포함된 내용 적용
max_features = 5000) # set the features number to 5000
vectorizer
# 추가
from sklearn.pipeline import Pipeline
pipeline = Pipeline([
('vect', vectorizer),
])
# 변경
# train_data_features = vectorizer.fit_transform(clean_train_reviews)
%time train_data_features = pipeline.fit_transform(clean_train_reviews)
print (train_data_features.shape)
# 변경
vocab = vectorizer.get_feature_names()
# print (vocab)
print(len(vocab))
vocab[:10]
# 추가
dist = np.sum(train_data_features, axis=0)
for tag, count in zip(vocab, dist):
print(count, tag)
# df = pd.DataFrame(train_data_features)
df = pd.DataFrame(dist, columns=vocab)
df
# 추가
pd.DataFrame(train_data_features[:10].toarray(), columns=vocab).head()
Random Forest
# Random Forest
print("Training the random forest...")
from sklearn.ensemble import RandomForestClassifier
# Initialize
# forest = RandomForestClassifier(n_estimators = 100)
forest = RandomForestClassifier(n_estimators = 100, n_jobs=-1, random_state=2020)
# forest = forest.fit( train_data_features, train["sentiment"] )
forest
# 분리
# Traing of Random Forest
%time forest = forest.fit( train_data_features, train["sentiment"] )
# 추가
from sklearn.model_selection import cross_val_score
%time score = np.mean(cross_val_score(
forest, train_data_features, train['sentiment'],
cv=10, scoring='roc_auc'))
score
TEST
clean_test_reviews[0]
%time test_data_features = pipeline.transform(clean_test_reviews)
test_data_features = test_data_features.toarray()
# 추가
test_data_features
# 추가
# 벡터화 된 단어로 숫자가 문서에서 등장하는 횟수를 나타낸다
test_data_features[5][:100]
# 추가
# 벡터화 하며 만든 사전에서 해당 단어가 무엇인지 찾아볼 수 있다.
# vocab = vectorizer.get_feature_names()
vocab[8], vocab[2558], vocab[2559], vocab[2560]
# Predict test data with trained random forest model
result = forest.predict(test_data_features)
# 추가
result[:10]
# Display predict result (convert thr result to csv file for submit to the Kaggle)
output = pd.DataFrame( data={"id":test["id"], "sentiment":result} )
output.to_csv( "Bag_of_Words_model.csv", index=False, quoting=3 )
output
Wordcloud
pip install wordcloud
# 추가
# newStopWords = ['one', 'movie', 'film']
# stopwords_pychan.extend(newStopWords)
from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt
# %matplotlib inline 설정을 해주어야지만 노트북 안에 그래프가 디스플레이 된다.
%matplotlib inline
def displayWordCloud(data = None, backgroundcolor = 'white', width=800, height=600 ):
wordcloud = WordCloud(stopwords = STOPWORDS,
background_color = backgroundcolor,
width = width, height = height).generate(data)
plt.figure(figsize = (15 , 10))
plt.imshow(wordcloud)
plt.axis("off")
plt.show()
# 추가
# 학습 데이터의 모든 단어에 대한 워드 클라우드를 그려본다.
%time displayWordCloud(' '.join(clean_train_reviews))
# 추가
# 단어 수
train['num_words'] = clean_train_reviews.apply(lambda x: len(str(x).split()))
# 중복을 제거한 단어 수
train['num_uniq_words'] = clean_train_reviews.apply(lambda x: len(set(str(x).split())))
# 테스트 데이터의 모든 단어에 대한 워드 클라우드를 그려본다.
%time displayWordCloud(' '.join(clean_test_reviews))
# 추가
# 불용어 추가 테스트
newStopWords = ['one', 'movie', 'film']
my_stopwords = stopwords.words("english")
my_stopwords.extend(newStopWords)
# 추가
def newDisplayWordCloud(data = None, backgroundcolor = 'white', width=800, height=600 ):
wordcloud = WordCloud(stopwords = my_stopwords,
background_color = backgroundcolor,
width = width, height = height).generate(data)
plt.figure(figsize = (15 , 10))
plt.imshow(wordcloud)
plt.axis("off")
plt.show()
# 추가
# 테스트 데이터의 모든 단어에 대한 워드 클라우드를 그려본다.
%time newDisplayWordCloud(' '.join(clean_test_reviews))
Word2Vec_CBOW방식
Word2Vec_Skip-gram방식
from gensim.models import Word2Vec
embedding_model = Word2Vec(tokenized_contents, size=100,
window = 2, min_count=50, workers=4, iter=100, sg=1) #window=2는 sg=0 시보, sg=1 skipgram
print(embedding_model.most_similar(positive=["디자인"], topn=100)) #디자인이라는 단어가 100차원의 데이터로 보관되어 있음
네이버영화
IDB
3. Bag of words with Word2Vec(실습)
Part 1 - Preprocessing
데이터전처리 과정을 전처리할 수 있는 Word2VecUtil이라는 class를 만들어 사용함(해당파일의 class명에 문제가 있어서 수정함) KaggleWord2VecUtility -> Word2VecUtil
import warnings
warnings.filterwarnings('ignore')
import re
from bs4 import BeautifulSoup
import pandas as pd
train = pd.read_csv("labeledTrainData.tsv", header=0, delimiter="\t", quoting=3)
test = pd.read_csv("testData.tsv", header=0, delimiter="\t", quoting=3)
unlabeled_train = pd.read_csv("unlabeledTrainData.tsv", header=0, delimiter="\t", quoting=3)
print(train.shape)
print(test.shape)
print(unlabeled_train.shape)
print(train['review'].size)
print(test['review'].size)
print(unlabeled_train['review'].size)
#(25000, 3)
#(25000, 2)
#(50000, 2)
#25000
#25000
#50000
train['sentiment'].value_counts()
#1 12500
#0 12500
part2- word2vec
from Word2VecUtil import Word2VecUtil
Word2VecUtil.review_to_wordlist(train['review'][0])[:10]
#['with', 'all', 'this', 'stuff', 'go', 'down', 'at', 'the', 'moment', 'with']
import nltk
nltk.download('punkt')
sentences = []
for review in train["review"]:
sentences += Word2VecUtil.review_to_sentences(
review, remove_stopwords=False)
for review in unlabeled_train["review"]:
sentences += Word2VecUtil.review_to_sentences(
review, remove_stopwords=False)
len(sentences)
#약 80만개의 문장이 포함됨
#795538
sentences[0][:10]
#['with', 'all', 'this', 'stuff', 'go', 'down', 'at', 'the', 'moment', 'with']
#gemsim 설치
#pip install gensim
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s',
level=logging.INFO)
# 파라메터값 지정
num_features = 300 # 문자 벡터 차원 수
min_word_count = 40 # 최소 문자 수
num_workers = 4 # 병렬 처리 스레드 수
context = 10 # 문자열 창 크기 #문자열 창 크기(전후) 한번에 익식하는 데이터의 수
downsampling = 1e-3 # 문자 빈도 수 Downsample
from gensim.models import word2vec
# 모델 학습
model = word2vec.Word2Vec(sentences,
workers=num_workers,
size=num_features,
min_count=min_word_count,
window=context,
sample=downsampling)
model
# 학습이 완료 되면 필요없는 메모리를 unload 시킨다.
model.init_sims(replace=True)
model_name = '300features_40minwords_10text'
# model_name = '300features_50minwords_20text'
model.save(model_name)
모델 결과 탐색
#여러 단어 중 관련 없는 단어(거리가 가장 먼 단어)는?
model.wv.doesnt_match("man woman child kitchen".split())
#'kitchen'
model.wv.doesnt_match("france england germany berlin".split())
#'berlin'
#가장 관련 높은 단어(거리가 가장 가까운 단어)는?
model.wv.most_similar("film")
#[('movi', 0.8592548370361328),
# ('flick', 0.6085095405578613),
# ('documentari', 0.5563615560531616),
# ('cinema', 0.5387020707130432),
# ('pictur', 0.5238867998123169),
# ('masterpiec', 0.4901632070541382),
# ('sequel', 0.48803427815437317),
# ('it', 0.4877569079399109),
# ('genr', 0.4808454215526581),
# ('effort', 0.4701777696609497)]
#happy로 하면 오류가 남 (stemming작업으로 원래 단어가 변형됨)
#model.wv.most_similar("happy")
model.wv.most_similar("happi") # stemming 처리 시
#[('unhappi', 0.4212590157985687),
# ('bitter', 0.41711732745170593),
# ('sad', 0.41446375846862793),
# ('afraid', 0.3979133367538452),
# ('satisfi', 0.39775803685188293),
# ('glad', 0.37727090716362),
# ('happier', 0.3730996251106262),
# ('upset', 0.3724191188812256),
# ('reward', 0.3672931492328644),
# ('sappi', 0.3646870255470276)]
Word2Vec으로 벡터화 한 단어를 t-SNE 를 통해 시각화
# 참고 https://stackoverflow.com/questions/43776572/visualise-word2vec-generated-from-gensim
from sklearn.manifold import TSNE
import matplotlib as mpl
import matplotlib.pyplot as plt
import gensim
import gensim.models as g
# 그래프에서 마이너스 폰트 깨지는 문제에 대한 대처
# mpl.rcParams['axes.unicode_minus'] = False
model_name = '300features_40minwords_10text'
model = g.Doc2Vec.load(model_name)
vocab = list(model.wv.vocab)
X = model[vocab]
print(len(X))
print(X[0][:10])
tsne = TSNE(n_components=2)
# 100개의 단어에 대해서만 시각화
X_tsne = tsne.fit_transform(X[:100,:])
# X_tsne = tsne.fit_transform(X)
#11986
#[ 0.00980356 0.06309218 0.05619177 -0.07966041 0.05931453 -0.06673906 -0.02150377 0.06647947 0.08702882 0.00142203]
df = pd.DataFrame(X_tsne, index=vocab[:100], columns=['x', 'y'])
df.shape
#(100, 2)
df.head(10)
#x y
#with 2.823911 -9.014259
#all -3.183646 -6.294578
#this -0.505597 -2.188253
#stuff -0.794164 -6.949909
#go 5.887387 0.091774
#down 4.398484 -11.293688
#at 5.728839 -9.630657
#the -2.743879 -7.748000
#moment -5.781786 -5.001288
#mj -1.763150 -12.215151
fig = plt.figure()
fig.set_size_inches(40, 20)
ax = fig.add_subplot(1, 1, 1)
ax.scatter(df['x'], df['y'])
for word, pos in df.iterrows():
ax.annotate(word, pos, fontsize=30)
plt.show()
import numpy as np
def makeFeatureVec(words, model, num_features):
"""
주어진 문장에서 단어 벡터의 평균을 구하는 함수
"""
# 속도를 위해 0으로 채운 배열로 초기화 한다.
featureVec = np.zeros((num_features,),dtype="float32")
nwords = 0.
# Index2word는 모델의 사전에 있는 단어명을 담은 리스트이다.
# 속도를 위해 set 형태로 초기화 한다.
index2word_set = set(model.wv.index2word)
# 루프를 돌며 모델 사전에 포함이 되는 단어라면 피처에 추가한다.
for word in words:
if word in index2word_set:
nwords = nwords + 1.
featureVec = np.add(featureVec,model[word])
# 결과를 단어수로 나누어 평균을 구한다.
featureVec = np.divide(featureVec,nwords)
return featureVec
def getAvgFeatureVecs(reviews, model, num_features):
# 리뷰 단어 목록의 각각에 대한 평균 feature 벡터를 계산하고
# 2D numpy 배열을 반환한다.
# 카운터를 초기화 한다.
counter = 0.
# 속도를 위해 2D 넘파이 배열을 미리 할당한다.
reviewFeatureVecs = np.zeros(
(len(reviews),num_features),dtype="float32")
for review in reviews:
# 매 1000개 리뷰마다 상태를 출력
if counter%1000. == 0.:
print("Review %d of %d" % (counter, len(reviews)))
# 평균 피처 벡터를 만들기 위해 위에서 정의한 함수를 호출한다.
reviewFeatureVecs[int(counter)] = makeFeatureVec(review, model, \
num_features)
# 카운터를 증가시킨다.
counter = counter + 1.
return reviewFeatureVecs
# 멀티스레드로 4개의 워커를 사용해 처리한다.
def getCleanReviews(reviews):
clean_reviews = []
clean_reviews = Word2VecUtil.apply_by_multiprocessing(\
reviews["review"], Word2VecUtil.review_to_wordlist,\
workers=4)
return clean_reviews
%time trainDataVecs = getAvgFeatureVecs(\
getCleanReviews(train), model, num_features )
%time testDataVecs = getAvgFeatureVecs(\
getCleanReviews(test), model, num_features )
모델 생성
from sklearn.ensemble import RandomForestClassifier
forest = RandomForestClassifier(
n_estimators = 100, n_jobs = -1, random_state=2018)
%time forest = forest.fit( trainDataVecs, train["sentiment"] )
#CPU times: user 1min 1s, sys: 166 ms, total: 1min 1s
#Wall time: 8.3 s
from sklearn.model_selection import cross_val_score
%time score = np.mean(cross_val_score(\
forest, trainDataVecs, \
train['sentiment'], cv=10, scoring='roc_auc'))
score
#0.9003752
Test
result = forest.predict( testDataVecs )
output = pd.DataFrame( data={"id":test["id"], "sentiment":result} )
output.to_csv('Word2Vec_AverageVectors_{0:.5f}.csv'.format(score),
index=False, quoting=3 )
output_sentiment = output['sentiment'].value_counts()
print(output_sentiment[0] - output_sentiment[1])
output_sentiment
#156
#0 12578
#1 12422
import seaborn as sns
%matplotlib inline
fig, axes = plt.subplots(ncols=2)
fig.set_size_inches(12,5)
sns.countplot(train['sentiment'], ax=axes[0])
sns.countplot(output['sentiment'], ax=axes[1])
4. NAVER_MOVIE 한글 텍스트처리
시간이 너무 오래걸려서 강사님이 코랩에서 돌릴 수 있는 코드를 제공해줌
import pandas as pd
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import re
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
train_data = pd.read_table('ratings_train.txt')
test_data = pd.read_table('ratings_test.txt')
train_data[:3]
#id document label
#0 9976970 아 더빙.. 진짜 짜증나네요 목소리 0
#1 3819312 흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나 1
#2 10265843 너무재밓었다그래서보는것을추천한다 0
len(train_data)
#15000
len(test_data)
#5000
#데이터 중복 확인 -> nunique
train_data['document'].nunique(),train_data['label'].nunique()
#(146182, 2)
train_data.drop_duplicates(subset=['document'],inplace=True) #중복데이터 삭제
len(train_data)
#146183
train_data['label'].value_counts().plot(kind='bar')
train_data.isnull().sum()
#id 0
#document 1
#label 0
#dtype: int64
print(train_data.isnull().sum())
print(train_data.document.isnull())
train_data.loc[train_data.document.isnull()]
train_data=train_data.dropna(how='any')
train_data['document']= train_data['document'].str.replace("[^ㄱ-하-ㅣ가-힣]","")
train_data.head()
train_data['document'].replace('',np.nan, inplace=True) #공란인 것을 nan으로 만들어라
train_data.loc[train_data.document.isnull()][:5]
test_data['document'].nunique()
#49157
test_data.drop_duplicates(subset=['document'],inplace=True)
test_data['document']= test_data['document'].str.replace("[^ㄱ-하-ㅣ가-힣]","")
test_data['document'].replace('',np.nan, inplace=True)
test_data=test_data.dropna(how='any')
print("테스트 데이터", len(test_data))
#테스트 데이터 48860
# 불용어 제거, 한국어의 조사, 접속사 등 -> 지속적으로 검토하면서 추가해서 삭제
stopwords = ['의','가','이','은','들','는','좀','잘','걍','과','도','를','으로','자','에','와','한','하다']
from konlpy.tag import Okt
okt = Okt()
okt.morphs("2000년 이후 최고의 서스팬스 영화.. 라고 했지만, 이걸 왜 봤을까?")
# 불용어 제거
# 형태소 토큰화
X_train = []
for sentence in train_data['document']:
temp_X = []
temp_X = okt.morphs(sentence, stem=True) # 토큰화
temp_X = [word for word in temp_X if not word in stopwords] # 불용어 제거
X_train.append(temp_X)
print(X_train[:3])
X_test = []
for sentence in test_data['document']:
temp_X = []
temp_X = okt.morphs(sentence, stem=True) # 토큰화
temp_X = [word for word in temp_X if not word in stopwords] # 불용어 제거
X_test.append(temp_X)
# 정수 인코딩
tokenizer = Tokenizer()
tokenizer.fit_on_texts(X_train)
print(tokenizer.word_index)
#{'영화': 1, '보다': 2, '을': 3, '없다': 4, '이다': 5, '있다'...
threshold = 3 # 빈도수가 3회 미만은 제거
total_cnt = len(tokenizer.word_index) # 단어의 수
rare_cnt = 0 # 등장 빈도수가 threshold보다 작은 단어의 개수를 카운트
total_freq = 0 # 훈련 데이터의 전체 단어 빈도수 총 합
rare_freq = 0 # 등장 빈도수가 threshold보다 작은 단어의 등장 빈도수의 총 합
# 단어와 빈도수의 쌍(pair)을 key와 value로 받는다.
for key, value in tokenizer.word_counts.items():
total_freq = total_freq + value
# 단어의 등장 빈도수가 threshold보다 작으면
if(value < threshold):
rare_cnt = rare_cnt + 1
rare_freq = rare_freq + value
print('단어 집합(vocabulary)의 크기 :',total_cnt)
print('등장 빈도가 %s번 이하인 희귀 단어의 수: %s'%(threshold - 1, rare_cnt))
print("단어 집합에서 희귀 단어의 비율:", (rare_cnt / total_cnt)*100)
print("전체 등장 빈도에서 희귀 단어 등장 빈도 비율:", (rare_freq / total_freq)*100)
#단어 집합(vocabulary)의 크기 : 43752
#등장 빈도가 2번 이하인 희귀 단어의 수: 24337
#단어 집합에서 희귀 단어의 비율: 55.62488571950996
#전체 등장 빈도에서 희귀 단어 등장 빈도 비율: 1.8715872104872904
vocab_size = total_cnt - rare_cnt + 1
# 전체 단어 개수 중 빈도수 2이하인 단어 개수는 제거. 0번 패딩 토큰을 고려하여 +1
print('단어 집합의 크기 :',vocab_size)
#단어 집합의 크기 : 19416
# 토크나이저는 텍스트 시퀀스를 숫자 시퀀스로 변환하는 정수 인코딩 과정에서
# 이보다 큰 숫자가 부여된 단어들은 아예 계산하지 않음
tokenizer = Tokenizer(vocab_size)
tokenizer.fit_on_texts(X_train)
X_train = tokenizer.texts_to_sequences(X_train)
X_test = tokenizer.texts_to_sequences(X_test)
print(X_train[:3])
#[[50, 454, 16, 260, 659], [933, 457, 41, 602, 1, 214, 1449, 24, 961, 675, 19], [386, 2444, 2315, 5671, 2, 222, 9]]
y_train = np.array(train_data['label'])
y_test = np.array(test_data['label'])
빈샘플(Empty samples) 제거
drop_train = [index for index, sentence in enumerate(X_train) if len(sentence) < 1]
drop_test = [index for index, sentence in enumerate(X_test) if len(sentence) < 1]
# 빈 샘플들을 제거
X_train = np.delete(X_train, drop_train, axis=0)
y_train = np.delete(y_train, drop_train, axis=0)
print(len(X_train))
print(len(y_train))
#145162
#145162
X_test = np.delete(X_test, drop_test, axis=0)
y_test = np.delete(y_test, drop_test, axis=0)
print(len(X_test))
print(len(y_test))
#48745
#48745
패딩
print('리뷰의 최대 길이 :',max(len(l) for l in X_train))
print('리뷰의 평균 길이 :',sum(map(len, X_train))/len(X_train))
plt.hist([len(s) for s in X_train], bins=50)
plt.xlabel('length of samples')
plt.ylabel('number of samples')
plt.show()
#리뷰의 최대 길이 : 69
#리뷰의 평균 길이 : 10.812485361182679
# 전체 샘플 중 길이가 max_len 이하인 샘플의 비율이 몇 %인지 확인하는 함수
def below_threshold_len(max_len, nested_list):
cnt = 0
for s in nested_list:
if(len(s) <= max_len):
cnt = cnt + 1
print('전체 샘플 중 길이가 %s 이하인 샘플의 비율: %s'%(max_len, (cnt / len(nested_list))*100))
max_len = 30
below_threshold_len(max_len, X_train)
#전체 샘플 중 길이가 30 이하인 샘플의 비율: 94.31944999380003
X_train = pad_sequences(X_train, maxlen = max_len)
X_test = pad_sequences(X_test, maxlen = max_len)
LSTM으로 네이버 영화 리뷰 감성 분류
from tensorflow.keras.layers import Embedding, Dense, LSTM
from tensorflow.keras.models import Sequential
from tensorflow.keras.models import load_model
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
T = X_train.shape[1]
from tensorflow.keras.layers import Input, Embedding, LSTM, Dense
from tensorflow.keras.models import Model
i = Input(shape=(T,))
x = Embedding(vocab_size, 100)(i)
x = LSTM(128)(x)
x = Dense(1, activation='sigmoid')(x)
model = Model(i, x)
# model.summary()
#Model: "model"
#_________________________________________________________________
#Layer (type) Output Shape Param #
#=================================================================
#input_1 (InputLayer) [(None, 30)] 0
#_________________________________________________________________
#embedding (Embedding) (None, 30, 100) 1941600
#_________________________________________________________________
#lstm (LSTM) (None, 128) 117248
#_________________________________________________________________
#dense (Dense) (None, 1) 129
#=================================================================
X_train.shape[1]
30
# 검증 데이터 손실(val_loss)이 증가하면, 과적합 징후
# 검증 데이터 손실이 4회 증가하면 학습을 조기 종료(Early Stopping)
# 검증 데이터의 정확도(val_acc)가 이전보다 좋아질 경우에만 모델을 저장
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=4)
mc = ModelCheckpoint('best_model.h5', monitor='val_acc', mode='max',
verbose=1, save_best_only=True)
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
history = model.fit(X_train, y_train, epochs=15,
callbacks=[es, mc], batch_size=60, validation_split=0.2)
# loaded_model = load_model('best_model.h5')
# print("\n 테스트 정확도: %.4f" % (loaded_model.evaluate(X_test, y_test)[1]))
print("\n 테스트 정확도: %.4f" % (model.evaluate(X_test, y_test)[1]))
#테스트 정확도: 0.8364
5.Naver 영화 관련 팀 프로젝트
네이버 무비 크롤링 코드
import requests
from bs4 import BeautifulSoup as bs
address = 'https://movie.naver.com/movie/point/af/list.nhn?&page=1'
res = requests.get(address)
res.encoding = None
parse = bs(res.text, 'html.parser')
td_list = parse.select('td.title')
score_list =[]
result_text = []
# print(td_list)
for td in td_list:
em = td.select('em')
for extract_tag in em:
score_list.append(extract_tag.getText())
extract_tag.extract() #em태크 관련 내용은 삭제
a = td.select('a')
for extract_tag in a:
extract_tag.extract() #a태크 관련 내용은 삭제
div = td.select('div')
for extract_tag in div:
extract_tag.extract() #div태크 관련 내용은 삭제
result_text.append(td.getText().strip()) #최종적으로 남은 텍스트파일(리뷰)만 남음
print(result_text)
print(score_list)
Leave a comment