Showing
7 changed files
with
129 additions
and
155 deletions
... | @@ -27,26 +27,134 @@ | ... | @@ -27,26 +27,134 @@ |
27 | - 장르 시각화 : matplot, Seaborn 패키지를 통한 시각화 | 27 | - 장르 시각화 : matplot, Seaborn 패키지를 통한 시각화 |
28 | 28 | ||
29 | ## Model | 29 | ## Model |
30 | -- 데이터 수집 : [CMU Movie Summary Corpus][CMU]의 Detaset 42,306개, 뮤지컬 줄거리 255개 | 30 | +- 데이터 수집 : [CMU Movie Summary Corpus][CMU]의 Detaset 42,306개, 뮤지컬 줄거리 307개 |
31 | - 데이터 전처리 : Detaset 토큰화, 불용어 처리 후 정수 인코딩 | 31 | - 데이터 전처리 : Detaset 토큰화, 불용어 처리 후 정수 인코딩 |
32 | -- 데이터 분석 : 의사결정나무 모델, RNN, k-nearest neighbor < 연구중 | 32 | +- 데이터 분석 : lstm |
33 | - 데이터 검증 : k-fold 교차검증을 활용하여 장르별 정확도를 확인 | 33 | - 데이터 검증 : k-fold 교차검증을 활용하여 장르별 정확도를 확인 |
34 | -- 데이터 시각화 : 분석된 장르를 장르 단어 분포도로 시각화한다. | 34 | +- 데이터 시각화 : 분석된 뮤지컬 데이터를 장르 단위로 시각화한다. |
35 | - | 35 | + |
36 | - | 36 | +## 과제 수행 |
37 | - | 37 | +### 데이터 수집 |
38 | -## Schedule | 38 | +[ 장르 분류 모델 학습 데이터 ] |
39 | - | 39 | + 모델 학습을 위한 데이터는 뮤지컬 줄거리로는 양이 충분하지 못해 뮤지컬과 줄거리가 비슷한 영화 데이 터를 활용했습니다. http://www.cs.cmu.edu/~ark/personas/에서 영화 줄거리(영어) 데이터를 42,306개 수집했 습니다. |
40 | -__3월__ | 40 | + |
41 | - - 주제 선정 | 41 | + |
42 | - | 42 | +* 수집한 영화 줄거리 태깅 일부 : 각 영화 줄거리에는 데이터 제공 사이트에서 미리 장르를 다양하게 태깅 된 상태였습니다. |
43 | -__4월__ | 43 | + |
44 | - - 뮤지컬 줄거리 웹 크롤링 | 44 | + |
45 | - - 테스트 데이터 라벨링 | 45 | + |
46 | - | 46 | + 미리 태깅되어 있는 장르를 [‘romance’, ’fantasy’ ,‘thriller’, ‘drama’, ’ history’ , ‘social’ , ‘#N/A’] 같이 6개의 장르로 재분류했습니다. |
47 | -__5월__ | 47 | + |
48 | - - 데이터 전처리 | 48 | + |
49 | - + 토큰화 (완료) | 49 | + |
50 | - + 라벨링 (진행중) | 50 | + 재분류 방법은 위 표처럼 직접 모든(364개) 장르를 확인하며 위 6가지 정해놓은 장르 중 가장 유사한 장르 를 선택했습니다. 장르 분류가 애매한 경우는 ‘#N/A’으로 처리했습니다. 이러한 방법을 364개의 장르를 재 태깅했습니다. |
51 | - | 51 | + |
52 | - | 52 | +재태깅된 장르를 기반으로 줄거리를 6가지 장르로 분류해서 장르별 csv파일로 추출했습니다 |
53 | + | ||
54 | + | ||
55 | +[ 모델 테스트 데이터 ] | ||
56 | + 브로드웨이 뮤지컬 줄거리를 크롤링을 통해 수집했습니다. 크롤링한 웹사이트는 https://broadwaymusicalhome.com/shows.htm 입니다. 총 307건의 줄거리를 크롤링하였습니다. (Beautifulsoup 패키지를 사용했습니다) | ||
57 | + | ||
58 | +### 데이터 전처리 | ||
59 | + | ||
60 | +[ NLTK 라이브러리 활용 전처리 ] | ||
61 | + 장르가 NULL인 줄거리를 제외하고 약 35,000개의 줄거리 데이터 전처리를 진행했습니다. 이때단어 토큰화, 불용어 제거를 위해 NLTK 자연어처리 라이브러리를 사용했습니다. | ||
62 | +* 전처리 소스코드 일부 (자세한 내용은 주석처리했습니다.) | ||
63 | + | ||
64 | + | ||
65 | + ```from tqdm import tqdm | ||
66 | + all_vocab = {} | ||
67 | + all_sentences = [] | ||
68 | + stop_words = set(stopwords.words('english')) | ||
69 | + | ||
70 | + for i in tqdm(allplot): | ||
71 | + all_sentences = word_tokenize(str(i)) # 단어 토큰화를 수행합니다. | ||
72 | + result = [] | ||
73 | + for word in all_sentences: | ||
74 | + word = word.lower() # 모든 단어를 소문자화하여 단어의 개수를 줄입니다. | ||
75 | + if word not in stop_words: # 단어 토큰화 된 결과에 대해서 불용어를 제거합니다. | ||
76 | + if len(word) > 2: # 단어 길이가 2이하인 경우에 대하여 추가로 단어를 제거합니다. | ||
77 | + result.append(word) | ||
78 | + if word not in all_vocab: | ||
79 | + all_vocab[word] = 0 | ||
80 | + all_vocab[word] += 1 | ||
81 | + all_sentences.append(result) | ||
82 | + | ||
83 | + all_vocab_sorted = sorted(all_vocab.items(), key = lambda x:x[1], reverse = True) | ||
84 | + | ||
85 | + all_word_to_index = {} | ||
86 | + i=0 | ||
87 | + for (word, frequency) in all_vocab_sorted : | ||
88 | + if frequency > 1 : # 빈도수가 적은 단어는 제외한다. | ||
89 | + i=i+1 | ||
90 | + all_word_to_index[word] = i | ||
91 | + vocab_size = 15000 #상위 15000개 단어만 사용 | ||
92 | + words_frequency = [w for w,c in all_word_to_index.items() if c >= vocab_size + 1] # 인덱스가 15000 초과인 단어 제거 | ||
93 | + for w in words_frequency: | ||
94 | + del all_word_to_index[w] # 해당 단어에 대한 인덱스 정보를 삭제 | ||
95 | + all_word_to_index['OOV'] = len(all_word_to_index) + 1 | ||
96 | + ``` | ||
97 | +[ 전체 줄거리(전체 : 로맨스, 판타지, 스릴러, 역사 줄거리) 단어 인덱스 부여 ] | ||
98 | + 단어 사용 빈도수가 적은 단어는 제외하기 위해서 빈도순으로 인덱스를 부여했습니다. 15,000순위 미만인 단어 정보는 삭제했습니다. | ||
99 | + | ||
100 | + | ||
101 | + | ||
102 | +[ 학습 데이터(= RM_train+TH_train+FN_train+HS_train ) 인코딩 ] | ||
103 | + 총 학습 데이터는 7000개로 ‘로맨스 : 스릴러 : 판타지 : 역사 = 2 : 2 : 2 : 1’의 비율로 맞추었습니다. | ||
104 | +* 인덱스 부여 소스코드 일부 (자세한 내용은 주석 처리했습니다.) | ||
105 | +### 모델 학습 | ||
106 | + | ||
107 | +다중 분류를 위해 순환 신경망 모델을 사용했습니다. | ||
108 | +* LSTM 모델 구현 소스코드 (자세한 설명은 주석 처리했습니다.) | ||
109 | +```from tensorflow.keras.preprocessing.sequence import pad_sequences | ||
110 | +from tensorflow.keras.models import Sequential | ||
111 | +from tensorflow.keras.layers import Dense, LSTM, Embedding | ||
112 | +from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint | ||
113 | +import numpy as np | ||
114 | + | ||
115 | + | ||
116 | +M_test=Mu_encoded | ||
117 | +M_test= np.array(M_test) | ||
118 | +max_len = 230 | ||
119 | +X_train = pad_sequences(X_train, maxlen=max_len) | ||
120 | +X_test = pad_sequences(X_test, maxlen=max_len) | ||
121 | + | ||
122 | +model = Sequential() | ||
123 | +model.add(Embedding(15002, 120)) | ||
124 | +model.add(LSTM(128)) | ||
125 | +model.add(Dense(4, activation='softmax')) | ||
126 | + | ||
127 | +es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=4) | ||
128 | +mc = ModelCheckpoint('best_model.h5', monitor='val_acc', mode='max', verbose=1, save_best_only=True) | ||
129 | + | ||
130 | +X_train = np.array(X_train) | ||
131 | +Y_train = np.array(Y_train) | ||
132 | +X_test = np.array(X_test) | ||
133 | +Y_test = np.array(Y_test) | ||
134 | + | ||
135 | +model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['acc']) | ||
136 | +model.fit(X_train, Y_train, validation_data=(X_test, Y_test), epochs=7, batch_size=64, callbacks=[es, mc]) | ||
137 | +``` | ||
138 | + | ||
139 | + 뮤지컬 데이터로 테스트 결과 많은 뮤지컬 작품이 로맨스로 분류된 것을 확인하였고, 스릴러가 가장 적은 비율로 분류된것을 확인했습니 다. | ||
140 | +[ 실제 줄거리와 비교 ] | ||
141 | +* 오페라의 유령 뮤지컬 줄거리의 장르를 예측한 결과 아래와 같이 로맨스로 정확하게 분류되었습니다. 오 페라의 유령같이 장르 특징이 뚜렷한 줄거리의 경우는 항상 정확한 분류가 이루어지는 것을 확인했습니다. | ||
142 | + | ||
143 | +## 기대효과 및 활용방안 | ||
144 | +공식 티켓 판매처(인터파크, 예스 24공연 등)에도 뮤지컬 장르구분은 존재하지 않았습니다. 이런 사이트에서 축적된 공연 데이터를 통해 더 정확한 장르 구분을 한다면 일반인들의 뮤지컬에 대한 관심과 접근성을 높 일 수 있을것으로 기대합니다. 또한, 국내 창작 뮤지컬에 로맨스 뮤지컬 뿐만 아니라 다양한 장르가 존재함 을 알릴 수 있을 것입니다. 또한, 분류된 결과를 데이터베이스에 구축하고 웹사이트를 구현하면 뮤지컬 장 르 체계화에 도움이 될 것입니다. | ||
145 | + | ||
146 | +## 결론 및 제언 | ||
147 | +이진 분류의 경우(예시- 로맨스 vs 판타지)에는 테스트이렇 데이터 정확도가 80%에 이르며 높은 정확도를 보였습니다. 하지만 다중 분류(4개)의 경우에 학습한 경우 정확도가 최대 63%까지만 이르며 모델의 성능을 높이지 못했습니다. 원인으로 첫째, 학습한 줄거리 데이터의 길이가 짧아 내용이 불충분한 경우가 있습니다. 둘째, 줄거리 길이는 충분하지만 분류를 위한 특성을 추출하기 어려운 단어가 많은 경우가 있었습니다. | ||
148 | + | ||
149 | +프로젝트 진행 초반에는 한글 줄거리로 국내 뮤지컬 장르를 분류하고자 했습니다. 하지만 국내 뮤지컬 줄 거리의 대부분은 홍보용으로 내용에 대한 설명이 부실한 경우가 많아 분석에 어려움이 있었습니다. 충분한 한국어 뮤지컬 줄거리 데이터를 구하지 못해 영어 자연어처리로 주제가 변경된 부분이 아쉽습니다 | ||
150 | + | ||
151 | +### 역할 분담 | ||
152 | +양윤지 : | ||
153 | + 영화 데이터 수집&정리, 줄거리 데이터 장르 재태깅, Train,Test데이터 시각화&패딩, LSTM모델구현, 시각화 | ||
154 | + | ||
155 | + | ||
156 | +김서영 : | ||
157 | +뮤지컬 데이터 수집&정리, 장르 데이터 전처리, Train,Test데이터 인코딩, LSTM모델로 학습, 테스트 데이터 학 | ||
158 | +습, 뮤지컬 데이터 분류, | ||
159 | + | ||
160 | +시연 영상 링크 : https://youtu.be/EKjjQ0tHM4s | ... | ... |
moviedata/MovieSummaries.zip
deleted
100644 → 0
This file is too large to display.
1 | -{ | ||
2 | - "cells": [ | ||
3 | - { | ||
4 | - "cell_type": "markdown", | ||
5 | - "metadata": {}, | ||
6 | - "source": [ | ||
7 | - "# <4월 20일 ~ 4월 24일>" | ||
8 | - ] | ||
9 | - }, | ||
10 | - { | ||
11 | - "cell_type": "markdown", | ||
12 | - "metadata": {}, | ||
13 | - "source": [ | ||
14 | - "\n", | ||
15 | - "(1) 플레이DB 웹크롤링 -> 에러처리, csv파일로 옮기기 남음\n", | ||
16 | - "\n", | ||
17 | - "(2) **tf-idf**로 키워드 추출 고려 <br/>\n", | ||
18 | - " -> 줄거리가 짧아서 단어 빈도수가 커야 6정도 ==> 따라서 장르별 대표작들 줄거리를 모아서 해보기로 계획\n", | ||
19 | - "\n", | ||
20 | - "(3) **word2vec**로 문맥이 비슷한 단어 파악하려했지만<br/>\n", | ||
21 | - " ->학습 시간이 오래걸리는 문제 <br/>\n", | ||
22 | - " ->단어 관계 파악 후에 어떻게 처리할지 고민,,<br/>\n", | ||
23 | - "\n", | ||
24 | - "---" | ||
25 | - ] | ||
26 | - }, | ||
27 | - { | ||
28 | - "cell_type": "markdown", | ||
29 | - "metadata": {}, | ||
30 | - "source": [ | ||
31 | - "# <다음주 계획>" | ||
32 | - ] | ||
33 | - }, | ||
34 | - { | ||
35 | - "cell_type": "markdown", | ||
36 | - "metadata": {}, | ||
37 | - "source": [ | ||
38 | - "\n", | ||
39 | - "-장르별 키워드 생각(크롤링x, 생각대로) <br/>\n", | ||
40 | - "ex) 로맨스 = ['사랑','연인','애틋',........]<br/>\n", | ||
41 | - "-가볍게 테스트<br/>\n", | ||
42 | - "\n", | ||
43 | - "\n", | ||
44 | - "### 테스트 결과가 잘 나온다면,, 장르별 키워드 추출 모델 만들기\n", | ||
45 | - "#### (잘 나오지 못하면,, 새로운 방법 고려)\n", | ||
46 | - "---\n", | ||
47 | - "\n", | ||
48 | - "(1-1) **불용어 대표 사전 제작**<br/>\n", | ||
49 | - "\n", | ||
50 | - "- 뮤지컬정보관련된거 ('뮤지컬','제작사','콘텐츠', 뮤지컬이름, '창작','티켓', '매진'....)<br/>\n", | ||
51 | - "- 고유 명사<br/>\n", | ||
52 | - "- 시간관련 명사, 부사 모든것, (시작 ,나이, '최초','전날' '작년', OOOO년 OO월 OO일, '당시')<br/>\n", | ||
53 | - "- 장소는 애매,, ('감옥'이런 장소는 유의미,,)(그런데 지명은 무의미)<br/>\n", | ||
54 | - "- 감정이 아닌 단어 예를 들면 ('표현', '세상',...) <br/>\n", | ||
55 | - "- 흔한 불용어('우리' ,,)<br/>\n", | ||
56 | - "- 한국어가 아닌 단어(한자, 영어)<br/>\n", | ||
57 | - "\n", | ||
58 | - "(1-2) **장르 대표작 30편씩 고르기**<br/>\n", | ||
59 | - "=> 장르별 대표작 30편씩은 줄거리 + 그 이외 기사, 대본 가능한대로 긁어와..<br/>\n", | ||
60 | - "\n", | ||
61 | - "*키워드 추출은 불용어 사전을 통해 불필요한 단어를 제외하고, 나머지 단어들의 사용된 빈도를 기준으로함.<br/>\n", | ||
62 | - "*이때 키워드를 사전 api와 비교해서 나오지 않는것은 이름으로 간주하고 제거.<br/>\n", | ||
63 | - "\n", | ||
64 | - "(1-3) 장르 대표작들을 통해 **‘장르별 대표 키워드 사전 만들기’** => 이때 키워드가 포함된 문장도 추출<br/>\n", | ||
65 | - "(왜냐하면 word2vec을 사용하려면 문장 필요)<br/>" | ||
66 | - ] | ||
67 | - }, | ||
68 | - { | ||
69 | - "cell_type": "code", | ||
70 | - "execution_count": null, | ||
71 | - "metadata": {}, | ||
72 | - "outputs": [], | ||
73 | - "source": [] | ||
74 | - } | ||
75 | - ], | ||
76 | - "metadata": { | ||
77 | - "kernelspec": { | ||
78 | - "display_name": "Python 3", | ||
79 | - "language": "python", | ||
80 | - "name": "python3" | ||
81 | - }, | ||
82 | - "language_info": { | ||
83 | - "codemirror_mode": { | ||
84 | - "name": "ipython", | ||
85 | - "version": 3 | ||
86 | - }, | ||
87 | - "file_extension": ".py", | ||
88 | - "mimetype": "text/x-python", | ||
89 | - "name": "python", | ||
90 | - "nbconvert_exporter": "python", | ||
91 | - "pygments_lexer": "ipython3", | ||
92 | - "version": "3.7.6" | ||
93 | - } | ||
94 | - }, | ||
95 | - "nbformat": 4, | ||
96 | - "nbformat_minor": 2 | ||
97 | -} |
1 | -{ | ||
2 | - "cells": [ | ||
3 | - { | ||
4 | - "cell_type": "markdown", | ||
5 | - "metadata": {}, | ||
6 | - "source": [ | ||
7 | - "## 1. 불용어 처리\n", | ||
8 | - "## 2. 어근 추출\n", | ||
9 | - "## 3. 인코딩\n", | ||
10 | - "## 4. 패딩 \n", | ||
11 | - "\n", | ||
12 | - "## 5. " | ||
13 | - ] | ||
14 | - } | ||
15 | - ], | ||
16 | - "metadata": { | ||
17 | - "kernelspec": { | ||
18 | - "display_name": "Python 3", | ||
19 | - "language": "python", | ||
20 | - "name": "python3" | ||
21 | - }, | ||
22 | - "language_info": { | ||
23 | - "codemirror_mode": { | ||
24 | - "name": "ipython", | ||
25 | - "version": 3 | ||
26 | - }, | ||
27 | - "file_extension": ".py", | ||
28 | - "mimetype": "text/x-python", | ||
29 | - "name": "python", | ||
30 | - "nbconvert_exporter": "python", | ||
31 | - "pygments_lexer": "ipython3", | ||
32 | - "version": "3.7.3" | ||
33 | - } | ||
34 | - }, | ||
35 | - "nbformat": 4, | ||
36 | - "nbformat_minor": 2 | ||
37 | -} |
This diff is collapsed. Click to expand it.
발표/5.29.zip
deleted
100644 → 0
No preview for this file type
발표/전체 인덱싱.zip
deleted
100644 → 0
No preview for this file type
-
Please register or login to post a comment