{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# **고급 Feacture 엔지니어링**\n", "## **1 Gensim 을 활용한 NLP 알고리즘**\n", "Word2Vec\n", "1. ! pip install gensim" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('chryses', 0.6371129751205444),\n", " ('priest', 0.6282371282577515),\n", " ('nymph', 0.6165897250175476),\n", " ('thanks', 0.6120550632476807),\n", " ('dishonored', 0.6062030792236328),\n", " ('narrate', 0.605045735836029),\n", " ('angered', 0.6038438677787781),\n", " ('chieftains', 0.6015218496322632),\n", " ('appease', 0.6003137826919556),\n", " ('akhilleus', 0.6002722978591919)]" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from gensim.models import Word2Vec\n", "w2v_model = Word2Vec.load('../backup/model.bin')\n", "w2v_model.wv.most_similar(positive=['woman','king'], negative=['man'])" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.3998656" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w2v_model.wv.similarity('woman','man')" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "11098" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# sorted(w2v_model.wv.vocab.keys(), reverse=False)[:14]\n", "len(w2v_model.wv.vocab.keys())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **2 Gensim 을 활용한 유사도 분석실습**\n", "Word2Vec\n", "1. ! pip install gensim\n", "1. **\"Ice\"** 와 **\"Fire\"** 의 문학내 유사도 측정" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('principals', 0.9933313131332397),\n", " ('threatening', 0.9859204292297363),\n", " ('distorting', 0.9620187878608704),\n", " ('freeport', 0.9174789190292358),\n", " ('stood', 0.8492887616157532),\n", " ('extend', 0.8167773485183716),\n", " ('douglas', 0.767949104309082),\n", " ('1858', 0.7635020017623901),\n", " ('conspiracy', 0.762062668800354),\n", " ('values', 0.7606658339500427)]" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w2v_model.wv.most_similar('stark')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", "# **The Simpson 대본의 학습 및 분석**\n", "심슨 에피소드의 대본을 활용한 문장내 단어의 의미 분석 Totorial 입니다.\n", "1. **[Kaggle Tutorial](https://www.kaggle.com/pierremegret/gensim-word2vec-tutorial)**\n", "1. **[Simpson Script](https://www.kaggle.com/pierremegret/dialogue-lines-of-the-simpsons)**" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "import logging\n", "import pandas as pd\n", "from time import time\n", "\n", "# Setting up the loggings to monitor gensim\n", "logging.basicConfig(format=\"%(levelname)s - %(asctime)s: %(message)s\", \n", " datefmt= '%H:%M:%S', level=logging.INFO)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **1 PreProcessing**\n", "데이터 전처리 작업의 진행" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(158314, 2)\n", "raw_character_text 17814\n", "spoken_words 26459\n", "dtype: int64\n", "(131853, 2)\n", "raw_character_text 0\n", "spoken_words 0\n", "dtype: int64\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
raw_character_textspoken_words
0Miss HooverNo, actually, it was a little of both. Sometim...
1Lisa SimpsonWhere's Mr. Bergstrom?
2Miss HooverI don't know. Although I'd sure like to talk t...
\n", "
" ], "text/plain": [ " raw_character_text spoken_words\n", "0 Miss Hoover No, actually, it was a little of both. Sometim...\n", "1 Lisa Simpson Where's Mr. Bergstrom?\n", "2 Miss Hoover I don't know. Although I'd sure like to talk t..." ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = pd.read_csv('../backup/simpsons_dataset.csv')\n", "print(df.shape)\n", "\n", "# NaN, Null 데이터를 제거 합니다\n", "print(df.isnull().sum())\n", "df = df.dropna().reset_index(drop=True)\n", "print(df.shape)\n", "print(df.isnull().sum())\n", "df.head(3)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "131853it [01:07, 1961.82it/s]" ] }, { "name": "stdout", "output_type": "stream", "text": [ "(85960, 1)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
raw_character_textspoken_words
0Miss HooverNo, actually, it was a little of both. Sometim...
1Lisa SimpsonWhere's Mr. Bergstrom?
2Miss HooverI don't know. Although I'd sure like to talk t...
\n", "
" ], "text/plain": [ " raw_character_text spoken_words\n", "0 Miss Hoover No, actually, it was a little of both. Sometim...\n", "1 Lisa Simpson Where's Mr. Bergstrom?\n", "2 Miss Hoover I don't know. Although I'd sure like to talk t..." ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import re, spacy\n", "def cleaning(doc):\n", " txt = [token.lemma_ for token in doc if not token.is_stop]\n", " if len(txt) > 2: # 2글자 이상 단어만 선별\n", " return ' '.join(txt)\n", " \n", "brief_cleaning = (re.sub(\"[^A-Za-z']+\", ' ', str(row)).lower() \n", " for row in df['spoken_words'])\n", "\n", "# Spacy의 PipeLine 을 활용하여 표제어로 변경 및 Stopword 를 제거 합니다.\n", "from tqdm import tqdm\n", "nlp = spacy.load('en', disable=['ner', 'parser']) # stopword 필터링 파이프라인\n", "txt = [cleaning(doc) for doc in tqdm(nlp.pipe(brief_cleaning, batch_size=5000, n_threads=-1))]\n", "\n", "# 데이터 없는 행제거 및 전처리 완료 된 테이블을 출력 합니다\n", "df_clean = pd.DataFrame({'clean': txt})\n", "df_clean = df_clean.dropna().drop_duplicates()\n", "print(df_clean.shape)\n", "df.head(3)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(85960, 1)\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
clean
0actually little disease magazine news show nat...
2know sure like talk touch lesson plan teach
3life worth live
\n", "
" ], "text/plain": [ " clean\n", "0 actually little disease magazine news show nat...\n", "2 know sure like talk touch lesson plan teach\n", "3 life worth live" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_clean = pd.DataFrame({'clean': txt})\n", "df_clean = df_clean.dropna().drop_duplicates()\n", "print(df_clean.shape)\n", "df_clean.head(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **2 N-Gram Modeling**\n", "**\"mr_burns\", \"bart_simpson\"** 과 같은 **bi-gram** 모델을 만듭니다." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['actually',\n", " 'little',\n", " 'disease',\n", " 'magazine',\n", " 'news',\n", " 'show',\n", " 'natural',\n", " 'think'],\n", " ['know', 'sure', 'like', 'talk', 'touch', 'lesson', 'plan', 'teach'],\n", " ['life', 'worth', 'live']]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sent = [row.split() for row in df_clean['clean']]\n", "sent[:3]" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO - 15:35:52: collecting all words and their counts\n", "INFO - 15:35:52: PROGRESS: at sentence #0, processed 0 words and 0 word types\n", "INFO - 15:35:52: PROGRESS: at sentence #10000, processed 63561 words and 52716 word types\n", "INFO - 15:35:52: PROGRESS: at sentence #20000, processed 130949 words and 99637 word types\n", "INFO - 15:35:52: PROGRESS: at sentence #30000, processed 192972 words and 138212 word types\n", "INFO - 15:35:52: PROGRESS: at sentence #40000, processed 249845 words and 172230 word types\n", "INFO - 15:35:52: PROGRESS: at sentence #50000, processed 311277 words and 208051 word types\n", "INFO - 15:35:52: PROGRESS: at sentence #60000, processed 373597 words and 243068 word types\n", "INFO - 15:35:53: PROGRESS: at sentence #70000, processed 436446 words and 278001 word types\n", "INFO - 15:35:53: PROGRESS: at sentence #80000, processed 497916 words and 311099 word types\n", "INFO - 15:35:53: collected 329869 word types from a corpus of 537147 words (unigram + bigrams) and 85960 sentences\n", "INFO - 15:35:53: using 329869 counts as vocab in Phrases<0 vocab, min_count=30, threshold=10.0, max_vocab_size=40000000>\n", "INFO - 15:35:53: source_vocab length 329869\n", "INFO - 15:35:56: Phraser built with 126 phrasegrams\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Phrases() 모듈에는 list로 구성된 텍스트를 바로 입력 가능 합니다\n", "# Phraser() 를 사용하는 이유는 Phrases() 의 메모리 차지를 줄입니다\n", "\n", "from gensim.models.phrases import Phrases, Phraser\n", "phrases = Phrases(sent, min_count=30, progress_per=10000)\n", "bigram = Phraser(phrases)\n", "sentences = bigram[sent]\n", "sentences" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **3 빈도 수의 계산 및 모델링**\n", "Mainly a sanity check of the effectiveness of the lemmatization, removal of stopwords, and addition of bigrams." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "29643\n" ] }, { "data": { "text/plain": [ "['oh', 'like', 'know', 'get', 'hey', 'think', 'right', 'look', 'want', 'come']" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from collections import defaultdict\n", "\n", "word_freq = defaultdict(int)\n", "for sent in sentences:\n", " for i in sent:\n", " word_freq[i] += 1\n", "print(len(word_freq))\n", "sorted(word_freq, key=word_freq.get, reverse=True)[:10]\n", "# \" // \".join(word_freq.keys())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **4 W2V 모델의 학습**\n", "Gensim 에 내장된 **[word2vec](https://radimrehurek.com/gensim/models/word2vec.html)** 로 학습 합니다. 3 단계로 구분한 뒤 단계별 모니터링 하면서 작업을 진행 합니다.\n", "1. Word2Vec():\n", "\n", " 이 첫 번째 단계에서는 모델의 매개 변수를 하나씩 설정합니다.\n", " 매개 변수 문장을 제공하지 않으므로 의도적으로 모델을 초기화하지 않은 상태로 둡니다.\n", "\n", "1. .build_vocab():\n", "\n", " 여기에서는 일련의 문장으로 어휘를 구성하여 모델을 초기화했습니다.\n", " 로깅을 통해 단어 진행에 대한 min_count 및 sample의 효과와 진행 상황을 더 중요하게 따를 수 있습니다. \n", " 특히 샘플은 모델의 성능에 큰 영향을 미치는 것으로 나타났습니다.\n", " \n", "1. .train():\n", "\n", " Finally, trains the model.\n", " The loggings here are mainly useful for monitoring, making sure that no threads are executed instantaneously.\n", " \n", "개별 Parametor 는 다음과 같습니다.\n", "1. **min_count = int :** Ignores all words with total absolute frequency lower than this - (2, 100)\n", "1. **window = int :** The maximum distance between the current and predicted word within a sentence. E.g. window words on the left and window words on the left of our target - (2, 10)\n", "1. **size = int :** Dimensionality of the feature vectors. - (50, 300)\n", "1. **sample = float :** The threshold for configuring which higher-frequency words are randomly downsampled. Highly influencial. - (0, 1e-5)\n", "1. **alpha = float :** The initial learning rate - (0.01, 0.05)\n", "1. **min_alpha = float :** Learning rate will linearly drop to min_alpha as training progresses. To set it: alpha - (min_alpha * epochs) ~ 0.00\n", "1. **negative = int :** If > 0, negative sampling will be used, the int for negative specifies how many \"noise words\" should be drown. If set to 0, no negative sampling is used. - (5, 20)\n", "1. **workers = int :** Use these many worker threads to train the model (=faster training with multicore machines)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import multiprocessing\n", "# 컴퓨터에서 연산 가능한 core 숫자를 호출 합니다\n", "cores = multiprocessing.cpu_count() \n", "cores" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO - 15:35:58: collecting all words and their counts\n", "INFO - 15:35:58: PROGRESS: at sentence #0, processed 0 words, keeping 0 word types\n", "INFO - 15:35:58: PROGRESS: at sentence #10000, processed 61706 words, keeping 9491 word types\n", "INFO - 15:35:59: PROGRESS: at sentence #20000, processed 127342 words, keeping 14373 word types\n", "INFO - 15:35:59: PROGRESS: at sentence #30000, processed 187807 words, keeping 17431 word types\n", "INFO - 15:35:59: PROGRESS: at sentence #40000, processed 243316 words, keeping 20124 word types\n", "INFO - 15:35:59: PROGRESS: at sentence #50000, processed 303167 words, keeping 22558 word types\n", "INFO - 15:35:59: PROGRESS: at sentence #60000, processed 363915 words, keeping 24804 word types\n", "INFO - 15:36:00: PROGRESS: at sentence #70000, processed 425375 words, keeping 26960 word types\n", "INFO - 15:36:00: PROGRESS: at sentence #80000, processed 485514 words, keeping 28777 word types\n", "INFO - 15:36:00: collected 29643 word types from a corpus of 523645 raw words and 85960 sentences\n", "INFO - 15:36:00: Loading a fresh vocabulary\n", "INFO - 15:36:00: effective_min_count=20 retains 3315 unique words (11% of original 29643, drops 26328)\n", "INFO - 15:36:00: effective_min_count=20 leaves 437848 word corpus (83% of original 523645, drops 85797)\n", "INFO - 15:36:00: deleting the raw counts dictionary of 29643 items\n", "INFO - 15:36:00: sample=6e-05 downsamples 1204 most-common words\n", "INFO - 15:36:00: downsampling leaves estimated 199419 word corpus (45.5% of prior 437848)\n", "INFO - 15:36:00: estimated required memory for 3315 words and 300 dimensions: 9613500 bytes\n", "INFO - 15:36:00: resetting layer weights\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Time to build vocab: 0.04 mins\n" ] } ], "source": [ "from gensim.models import Word2Vec\n", "w2v_model = Word2Vec(min_count=20, window=2, size=300, sample=6e-5, \n", " alpha=0.03, min_alpha=0.0007, negative=20, workers=cores-1)\n", "\n", "# Building the Vocabulary Table\n", "# Word2Vec requires us to build the vocabulary table \n", "# (simply digesting all the words and filtering out the unique words, and doing some basic counts on them)\n", "t = time()\n", "w2v_model.build_vocab(sentences, progress_per=10000)\n", "print('Time to build vocab: {} mins'.format(round((time() - t) / 60, 2)))" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO - 15:36:00: training model with 3 workers on 3315 vocabulary and 300 features, using sg=0 hs=0 sample=6e-05 negative=20 window=2\n", "INFO - 15:36:01: EPOCH 1 - PROGRESS: at 39.39% examples, 78203 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:02: EPOCH 1 - PROGRESS: at 86.15% examples, 84963 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:02: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:02: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:02: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:02: EPOCH - 1 : training on 523645 raw words (199755 effective words) took 2.3s, 86796 effective words/s\n", "INFO - 15:36:03: EPOCH 2 - PROGRESS: at 45.82% examples, 90257 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:05: EPOCH 2 - PROGRESS: at 88.13% examples, 85172 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:05: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:05: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:05: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:05: EPOCH - 2 : training on 523645 raw words (198855 effective words) took 2.3s, 86358 effective words/s\n", "INFO - 15:36:06: EPOCH 3 - PROGRESS: at 41.54% examples, 82756 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:07: EPOCH 3 - PROGRESS: at 84.22% examples, 82341 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:07: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:07: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:07: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:07: EPOCH - 3 : training on 523645 raw words (199333 effective words) took 2.4s, 83467 effective words/s\n", "INFO - 15:36:08: EPOCH 4 - PROGRESS: at 43.69% examples, 86246 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:09: EPOCH 4 - PROGRESS: at 90.04% examples, 87661 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:09: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:09: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:09: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:09: EPOCH - 4 : training on 523645 raw words (199442 effective words) took 2.3s, 88133 effective words/s\n", "INFO - 15:36:10: EPOCH 5 - PROGRESS: at 43.69% examples, 85630 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:11: EPOCH 5 - PROGRESS: at 90.04% examples, 88778 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:12: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:12: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:12: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:12: EPOCH - 5 : training on 523645 raw words (199772 effective words) took 2.2s, 89311 effective words/s\n", "INFO - 15:36:13: EPOCH 6 - PROGRESS: at 43.69% examples, 86464 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:14: EPOCH 6 - PROGRESS: at 88.13% examples, 86912 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:14: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:14: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:14: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:14: EPOCH - 6 : training on 523645 raw words (199674 effective words) took 2.3s, 88173 effective words/s\n", "INFO - 15:36:15: EPOCH 7 - PROGRESS: at 43.69% examples, 87081 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:16: EPOCH 7 - PROGRESS: at 90.04% examples, 88962 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:16: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:16: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:16: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:16: EPOCH - 7 : training on 523645 raw words (199235 effective words) took 2.2s, 90257 effective words/s\n", "INFO - 15:36:17: EPOCH 8 - PROGRESS: at 43.69% examples, 84497 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:18: EPOCH 8 - PROGRESS: at 90.04% examples, 88015 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:18: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:18: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:18: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:18: EPOCH - 8 : training on 523645 raw words (199529 effective words) took 2.2s, 89366 effective words/s\n", "INFO - 15:36:19: EPOCH 9 - PROGRESS: at 45.82% examples, 87895 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:20: EPOCH 9 - PROGRESS: at 90.04% examples, 87242 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:21: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:21: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:21: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:21: EPOCH - 9 : training on 523645 raw words (198889 effective words) took 2.2s, 88585 effective words/s\n", "INFO - 15:36:22: EPOCH 10 - PROGRESS: at 45.82% examples, 89262 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:23: EPOCH 10 - PROGRESS: at 91.99% examples, 90315 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:23: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:23: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:23: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:23: EPOCH - 10 : training on 523645 raw words (199127 effective words) took 2.2s, 90887 effective words/s\n", "INFO - 15:36:24: EPOCH 11 - PROGRESS: at 41.54% examples, 82666 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:25: EPOCH 11 - PROGRESS: at 90.04% examples, 88063 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:25: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:25: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:25: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:25: EPOCH - 11 : training on 523645 raw words (199146 effective words) took 2.2s, 88544 effective words/s\n", "INFO - 15:36:26: EPOCH 12 - PROGRESS: at 41.54% examples, 82819 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:27: EPOCH 12 - PROGRESS: at 86.15% examples, 85256 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:27: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:27: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:27: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:27: EPOCH - 12 : training on 523645 raw words (199233 effective words) took 2.3s, 85932 effective words/s\n", "INFO - 15:36:29: EPOCH 13 - PROGRESS: at 47.89% examples, 91893 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:30: EPOCH 13 - PROGRESS: at 93.83% examples, 90291 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:30: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:30: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:30: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:30: EPOCH - 13 : training on 523645 raw words (199783 effective words) took 2.2s, 90916 effective words/s\n", "INFO - 15:36:31: EPOCH 14 - PROGRESS: at 45.82% examples, 88879 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:32: EPOCH 14 - PROGRESS: at 93.83% examples, 91737 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:32: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:32: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:32: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:32: EPOCH - 14 : training on 523645 raw words (199586 effective words) took 2.2s, 91999 effective words/s\n", "INFO - 15:36:33: EPOCH 15 - PROGRESS: at 39.39% examples, 79193 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:34: EPOCH 15 - PROGRESS: at 88.13% examples, 85931 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:34: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:34: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:34: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:34: EPOCH - 15 : training on 523645 raw words (199069 effective words) took 2.3s, 87451 effective words/s\n", "INFO - 15:36:35: EPOCH 16 - PROGRESS: at 45.82% examples, 86120 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:36: EPOCH 16 - PROGRESS: at 90.04% examples, 86970 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:36: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:36: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:36: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:36: EPOCH - 16 : training on 523645 raw words (199228 effective words) took 2.3s, 87862 effective words/s\n", "INFO - 15:36:37: EPOCH 17 - PROGRESS: at 43.69% examples, 86403 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:38: EPOCH 17 - PROGRESS: at 90.04% examples, 88756 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:39: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:39: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:39: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:39: EPOCH - 17 : training on 523645 raw words (199507 effective words) took 2.2s, 89617 effective words/s\n", "INFO - 15:36:40: EPOCH 18 - PROGRESS: at 41.54% examples, 80584 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:41: EPOCH 18 - PROGRESS: at 90.04% examples, 87118 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:41: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:41: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:41: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:41: EPOCH - 18 : training on 523645 raw words (199602 effective words) took 2.3s, 88206 effective words/s\n", "INFO - 15:36:42: EPOCH 19 - PROGRESS: at 45.82% examples, 89088 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:43: EPOCH 19 - PROGRESS: at 90.04% examples, 87161 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:43: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:43: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:43: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:43: EPOCH - 19 : training on 523645 raw words (199656 effective words) took 2.3s, 88199 effective words/s\n", "INFO - 15:36:44: EPOCH 20 - PROGRESS: at 45.82% examples, 88658 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:45: EPOCH 20 - PROGRESS: at 91.99% examples, 89779 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:45: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:45: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:45: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:45: EPOCH - 20 : training on 523645 raw words (199528 effective words) took 2.2s, 90283 effective words/s\n", "INFO - 15:36:46: EPOCH 21 - PROGRESS: at 41.54% examples, 82527 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:47: EPOCH 21 - PROGRESS: at 90.04% examples, 87982 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:48: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:48: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:48: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:48: EPOCH - 21 : training on 523645 raw words (199284 effective words) took 2.2s, 89021 effective words/s\n", "INFO - 15:36:49: EPOCH 22 - PROGRESS: at 41.54% examples, 82536 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:50: EPOCH 22 - PROGRESS: at 86.15% examples, 84963 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:50: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:50: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:50: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:50: EPOCH - 22 : training on 523645 raw words (198940 effective words) took 2.3s, 86840 effective words/s\n", "INFO - 15:36:51: EPOCH 23 - PROGRESS: at 45.82% examples, 88984 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:52: EPOCH 23 - PROGRESS: at 90.04% examples, 87060 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:52: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:52: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:52: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:52: EPOCH - 23 : training on 523645 raw words (199452 effective words) took 2.3s, 87866 effective words/s\n", "INFO - 15:36:53: EPOCH 24 - PROGRESS: at 43.69% examples, 84958 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:54: EPOCH 24 - PROGRESS: at 90.04% examples, 87942 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:54: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:54: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:54: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:55: EPOCH - 24 : training on 523645 raw words (199363 effective words) took 2.2s, 88733 effective words/s\n", "INFO - 15:36:56: EPOCH 25 - PROGRESS: at 41.54% examples, 82595 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:36:57: EPOCH 25 - PROGRESS: at 90.04% examples, 88227 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:57: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:57: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:57: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:57: EPOCH - 25 : training on 523645 raw words (199378 effective words) took 2.3s, 88375 effective words/s\n", "INFO - 15:36:58: EPOCH 26 - PROGRESS: at 41.54% examples, 79913 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:59: EPOCH 26 - PROGRESS: at 86.15% examples, 82995 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:36:59: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:36:59: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:36:59: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:36:59: EPOCH - 26 : training on 523645 raw words (199376 effective words) took 2.4s, 84789 effective words/s\n", "INFO - 15:37:00: EPOCH 27 - PROGRESS: at 41.54% examples, 81776 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:37:01: EPOCH 27 - PROGRESS: at 86.15% examples, 84585 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:37:01: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:37:01: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:37:01: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:37:01: EPOCH - 27 : training on 523645 raw words (199427 effective words) took 2.3s, 85989 effective words/s\n", "INFO - 15:37:02: EPOCH 28 - PROGRESS: at 45.82% examples, 90238 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:37:04: EPOCH 28 - PROGRESS: at 91.99% examples, 89660 words/s, in_qsize 1, out_qsize 0\n", "INFO - 15:37:04: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:37:04: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:37:04: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:37:04: EPOCH - 28 : training on 523645 raw words (199613 effective words) took 2.2s, 90478 effective words/s\n", "INFO - 15:37:05: EPOCH 29 - PROGRESS: at 41.54% examples, 81478 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:37:06: EPOCH 29 - PROGRESS: at 90.04% examples, 87387 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:37:06: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:37:06: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:37:06: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:37:06: EPOCH - 29 : training on 523645 raw words (199377 effective words) took 2.3s, 88449 effective words/s\n", "INFO - 15:37:07: EPOCH 30 - PROGRESS: at 43.69% examples, 84277 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:37:08: EPOCH 30 - PROGRESS: at 88.13% examples, 84638 words/s, in_qsize 0, out_qsize 0\n", "INFO - 15:37:08: worker thread finished; awaiting finish of 2 more threads\n", "INFO - 15:37:08: worker thread finished; awaiting finish of 1 more threads\n", "INFO - 15:37:08: worker thread finished; awaiting finish of 0 more threads\n", "INFO - 15:37:08: EPOCH - 30 : training on 523645 raw words (199395 effective words) took 2.3s, 86538 effective words/s\n", "INFO - 15:37:08: training on a 15709350 raw words (5981554 effective words) took 68.1s, 87845 effective words/s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Time to train the model: 1.13 mins\n" ] } ], "source": [ "# Training of the model (Parameters of the training)\n", "# total_examples = int : Count of sentences\n", "# epochs = int : Number of iterations (epochs) over the corpus - [10, 20, 30]\n", "t = time()\n", "w2v_model.train(sentences, total_examples=w2v_model.corpus_count, epochs=30, report_delay=1)\n", "print('Time to train the model: {} mins'.format(round((time() - t) / 60, 2)))" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO - 15:37:08: precomputing L2-norms of word weight vectors\n" ] } ], "source": [ "# 추가로 학습하지 않을 경우 init_sims()을 호출하여 메모리 효율을 높입니다.\n", "# which will make the model much more memory-efficient:\n", "w2v_model.init_sims(replace=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **5 W2V 학습한 모델 살펴보기**\n", "앞에서 학습이 완료된 모델을 저장 및 활용할 수 있습니다." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('depressed', 0.800049901008606),\n", " ('sweetheart', 0.7771680355072021),\n", " ('snuggle', 0.7697296142578125),\n", " ('marge', 0.7636249661445618),\n", " ('terrific', 0.7587988376617432),\n", " ('good_friend', 0.7575525045394897),\n", " ('gee', 0.7561341524124146),\n", " ('hammock', 0.7530875205993652),\n", " ('feel_well', 0.7504291534423828),\n", " ('becky', 0.7494775652885437)]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 메인 캐릭터 호머와 연관성 높은 단어들을 호출 합니다\n", "w2v_model.wv.most_similar(positive=[\"homer\"])\n", "# w2v_model.wv.most_similar(positive=[\"marge\"])\n", "# w2v_model.wv.most_similar(positive=[\"bart\"])" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('united_state', 0.785035252571106),\n", " ('congratulation', 0.7744359374046326),\n", " ('select', 0.773761510848999),\n", " ('pleased', 0.7718425989151001),\n", " ('council', 0.7696194648742676),\n", " ('aboard', 0.7508918046951294),\n", " ('recent', 0.748868465423584),\n", " ('robert', 0.7483236789703369),\n", " ('governor', 0.7412874698638916),\n", " ('easily', 0.7393561601638794)]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# bi_gram 인 호머심슨을 대상으로 확인 합니다\n", "w2v_model.wv.most_similar(positive=[\"homer_simpson\"])" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.72318304" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 단어간 유사도를 측정 합니다.\n", "# w2v_model.wv.similarity(\"moe_'s\", 'tavern')\n", "w2v_model.wv.similarity('maggie', 'baby')" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.66021216" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w2v_model.wv.similarity('bart', 'nelson')" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/markbaum/Python/nltk/lib/python3.6/site-packages/gensim/models/keyedvectors.py:877: FutureWarning: arrays to stack must be passed as a \"sequence\" type such as list or tuple. Support for non-sequence iterables such as generators is deprecated as of NumPy 1.16 and will raise an error in the future.\n", " vectors = vstack(self.word_vec(word, use_norm=True) for word in used_words).astype(REAL)\n" ] }, { "data": { "text/plain": [ "'nelson'" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 단어들 중 연관성이 낮은 단어를 선별 합니다.\n", "# w2v_model.wv.doesnt_match(['jimbo', 'milhouse', 'kearney'])\n", "w2v_model.wv.doesnt_match([\"nelson\", \"bart\", \"milhouse\"])" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('see', 0.6492701768875122),\n", " ('admire', 0.6330732107162476),\n", " ('care', 0.627632737159729)]" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w2v_model.wv.most_similar(positive=[\"woman\", \"homer\"], negative=[\"marge\"], topn=3)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('lisa', 0.7655842304229736),\n", " ('hearing', 0.6929087042808533),\n", " ('parent', 0.6803374290466309)]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w2v_model.wv.most_similar(positive=[\"woman\", \"bart\"], negative=[\"man\"], topn=3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **6 t-sne 를 활용한 시각화**\n", "학습한 모델을 보다 포괄적으로 검증 가능한, 시각화 방법을 활용 합니다" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt \n", "import seaborn as sns\n", "sns.set_style(\"darkgrid\")\n", "from sklearn.decomposition import PCA\n", "from sklearn.manifold import TSNE\n", "\n", "def tsnescatterplot(model, word, list_names):\n", " \"\"\" Plot in seaborn the results from the t-SNE dimensionality reduction algorithm of the vectors of a query word,\n", " its list of most similar words, and a list of words.\"\"\"\n", " arrays = np.empty((0, 300), dtype='f')\n", " word_labels = [word]\n", " color_list = ['red']\n", " # adds the vector of the query word\n", " arrays = np.append(arrays, model.wv.__getitem__([word]), axis=0)\n", " # gets list of most similar words\n", " close_words = model.wv.most_similar([word])\n", " # adds the vector for each of the closest words to the array\n", " for wrd_score in close_words:\n", " wrd_vector = model.wv.__getitem__([wrd_score[0]])\n", " word_labels.append(wrd_score[0])\n", " color_list.append('blue')\n", " arrays = np.append(arrays, wrd_vector, axis=0)\n", " # adds the vector for each of the words from list_names to the array\n", " for wrd in list_names:\n", " wrd_vector = model.wv.__getitem__([wrd])\n", " word_labels.append(wrd)\n", " color_list.append('green')\n", " arrays = np.append(arrays, wrd_vector, axis=0)\n", " # Reduces the dimensionality from 300 to 50 dimensions with PCA\n", " reduc = PCA(n_components=15).fit_transform(arrays)\n", " # Finds t-SNE coordinates for 2 dimensions\n", " np.set_printoptions(suppress=True)\n", " Y = TSNE(n_components=2, random_state=0, perplexity=15).fit_transform(reduc)\n", " # Sets everything up to plot\n", " df = pd.DataFrame({'x': [x for x in Y[:, 0]],\n", " 'y': [y for y in Y[:, 1]],\n", " 'words': word_labels, 'color': color_list})\n", " fig, _ = plt.subplots()\n", " fig.set_size_inches(9, 9) \n", " # Basic plot\n", " p1 = sns.regplot(data=df, x=\"x\", y=\"y\", fit_reg=False, marker=\"o\",\n", " scatter_kws={'s': 40,'facecolors': df['color']}) \n", " # Adds annotations one by one with a loop\n", " for line in range(0, df.shape[0]):\n", " p1.text(df[\"x\"][line], df['y'][line],\n", " ' ' + df[\"words\"][line].title(),\n", " horizontalalignment = 'left',\n", " verticalalignment = 'bottom', size='medium',\n", " color=df['color'][line], weight='normal').set_size(15)\n", " plt.xlim(Y[:, 0].min()-50, Y[:, 0].max()+50)\n", " plt.ylim(Y[:, 1].min()-50, Y[:, 1].max()+50)\n", " plt.title('t-SNE visualization for {}'.format(word.title()))" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "tsnescatterplot(w2v_model, 'homer', \n", " ['dog', 'bird', 'ah', 'maude', 'bob', 'mel', 'apu', 'duff'])" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.3" } }, "nbformat": 4, "nbformat_minor": 4 }