diff --git "a/Euron_Week12_\352\260\234\353\205\220\354\240\225\353\246\254.pdf" "b/Euron_Week12_\352\260\234\353\205\220\354\240\225\353\246\254.pdf" new file mode 100644 index 0000000..5a92ee3 Binary files /dev/null and "b/Euron_Week12_\352\260\234\353\205\220\354\240\225\353\246\254.pdf" differ diff --git "a/Euron_Week12_\354\230\210\354\212\265.ipynb" "b/Euron_Week12_\354\230\210\354\212\265.ipynb" new file mode 100644 index 0000000..6a2f524 --- /dev/null +++ "b/Euron_Week12_\354\230\210\354\212\265.ipynb" @@ -0,0 +1,1977 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "## **텍스트 분석**" + ], + "metadata": { + "id": "8pUTwBbdfvt3" + } + }, + { + "cell_type": "markdown", + "source": [ + "### 1. 텍스트 정규화" + ], + "metadata": { + "id": "RMzxwhqrTIr7" + } + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "mQ0yjKhCSsTi", + "outputId": "7bcd1a2e-759e-4ddd-f226-f1892852ad1e" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "[nltk_data] Downloading package punkt to /root/nltk_data...\n", + "[nltk_data] Unzipping tokenizers/punkt.zip.\n", + "[nltk_data] Downloading package punkt_tab to /root/nltk_data...\n", + "[nltk_data] Unzipping tokenizers/punkt_tab.zip.\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + " 3\n", + "['The Matrix is everywhere its all around us, here even in this room.', 'You can see it out your window or on your television.', 'You feel it when you go to work, or go to church or pay your taxes.']\n" + ] + } + ], + "source": [ + "# 1. 텍스트 샘플(Text Sample) 로드 및 문장 토큰화(Sentence Tokenization)\n", + "# 자연어 처리 라이브러리인 NLTK를 활용하여 텍스트를 문장 단위로 분할하고 결과를 확인합니다.\n", + "\n", + "import nltk\n", + "from nltk import sent_tokenize\n", + "\n", + "# 토큰화에 필요한 자원(Resource) 다운로드\n", + "nltk.download('punkt')\n", + "nltk.download('punkt_tab')\n", + "\n", + "# 분석할 텍스트 샘플 정의\n", + "text_sample = 'The Matrix is everywhere its all around us, here even in this room. \\\n", + " You can see it out your window or on your television. \\\n", + " You feel it when you go to work, or go to church or pay your taxes.'\n", + "\n", + "# NLTK의 sent_tokenize를 이용해 문장 토큰화 수행\n", + "sentences = sent_tokenize(text=text_sample)\n", + "\n", + "# 생성된 토큰 리스트의 자료형(Type) 및 문장 개수(Length) 출력하여 구조 확인\n", + "print(type(sentences), len(sentences))\n", + "\n", + "# 분할된 문장 데이터 전체 출력\n", + "print(sentences)" + ] + }, + { + "cell_type": "code", + "source": [ + "# 2. 문장 데이터 로드 및 단어 토큰화(Word Tokenization)\n", + "# NLTK 라이브러리를 활용하여 단일 문장을 단어(Word) 단위로 분할하고 구조를 확인합니다.\n", + "\n", + "from nltk import word_tokenize\n", + "\n", + "# 분석할 문장 샘플 정의\n", + "sentence = \"The Matrix is everywhere its all around us, here even in this room.\"\n", + "\n", + "# NLTK의 word_tokenize를 이용해 단어 토큰화 수행\n", + "words = word_tokenize(sentence)\n", + "\n", + "# 생성된 토큰 리스트의 자료형(Type) 및 단어 개수(Length) 출력하여 구조 확인\n", + "print(type(words), len(words))\n", + "\n", + "# 분할된 단어 데이터 전체 출력\n", + "print(words)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "QQJhNXavTUbU", + "outputId": "857e6659-6e7a-4746-e654-d5c0603de84a" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " 15\n", + "['The', 'Matrix', 'is', 'everywhere', 'its', 'all', 'around', 'us', ',', 'here', 'even', 'in', 'this', 'room', '.']\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 3. 문서 데이터 로드 및 종합 토큰화(Text Tokenization) 함수 구현\n", + "# 텍스트 샘플을 문장별로 먼저 분할한 후, 각 문장을 다시 단어 단위로 토큰화하는 함수를 정의하고 검증합니다.\n", + "\n", + "from nltk import word_tokenize, sent_tokenize\n", + "\n", + "# 여러 개의 문장으로 된 입력 데이터를 문장별로 단어 토큰화하는 사용자 정의 함수 생성\n", + "def tokenize_text(text):\n", + "\n", + " # 입력된 텍스트를 문장별로 분리(Sentence Tokenization)\n", + " sentences = sent_tokenize(text)\n", + "\n", + " # 분리된 각 문장별로 단어 토큰화(Word Tokenization) 수행 후 리스트로 저장\n", + " word_tokens = [word_tokenize(sentence) for sentence in sentences]\n", + " return word_tokens\n", + "\n", + "# 여러 문장에 대해 문장별 단어 토큰화 수행\n", + "word_tokens = tokenize_text(text_sample)\n", + "\n", + "# 생성된 2차원 리스트의 자료형(Type) 및 문장 개수(Length) 출력하여 구조 확인\n", + "print(type(word_tokens), len(word_tokens))\n", + "\n", + "# 문장별로 분할된 단어 토큰 데이터 전체 출력 (2차원 리스트 형태)\n", + "print(word_tokens)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "RVxijaXUUAfM", + "outputId": "c47e0fb3-9940-4b81-9c59-fe224c89d11b" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " 3\n", + "[['The', 'Matrix', 'is', 'everywhere', 'its', 'all', 'around', 'us', ',', 'here', 'even', 'in', 'this', 'room', '.'], ['You', 'can', 'see', 'it', 'out', 'your', 'window', 'or', 'on', 'your', 'television', '.'], ['You', 'feel', 'it', 'when', 'you', 'go', 'to', 'work', ',', 'or', 'go', 'to', 'church', 'or', 'pay', 'your', 'taxes', '.']]\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 4. NLTK 불용어(Stopwords) 데이터 세트 다운로드\n", + "# 텍스트 전처리 과정에서 의미가 없는 단어를 제거하기 위해 NLTK가 제공하는 불용어 사전을 불러옵니다.\n", + "\n", + "import nltk\n", + "\n", + "# 영어, 한국어 등 다양한 언어의 불용어 사전 자원(Resource) 다운로드\n", + "nltk.download('stopwords')" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "fW_ILC9FURN7", + "outputId": "e1fb6732-74f4-4a58-f965-112649562694" + }, + "execution_count": 5, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "[nltk_data] Downloading package stopwords to /root/nltk_data...\n", + "[nltk_data] Unzipping corpora/stopwords.zip.\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "True" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 5. 영어 불용어(Stopwords) 데이터 세트 구조 및 샘플 확인\n", + "# NLTK에 내장된 영어 불용어의 전체 개수를 확인하고, 상위 20개 샘플을 출력하여 데이터를 파악합니다.\n", + "\n", + "# 등록된 영어 불용어(Stopwords)의 전체 개수(Length) 출력\n", + "print('영어 stop words 개수:', len(nltk.corpus.stopwords.words('english')))\n", + "\n", + "# 영어 불용어 목록 중 상위 20개 단어(Row)를 출력하여 구조 확인\n", + "print(nltk.corpus.stopwords.words('english')[:20])" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-w6haR3ZUTO2", + "outputId": "5a25f07e-28f2-4e6e-e683-2d38faba9a26" + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "영어 stop words 개수: 198\n", + "['a', 'about', 'above', 'after', 'again', 'against', 'ain', 'all', 'am', 'an', 'and', 'any', 'are', 'aren', \"aren't\", 'as', 'at', 'be', 'because', 'been']\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 6. 불용어(Stopwords) 제거를 통한 단어 필터링 전처리\n", + "# 앞서 생성한 문장별 단어 토큰 리스트에서 영어 불용어를 제거하고 실질적인 의미를 가진 단어만 추출합니다.\n", + "\n", + "import nltk\n", + "\n", + "# NLTK 영어 불용어(Stopwords) 목록 로드\n", + "stopwords = nltk.corpus.stopwords.words('english')\n", + "all_tokens = []\n", + "\n", + "# 3개의 문장별로 분할된 word_tokens 리스트를 순회하며 불용어 제거 반복문 수행\n", + "for sentence in word_tokens:\n", + " filtered_words = []\n", + "\n", + " # 개별 문장 내의 토큰화된 단어 리스트를 순회\n", + " for word in sentence:\n", + " # 대소문자 구분을 없애기 위해 소문자로 모두 변환(Lowercasing)\n", + " word = word.lower()\n", + "\n", + " # 토큰화된 개별 단어가 영어 불용어 목록에 포함되지 않는 경우에만 추출\n", + " if word not in stopwords:\n", + " filtered_words.append(word)\n", + "\n", + " # 불용어가 제거된 단어 리스트를 최종 토큰 리스트에 추가\n", + " all_tokens.append(filtered_words)\n", + "\n", + "# 불용어가 정제된 문장별 단어 토큰 데이터 전체 출력하여 구조 확인\n", + "print(all_tokens)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "dtZJy7u7UZ9o", + "outputId": "6fd1bc19-2bce-43ae-f90f-e02e6c89fc75" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[['matrix', 'everywhere', 'around', 'us', ',', 'even', 'room', '.'], ['see', 'window', 'television', '.'], ['feel', 'go', 'work', ',', 'go', 'church', 'pay', 'taxes', '.']]\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 7. 어간 추출(Stemming) 모델을 활용한 단어 원형 추출\n", + "# LancasterStemmer를 이용하여 다양한 형태로 변형된 단어들의 어간(Stem)을 추출하고 결과를 비교합니다.\n", + "\n", + "from nltk.stem import LancasterStemmer\n", + "\n", + "# LancasterStemmer 객체 생성\n", + "stemmer = LancasterStemmer()\n", + "\n", + "# 'work' 관련 동사 변형들의 어간 추출 결과 출력\n", + "print(stemmer.stem('working'), stemmer.stem('works'), stemmer.stem('worked'))\n", + "\n", + "# 'amuse' 관련 동사 변형들의 어간 추출 결과 출력\n", + "print(stemmer.stem('amusing'), stemmer.stem('amuses'), stemmer.stem('amused'))\n", + "\n", + "# 'happy' 관련 형용사 비교급/최상급 변형들의 어간 추출 결과 출력\n", + "print(stemmer.stem('happier'), stemmer.stem('happiest'))\n", + "\n", + "# 'fancy' 관련 형용사 비교급/최상급 변형들의 어간 추출 결과 출력하여 구조 확인\n", + "print(stemmer.stem('fancier'), stemmer.stem('fanciest'))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8ppfMZmoU1SC", + "outputId": "df1c731e-5772-4a2b-e442-6d7088df66ea" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "work work work\n", + "amus amus amus\n", + "happy happiest\n", + "fant fanciest\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 8. 표제어 추출(Lemmatization) 모델을 활용한 단어 원형 복원\n", + "# WordNetLemmatizer를 활용하여 단어의 품사(POS) 정보를 기반으로 정확한 표제어(Lemma)를 추출합니다.\n", + "\n", + "import nltk\n", + "from nltk.stem import WordNetLemmatizer\n", + "\n", + "# 표제어 추출에 필요한 WordNet 데이터 세트(Resource) 다운로드\n", + "nltk.download('wordnet')\n", + "\n", + "# WordNetLemmatizer 객체 생성\n", + "lemma = WordNetLemmatizer()\n", + "\n", + "# 동사('v') 품사 정보를 지정하여 'amuse' 관련 단어들의 표제어 추출 결과 출력\n", + "print(lemma.lemmatize('amusing', 'v'), lemma.lemmatize('amuses', 'v'), lemma.lemmatize('amused', 'v'))\n", + "\n", + "# 형용사('a') 품사 정보를 지정하여 'happy' 관련 단어들의 표제어 추출 결과 출력\n", + "print(lemma.lemmatize('happier', 'a'), lemma.lemmatize('happiest', 'a'))\n", + "\n", + "# 형용사('a') 품사 정보를 지정하여 'fancy' 관련 단어들의 표제어 추출 결과 출력하여 구조 확인\n", + "print(lemma.lemmatize('fancier', 'a'), lemma.lemmatize('fanciest', 'a'))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "21ukCWsNU_PY", + "outputId": "6090a79d-d54e-4a42-de73-94e7b65956bd" + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "[nltk_data] Downloading package wordnet to /root/nltk_data...\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "amuse amuse amuse\n", + "happy happy\n", + "fancy fancy\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 2. Bag of Words - BOW" + ], + "metadata": { + "id": "EVFM5d11VWRL" + } + }, + { + "cell_type": "code", + "source": [ + "# 1. 넘파이(NumPy) 기반 밀집 행렬(Dense Matrix) 생성 및 데이터 정의\n", + "# 희소 행렬 변환을 수행하기 전, 다차원 배열을 활용하여 기본 밀집 행렬의 구조를 정의합니다.\n", + "\n", + "import numpy as np\n", + "\n", + "# 2행 3열 구조의 2차원 밀집 행렬 데이터 생성\n", + "dense = np.array([[3, 0, 1], [0, 2, 0]])" + ], + "metadata": { + "id": "1n-6Scc-VUe8" + }, + "execution_count": 10, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 2. COO(Coordinate) 형식을 활용한 희소 행렬(Sparse Matrix) 생성\n", + "# SciPy 라이브러리의 coo_matrix를 사용하여 0이 아닌 데이터와 해당 위치(행, 열) 정보를 기반으로 희소 행렬을 구조화합니다.\n", + "\n", + "from scipy import sparse\n", + "\n", + "# 0이 아닌 실제 데이터 값(Data) 배열 생성\n", + "data = np.array([3, 1, 2])\n", + "\n", + "# 데이터가 위치한 행 인덱스(Row Position)와 열 인덱스(Column Position) 배열을 각각 생성\n", + "row_pos = np.array([0, 0, 1])\n", + "col_pos = np.array([0, 2, 1])\n", + "\n", + "# SciPy의 coo_matrix를 이용하여 COO 형식의 희소 행렬 변환 수행\n", + "sparse_coo = sparse.coo_matrix((data, (row_pos, col_pos)))" + ], + "metadata": { + "id": "BYPUYKoJVg57" + }, + "execution_count": 11, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 3. 희소 행렬(Sparse Matrix)의 밀집 행렬(Dense Matrix) 변환 및 구조 확인\n", + "# COO 형식으로 압축된 희소 행렬을 toarray() 메서드를 통해 다시 원래의 넘파이 배열로 복원합니다.\n", + "\n", + "# COO 형식의 희소 행렬을 일반 다차원 넘파이 배열(Array) 형태로 변환하여 출력\n", + "sparse_coo.toarray()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "4A469JXuVmU8", + "outputId": "5e25a6fc-1246-41d0-9947-95834c444b06" + }, + "execution_count": 12, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "array([[3, 0, 1],\n", + " [0, 2, 0]])" + ] + }, + "metadata": {}, + "execution_count": 12 + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 4. COO 및 CSR 형식을 활용한 희소 행렬(Sparse Matrix) 변환 및 검증\n", + "# 6x6 밀집 행렬을 COO 형식과 고유 인덱스 배열을 활용한 CSR 형식으로 각각 변환하고, 원래 배열로 복원하여 정확성을 검증합니다.\n", + "\n", + "import numpy as np\n", + "from scipy import sparse\n", + "\n", + "# 6행 6열 구조의 2차원 밀집 행렬(Dense Matrix) 데이터 정의\n", + "dense2 = np.array([[0, 0, 1, 0, 0, 5],\n", + " [1, 4, 0, 3, 2, 5],\n", + " [0, 6, 0, 3, 0, 0],\n", + " [2, 0, 0, 0, 0, 0],\n", + " [0, 0, 0, 7, 0, 8],\n", + " [1, 0, 0, 0, 0, 0]])\n", + "\n", + "# 행렬 내에서 0이 아닌 실제 데이터 값(Data) 배열 생성\n", + "data2 = np.array([1, 5, 1, 4, 3, 2, 5, 6, 3, 2, 7, 8, 1])\n", + "\n", + "# 데이터가 위치한 행 인덱스(Row Position)와 열 인덱스(Column Position) 배열을 각각 생성\n", + "row_pos = np.array([0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 4, 4, 5])\n", + "coI_pos = np.array([2, 5, 0, 1, 3, 4, 5, 1, 3, 0, 3, 5, 0])\n", + "\n", + "# SciPy의 coo_matrix를 이용하여 COO 형식의 희소 행렬 변환 수행\n", + "sparse_coo = sparse.coo_matrix((data2, (row_pos, coI_pos)))\n", + "\n", + "# 행 위치 배열 내 고유한 값의 시작 위치 인덱스(Row Position Index) 배열 생성 (CSR 압축용)\n", + "row_pos_ind = np.array([0, 2, 7, 9, 10, 12, 13])\n", + "\n", + "# SciPy의 csr_matrix를 이용하여 CSR 형식의 희소 행렬 변환 수행\n", + "sparse_csr = sparse.csr_matrix((data2, coI_pos, row_pos_ind))\n", + "\n", + "# COO 형식으로 변환된 희소 행렬을 다시 밀집 행렬(Dense Matrix)로 복원하여 결과 출력\n", + "print('COO 변환된 데이터가 제대로 되었는지 다시 Dense로 출력 확인')\n", + "print(sparse_coo.toarray())\n", + "\n", + "# CSR 형식으로 변환된 희소 행렬을 다시 밀집 행렬(Dense Matrix)로 복원하여 결과 출력 및 구조 확인\n", + "print('CSR 변환된 데이터가 제대로 되었는지 다시 Dense로 출력 확인')\n", + "print(sparse_csr.toarray())" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "69hfeAnhV9YS", + "outputId": "bc83e992-e602-4813-bcaa-a154e7867b3e" + }, + "execution_count": 13, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "COO 변환된 데이터가 제대로 되었는지 다시 Dense로 출력 확인\n", + "[[0 0 1 0 0 5]\n", + " [1 4 0 3 2 5]\n", + " [0 6 0 3 0 0]\n", + " [2 0 0 0 0 0]\n", + " [0 0 0 7 0 8]\n", + " [1 0 0 0 0 0]]\n", + "CSR 변환된 데이터가 제대로 되었는지 다시 Dense로 출력 확인\n", + "[[0 0 1 0 0 5]\n", + " [1 4 0 3 2 5]\n", + " [0 6 0 3 0 0]\n", + " [2 0 0 0 0 0]\n", + " [0 0 0 7 0 8]\n", + " [1 0 0 0 0 0]]\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 5. SciPy 함수 기반 COO 및 CSR 희소 행렬(Sparse Matrix) 자동 변환\n", + "# 위치 배열을 직접 생성하지 않고, SciPy 내장 함수를 활용하여 밀집 행렬을 COO와 CSR 형식으로 효율적으로 변환합니다.\n", + "\n", + "import numpy as np\n", + "from scipy import sparse\n", + "\n", + "# 6행 6열 구조의 2차원 밀집 행렬(Dense Matrix) 데이터 정의\n", + "dense3 = np.array([[0, 0, 1, 0, 0, 5],\n", + " [1, 4, 0, 3, 2, 5],\n", + " [0, 6, 0, 3, 0, 0],\n", + " [2, 0, 0, 0, 0, 0],\n", + " [0, 0, 0, 7, 0, 8],\n", + " [1, 0, 0, 0, 0, 0]])\n", + "\n", + "# SciPy의 coo_matrix 인터페이스를 통해 밀집 행렬을 COO 형식 희소 행렬로 자동 변환\n", + "coo = sparse.coo_matrix(dense3)\n", + "\n", + "# SciPy의 csr_matrix 인터페이스를 통해 밀집 행렬을 CSR 형식 희소 행렬로 자동 변환하여 구조화\n", + "csr = sparse.csr_matrix(dense3)" + ], + "metadata": { + "id": "_P4y5zPFWBdj" + }, + "execution_count": 14, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 3. 감성 분석" + ], + "metadata": { + "id": "svu6eh11Xhyu" + } + }, + { + "cell_type": "code", + "source": [ + "# 1. 감성 분석(Sentiment Analysis) 데이터 세트 로드 및 데이터프레임 변환\n", + "# 지도학습 기반의 감성 분석 모델 학습을 위해 탭(\\t)으로 구분된 영화 리뷰 데이터를 불러오고 구조를 확인합니다.\n", + "\n", + "import pandas as pd\n", + "\n", + "# 영화 리뷰 데이터 세트 가져오기 (TSV 파일 로드)\n", + "review_df = pd.read_csv('/content/labeledTrainData.tsv', header=0, sep='\\t', quoting=3)\n", + "\n", + "# 생성된 데이터프레임(DataFrame)의 상위 3개 행(Row) 출력하여 데이터 구조 확인\n", + "review_df.head(3)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 143 + }, + "id": "DPGBkDokXRWj", + "outputId": "fb4aa88b-dbd1-4a7c-8a24-293ce0009919" + }, + "execution_count": 16, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " id sentiment review\n", + "0 \"5814_8\" 1 \"With all this stuff going down at the moment ...\n", + "1 \"2381_9\" 1 \"\\\"The Classic War of the Worlds\\\" by Timothy ...\n", + "2 \"7759_3\" 0 \"The film starts with a manager (Nicholas Bell..." + ], + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idsentimentreview
0\"5814_8\"1\"With all this stuff going down at the moment ...
1\"2381_9\"1\"\\\"The Classic War of the Worlds\\\" by Timothy ...
2\"7759_3\"0\"The film starts with a manager (Nicholas Bell...
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "review_df", + "summary": "{\n \"name\": \"review_df\",\n \"rows\": 13923,\n \"fields\": [\n {\n \"column\": \"id\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 13923,\n \"samples\": [\n \"\\\"3552_2\\\"\",\n \"\\\"10354_9\\\"\",\n \"\\\"7326_10\\\"\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"sentiment\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 1,\n \"num_unique_values\": 2,\n \"samples\": [\n 0,\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"review\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 13884,\n \"samples\": [\n \"\\\"Well, What can I say, other than these people are Super in every way. I quite like Sharon Mcreedy, I enjoy this pure Nostalgic Series And I have the boxed set of 9 discs 30 episodes, I did not realise that they had made so many, I also think that it is a great shame, that they have not made any more. I wish that I got given these powers, Imagine me, being knocked off my cycle, somewhere and being knocked out cold, then waking up in a special hospital. Later on, I discover that my body has been enhanced. Just like Richard Barrat. These stories are 50 Minutes of pure action and suspense all the way, You cannot fight these 3 people, as they would defeat you in all forms of weaponry. The music is well written, and to me, puts a wonderful picture of 3 super beings in my mind, The sort of powers that the champions have are the same as our domestic dog or cats, Improved sight, Improved hearing and touch. and the strength of 10 men for Richard and Craig and the strength of 3 women for Sharon. Who I thought was beautiful and intelligent. When I was a boy, I had a huge crush on her!!!! Now I can see why, on my DVD set. The box is very nice and it comes with a free booklet all about the series. I also thought that Trymane was a good boss, firm but he got things done!\\\"\",\n \"\\\"The \\\\\\\"Trivia\\\\\\\" page on IMDb claims the filmmakers protested because this film was re-cut by the studio to \\\\\\\"simplify the plot\\\\\\\". If so, that effort was a total failure, as this is one of the most incoherent narratives I've ever seen in a film -- I'd hate to have seen it before the plot was \\\\\\\"simplified.\\\\\\\"

It's sad to see Warren with so little character to go on that even he can't do anything with the inept material. It's interesting to see Caron in '70s mode instead of her Hollywood-era glamour garb and persona, but it's sad to see her haplessly wander through this doing-a- favor-to-her-producer-husband dreck. She would actually later hook up with and marry the director, instead -- who, you'll note, never directed anything again, but did strictly 1st or 2nd A.D. work in TV from here on out. That oughta tell you enough right there.

I call this \\\\\\\"interesting\\\\\\\" because I have an automatic fondness for American films of this period, and this role does add perspective to Oates' otherwise fantastic 1971 output (Two- Lane Blacktop, The Hired Hand). But the \\\\\\\"1940s detective as fish-out-of-water in 1970s L.A.\\\\\\\" theme, which is the only thing the movie really has to say, is sold in way too heavy- handed a manner. A similar theme would be far more effectively handled two years later in Altman's The Long Goodbye. And as far as Oates playing a hard-bitten guy on a doomed errand, three years on, he would give his definitive performance in Bring Me the Head of Alfredo Garcia. If you haven't seen those, don't waste your time with this!\\\"\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 16 + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 2. 개별 리뷰 텍스트 데이터 추출 및 원문 확인\n", + "# 데이터프레임의 'review' 컬럼에서 첫 번째 인덱스의 데이터를 선택하여 분석 대상 텍스트의 형태를 파악합니다.\n", + "\n", + "# 첫 번째 행(Row)의 영화 리뷰 텍스트(Text) 데이터를 선택하여 콘솔에 출력 및 확인\n", + "print(review_df['review'][0])" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "y_bNZVCwYiqh", + "outputId": "bc808736-cce8-4571-f381-56f36db1f1c6" + }, + "execution_count": 17, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\"With all this stuff going down at the moment with MJ i've started listening to his music, watching the odd documentary here and there, watched The Wiz and watched Moonwalker again. Maybe i just want to get a certain insight into this guy who i thought was really cool in the eighties just to maybe make up my mind whether he is guilty or innocent. Moonwalker is part biography, part feature film which i remember going to see at the cinema when it was originally released. Some of it has subtle messages about MJ's feeling towards the press and also the obvious message of drugs are bad m'kay.

Visually impressive but of course this is all about Michael Jackson so unless you remotely like MJ in anyway then you are going to hate this and find it boring. Some may call MJ an egotist for consenting to the making of this movie BUT MJ and most of his fans would say that he made it for the fans which if true is really nice of him.

The actual feature film bit when it finally starts is only on for 20 minutes or so excluding the Smooth Criminal sequence and Joe Pesci is convincing as a psychopathic all powerful drug lord. Why he wants MJ dead so bad is beyond me. Because MJ overheard his plans? Nah, Joe Pesci's character ranted that he wanted people to know it is he who is supplying drugs etc so i dunno, maybe he just hates MJ's music.

Lots of cool things in this like MJ turning into a car and a robot and the whole Speed Demon sequence. Also, the director must have had the patience of a saint when it came to filming the kiddy Bad sequence as usually directors hate working with one kid let alone a whole bunch of them performing a complex dance scene.

Bottom line, this movie is for people who like MJ on one level or another (which i think is most people). If not, then stay away. It does try and give off a wholesome message and ironically MJ's bestest buddy in this movie is a girl! Michael Jackson is truly one of the most talented people ever to grace this planet but is he guilty? Well, with all the attention i've gave this subject....hmmm well i don't know because people can be different behind closed doors, i know this for a fact. He is either an extremely nice but stupid guy or one of the most sickest liars. I hope he is not the latter.\"\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 3. 정규 표현식(Regular Expression)을 활용한 텍스트 데이터 정제 및 전처리\n", + "# 텍스트 내의 불필요한 HTML 태그와 영문이 아닌 특수문자, 숫자 등을 제거하여 감성 분석에 적합한 형태로 정제합니다.\n", + "\n", + "import re\n", + "\n", + "#
HTML 태그를 replace 함수를 이용하여 공백(Space)으로 변환\n", + "review_df['review'] = review_df['review'].str.replace('
', ' ')\n", + "\n", + "# 파이썬의 정규 표현식 모듈인 re를 이용해 영어 문자열이 아닌 모든 문자를 공백으로 변환 (정제 과정 수행)\n", + "review_df['review'] = review_df['review'].apply(lambda x : re.sub(\"[^a-zA-Z]\", \" \", x))" + ], + "metadata": { + "id": "4vkQ1HR0Ylet" + }, + "execution_count": 18, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 4. 데이터 세트 분할 및 학습/테스트 데이터(Train/Test Dataset) 생성\n", + "# 학습용 피처/클래스 데이터와 검증용 피처/클래스 데이터를 7:3 비율로 분할하고 최종 데이터 구조를 확인합니다.\n", + "\n", + "from sklearn.model_selection import train_test_split\n", + "\n", + "# 타깃 레이블인 감성(Sentiment) 클래스 데이터프레임 추출\n", + "class_df = review_df['sentiment']\n", + "\n", + "# 원본 데이터에서 불필요한 고유 ID와 타깃 식별자를 삭제하여 피처(Feature) 데이터프레임 생성\n", + "feature_df = review_df.drop(['id', 'sentiment'], axis=1, inplace=False)\n", + "\n", + "# train_test_split을 이용하여 학습 데이터 세트와 테스트 데이터 세트로 분할 (테스트 비율 30%)\n", + "X_train, X_test, y_train, y_test = train_test_split(feature_df, class_df, test_size=0.3, random_state=156)\n", + "\n", + "# 분할된 학습 피처 데이터와 테스트 피처 데이터의 행렬 구조(Shape) 확인\n", + "X_train.shape, X_test.shape" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Ib3REJ93Y1cK", + "outputId": "c500c8c4-6721-4171-8076-a5956aba0900" + }, + "execution_count": 19, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "((9746, 1), (4177, 1))" + ] + }, + "metadata": {}, + "execution_count": 19 + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 5. 파이프라인(Pipeline)을 활용한 카운트 기반 피처 벡터화 및 로지스틱 회귀 학습/평가\n", + "# 텍스트 데이터의 Count 벡터화와 로지스틱 회귀(Logistic Regression) 모델의 학습, 예측, 성능 평가를 단일 파이프라인으로 결합하여 수행합니다.\n", + "\n", + "from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer\n", + "from sklearn.pipeline import Pipeline\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.metrics import accuracy_score, roc_auc_score\n", + "\n", + "# CountVectorizer(피처 벡터화)와 LogisticRegression(분류 모델)을 결합한 파이프라인 객체 생성\n", + "# 스톱 워드는 English, n-gram은 (1, 2), 분류기의 규제 계수 C는 10으로 설정\n", + "pipeline = Pipeline([\n", + " ('cnt_vect', CountVectorizer(stop_words='english', ngram_range=(1, 2))),\n", + " ('lr_clf', LogisticRegression(solver='liblinear', C=10))\n", + "])\n", + "\n", + "# 학습 데이터의 리뷰 텍스트를 입력하여 파이프라인 전체 프로세스(벡터화 및 모델) 학습(Fit) 수행\n", + "pipeline.fit(X_train['review'], y_train)\n", + "\n", + "# 테스트 데이터를 이용해 클래스 예측(Predict) 및 긍정 확률(Predict Proba) 추출\n", + "pred = pipeline.predict(X_test['review'])\n", + "pred_probs = pipeline.predict_proba(X_test['review'])[:, 1]\n", + "\n", + "# 모델의 최종 성능 지표인 예측 정확도(Accuracy) 및 ROC-AUC 수치를 출력하여 구조 확인\n", + "print('예측 정확도는 {0:.4f}, ROC-AUC는 {1:.4f}'.format(accuracy_score(y_test, pred), roc_auc_score(y_test, pred_probs)))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ZhIMQONUZEH9", + "outputId": "8546d09c-4017-4526-8e71-5bce06931e87" + }, + "execution_count": 20, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "예측 정확도는 0.8753, ROC-AUC는 0.9377\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 6. NLTK 전체 코퍼스(Corpus) 및 데이터 세트 통합 다운로드\n", + "# 자연어 처리에 필요한 NLTK 라이브러리의 모든 패키지, 사전 데이터, 언어 모델 자원(Resource)을 일괄 다운로드합니다.\n", + "\n", + "import nltk\n", + "\n", + "# NLTK가 제공하는 전체 데이터 세트('all') 일괄 다운로드 수행\n", + "nltk.download('all')" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "cHfmrCxEcfHO", + "outputId": "e771ecc0-80f0-4bbf-a3c5-c0501f823c49" + }, + "execution_count": 21, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "[nltk_data] Downloading collection 'all'\n", + "[nltk_data] | \n", + "[nltk_data] | Downloading package abc to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/abc.zip.\n", + "[nltk_data] | Downloading package alpino to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/alpino.zip.\n", + "[nltk_data] | Downloading package averaged_perceptron_tagger to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping taggers/averaged_perceptron_tagger.zip.\n", + "[nltk_data] | Downloading package averaged_perceptron_tagger_eng to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping\n", + "[nltk_data] | taggers/averaged_perceptron_tagger_eng.zip.\n", + "[nltk_data] | Downloading package averaged_perceptron_tagger_ru to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping\n", + "[nltk_data] | taggers/averaged_perceptron_tagger_ru.zip.\n", + "[nltk_data] | Downloading package averaged_perceptron_tagger_rus to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping\n", + "[nltk_data] | taggers/averaged_perceptron_tagger_rus.zip.\n", + "[nltk_data] | Downloading package basque_grammars to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping grammars/basque_grammars.zip.\n", + "[nltk_data] | Downloading package bcp47 to /root/nltk_data...\n", + "[nltk_data] | Downloading package biocreative_ppi to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/biocreative_ppi.zip.\n", + "[nltk_data] | Downloading package bllip_wsj_no_aux to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping models/bllip_wsj_no_aux.zip.\n", + "[nltk_data] | Downloading package book_grammars to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping grammars/book_grammars.zip.\n", + "[nltk_data] | Downloading package brown to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/brown.zip.\n", + "[nltk_data] | Downloading package brown_tei to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/brown_tei.zip.\n", + "[nltk_data] | Downloading package cess_cat to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/cess_cat.zip.\n", + "[nltk_data] | Downloading package cess_esp to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/cess_esp.zip.\n", + "[nltk_data] | Downloading package chat80 to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/chat80.zip.\n", + "[nltk_data] | Downloading package city_database to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/city_database.zip.\n", + "[nltk_data] | Downloading package cmudict to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/cmudict.zip.\n", + "[nltk_data] | Downloading package comparative_sentences to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/comparative_sentences.zip.\n", + "[nltk_data] | Downloading package comtrans to /root/nltk_data...\n", + "[nltk_data] | Downloading package conll2000 to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/conll2000.zip.\n", + "[nltk_data] | Downloading package conll2002 to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/conll2002.zip.\n", + "[nltk_data] | Downloading package conll2007 to /root/nltk_data...\n", + "[nltk_data] | Downloading package crubadan to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/crubadan.zip.\n", + "[nltk_data] | Downloading package dependency_treebank to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/dependency_treebank.zip.\n", + "[nltk_data] | Downloading package dolch to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/dolch.zip.\n", + "[nltk_data] | Downloading package english_wordnet to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/english_wordnet.zip.\n", + "[nltk_data] | Downloading package europarl_raw to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/europarl_raw.zip.\n", + "[nltk_data] | Downloading package extended_omw to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Downloading package floresta to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/floresta.zip.\n", + "[nltk_data] | Downloading package framenet_v15 to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/framenet_v15.zip.\n", + "[nltk_data] | Downloading package framenet_v17 to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/framenet_v17.zip.\n", + "[nltk_data] | Downloading package gazetteers to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/gazetteers.zip.\n", + "[nltk_data] | Downloading package genesis to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/genesis.zip.\n", + "[nltk_data] | Downloading package gutenberg to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/gutenberg.zip.\n", + "[nltk_data] | Downloading package ieer to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/ieer.zip.\n", + "[nltk_data] | Downloading package inaugural to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/inaugural.zip.\n", + "[nltk_data] | Downloading package indian to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/indian.zip.\n", + "[nltk_data] | Downloading package jeita to /root/nltk_data...\n", + "[nltk_data] | Downloading package kimmo to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/kimmo.zip.\n", + "[nltk_data] | Downloading package knbc to /root/nltk_data...\n", + "[nltk_data] | Downloading package large_grammars to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping grammars/large_grammars.zip.\n", + "[nltk_data] | Downloading package lin_thesaurus to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/lin_thesaurus.zip.\n", + "[nltk_data] | Downloading package mac_morpho to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/mac_morpho.zip.\n", + "[nltk_data] | Downloading package machado to /root/nltk_data...\n", + "[nltk_data] | Downloading package masc_tagged to /root/nltk_data...\n", + "[nltk_data] | Downloading package maxent_ne_chunker to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping chunkers/maxent_ne_chunker.zip.\n", + "[nltk_data] | Downloading package maxent_ne_chunker_tab to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping chunkers/maxent_ne_chunker_tab.zip.\n", + "[nltk_data] | Downloading package maxent_treebank_pos_tagger to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping taggers/maxent_treebank_pos_tagger.zip.\n", + "[nltk_data] | Downloading package maxent_treebank_pos_tagger_tab to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping\n", + "[nltk_data] | taggers/maxent_treebank_pos_tagger_tab.zip.\n", + "[nltk_data] | Downloading package mock_corpus to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/mock_corpus.zip.\n", + "[nltk_data] | Downloading package moses_sample to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping models/moses_sample.zip.\n", + "[nltk_data] | Downloading package movie_reviews to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/movie_reviews.zip.\n", + "[nltk_data] | Downloading package mte_teip5 to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/mte_teip5.zip.\n", + "[nltk_data] | Downloading package mwa_ppdb to /root/nltk_data...\n", + "[nltk_data] | Unzipping misc/mwa_ppdb.zip.\n", + "[nltk_data] | Downloading package names to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/names.zip.\n", + "[nltk_data] | Downloading package nombank.1.0 to /root/nltk_data...\n", + "[nltk_data] | Downloading package nonbreaking_prefixes to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/nonbreaking_prefixes.zip.\n", + "[nltk_data] | Downloading package nps_chat to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/nps_chat.zip.\n", + "[nltk_data] | Downloading package omw to /root/nltk_data...\n", + "[nltk_data] | Downloading package omw-1.4 to /root/nltk_data...\n", + "[nltk_data] | Downloading package opinion_lexicon to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/opinion_lexicon.zip.\n", + "[nltk_data] | Downloading package panlex_swadesh to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Downloading package paradigms to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/paradigms.zip.\n", + "[nltk_data] | Downloading package pe08 to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/pe08.zip.\n", + "[nltk_data] | Downloading package perluniprops to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping misc/perluniprops.zip.\n", + "[nltk_data] | Downloading package pil to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/pil.zip.\n", + "[nltk_data] | Downloading package pl196x to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/pl196x.zip.\n", + "[nltk_data] | Downloading package porter_test to /root/nltk_data...\n", + "[nltk_data] | Unzipping stemmers/porter_test.zip.\n", + "[nltk_data] | Downloading package ppattach to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/ppattach.zip.\n", + "[nltk_data] | Downloading package problem_reports to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/problem_reports.zip.\n", + "[nltk_data] | Downloading package product_reviews_1 to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/product_reviews_1.zip.\n", + "[nltk_data] | Downloading package product_reviews_2 to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/product_reviews_2.zip.\n", + "[nltk_data] | Downloading package propbank to /root/nltk_data...\n", + "[nltk_data] | Downloading package pros_cons to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/pros_cons.zip.\n", + "[nltk_data] | Downloading package ptb to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/ptb.zip.\n", + "[nltk_data] | Downloading package punkt to /root/nltk_data...\n", + "[nltk_data] | Package punkt is already up-to-date!\n", + "[nltk_data] | Downloading package punkt_tab to /root/nltk_data...\n", + "[nltk_data] | Package punkt_tab is already up-to-date!\n", + "[nltk_data] | Downloading package qc to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/qc.zip.\n", + "[nltk_data] | Downloading package reuters to /root/nltk_data...\n", + "[nltk_data] | Downloading package rslp to /root/nltk_data...\n", + "[nltk_data] | Unzipping stemmers/rslp.zip.\n", + "[nltk_data] | Downloading package rte to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/rte.zip.\n", + "[nltk_data] | Downloading package sample_grammars to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping grammars/sample_grammars.zip.\n", + "[nltk_data] | Downloading package semcor to /root/nltk_data...\n", + "[nltk_data] | Downloading package senseval to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/senseval.zip.\n", + "[nltk_data] | Downloading package sentence_polarity to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/sentence_polarity.zip.\n", + "[nltk_data] | Downloading package sentiwordnet to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/sentiwordnet.zip.\n", + "[nltk_data] | Downloading package shakespeare to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/shakespeare.zip.\n", + "[nltk_data] | Downloading package sinica_treebank to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/sinica_treebank.zip.\n", + "[nltk_data] | Downloading package smultron to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/smultron.zip.\n", + "[nltk_data] | Downloading package snowball_data to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Downloading package spanish_grammars to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping grammars/spanish_grammars.zip.\n", + "[nltk_data] | Downloading package state_union to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/state_union.zip.\n", + "[nltk_data] | Downloading package stopwords to /root/nltk_data...\n", + "[nltk_data] | Package stopwords is already up-to-date!\n", + "[nltk_data] | Downloading package subjectivity to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/subjectivity.zip.\n", + "[nltk_data] | Downloading package swadesh to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/swadesh.zip.\n", + "[nltk_data] | Downloading package switchboard to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/switchboard.zip.\n", + "[nltk_data] | Downloading package tagsets to /root/nltk_data...\n", + "[nltk_data] | Unzipping help/tagsets.zip.\n", + "[nltk_data] | Downloading package tagsets_json to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping help/tagsets_json.zip.\n", + "[nltk_data] | Downloading package timit to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/timit.zip.\n", + "[nltk_data] | Downloading package toolbox to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/toolbox.zip.\n", + "[nltk_data] | Downloading package treebank to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/treebank.zip.\n", + "[nltk_data] | Downloading package twitter_samples to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/twitter_samples.zip.\n", + "[nltk_data] | Downloading package udhr to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/udhr.zip.\n", + "[nltk_data] | Downloading package udhr2 to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/udhr2.zip.\n", + "[nltk_data] | Downloading package unicode_samples to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/unicode_samples.zip.\n", + "[nltk_data] | Downloading package universal_tagset to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping taggers/universal_tagset.zip.\n", + "[nltk_data] | Downloading package universal_treebanks_v20 to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Downloading package vader_lexicon to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Downloading package verbnet to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/verbnet.zip.\n", + "[nltk_data] | Downloading package verbnet3 to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/verbnet3.zip.\n", + "[nltk_data] | Downloading package webtext to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/webtext.zip.\n", + "[nltk_data] | Downloading package wmt15_eval to /root/nltk_data...\n", + "[nltk_data] | Unzipping models/wmt15_eval.zip.\n", + "[nltk_data] | Downloading package word2vec_sample to\n", + "[nltk_data] | /root/nltk_data...\n", + "[nltk_data] | Unzipping models/word2vec_sample.zip.\n", + "[nltk_data] | Downloading package wordnet to /root/nltk_data...\n", + "[nltk_data] | Package wordnet is already up-to-date!\n", + "[nltk_data] | Downloading package wordnet2021 to /root/nltk_data...\n", + "[nltk_data] | Downloading package wordnet2022 to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/wordnet2022.zip.\n", + "[nltk_data] | Downloading package wordnet31 to /root/nltk_data...\n", + "[nltk_data] | Downloading package wordnet_ic to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/wordnet_ic.zip.\n", + "[nltk_data] | Downloading package words to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/words.zip.\n", + "[nltk_data] | Downloading package ycoe to /root/nltk_data...\n", + "[nltk_data] | Unzipping corpora/ycoe.zip.\n", + "[nltk_data] | \n", + "[nltk_data] Done downloading collection all\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "True" + ] + }, + "metadata": {}, + "execution_count": 21 + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 7. WordNet 기반 단어의 시셋(Synset) 추출 및 의미 집합 구조 확인\n", + "# NLTK의 WordNet을 활용하여 특정 단어가 내포하는 다의어/동음이의어 사전 구조를 불러오고 개수를 파악합니다.\n", + "\n", + "from nltk.corpus import wordnet as wn\n", + "\n", + "# 분석할 기준 단어(Term) 정의\n", + "term = 'present'\n", + "\n", + "# 'present'라는 단어를 기반으로 WordNet에 등록된 시셋(Synsets) 리스트 생성\n", + "synsets = wn.synsets(term)\n", + "\n", + "# 반환된 시셋 객체의 자료형(Type) 출력\n", + "print('synsets() 반환 type :', type(synsets))\n", + "\n", + "# 해당 단어가 가지고 있는 고유한 의미 집합의 개수(Length) 출력\n", + "print('synsets() 반환 값 갯수:', len(synsets))\n", + "\n", + "# 단어가 가진 모든 어휘적 의미(Synset) 목록 전체 출력하여 구조 확인\n", + "print('synsets() 반환 값 :', synsets)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "FyqXFemrc1MF", + "outputId": "1d48a255-43e5-44a6-c9d6-d089a6c382aa" + }, + "execution_count": 22, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "synsets() 반환 type : \n", + "synsets() 반환 값 갯수: 18\n", + "synsets() 반환 값 : [Synset('present.n.01'), Synset('present.n.02'), Synset('present.n.03'), Synset('show.v.01'), Synset('present.v.02'), Synset('stage.v.01'), Synset('present.v.04'), Synset('present.v.05'), Synset('award.v.01'), Synset('give.v.08'), Synset('deliver.v.01'), Synset('introduce.v.01'), Synset('portray.v.04'), Synset('confront.v.03'), Synset('present.v.12'), Synset('salute.v.06'), Synset('present.a.01'), Synset('present.a.02')]\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 8. 시셋(Synset) 객체별 어휘 세부 정보 및 의미론적 구조 분석\n", + "# 추출된 단어 의미 집합 리스트를 순회하며 각 시셋의 이름, 품사 분류(POS), 개념 정의(Definition), 표제어 목록을 출력합니다.\n", + "\n", + "# 단어 'present'로 생성된 모든 시셋(Synsets) 리스트를 순회하는 반복문\n", + "for synset in synsets:\n", + " # 개별 시셋의 고유 식별 명칭(Name) 출력\n", + " print('##### Synset name : ', synset.name(), '#####')\n", + "\n", + " # 해당 의미가 속한 문맥상의 품사 및 분류 그룹(Lexicographer Name) 출력\n", + " print('POS :', synset.lexname())\n", + "\n", + " # 해당 어휘 의미에 대한 사전적 주석 및 개념 정의(Definition) 출력\n", + " print('Definition:', synset.definition())\n", + "\n", + " # 동일한 의미를 공유하는 유의어 및 표제어(Lemmas) 리스트를 출력하여 구조 확인\n", + " print('Lemmas:', synset.lemma_names())" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "M5s4qKY5dJhi", + "outputId": "4aaa627e-93dc-4a8a-a67e-c4e5dd8017cc" + }, + "execution_count": 23, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "##### Synset name : present.n.01 #####\n", + "POS : noun.time\n", + "Definition: the period of time that is happening now; any continuous stretch of time including the moment of speech\n", + "Lemmas: ['present', 'nowadays']\n", + "##### Synset name : present.n.02 #####\n", + "POS : noun.possession\n", + "Definition: something presented as a gift\n", + "Lemmas: ['present']\n", + "##### Synset name : present.n.03 #####\n", + "POS : noun.communication\n", + "Definition: a verb tense that expresses actions or states at the time of speaking\n", + "Lemmas: ['present', 'present_tense']\n", + "##### Synset name : show.v.01 #####\n", + "POS : verb.perception\n", + "Definition: give an exhibition of to an interested audience\n", + "Lemmas: ['show', 'demo', 'exhibit', 'present', 'demonstrate']\n", + "##### Synset name : present.v.02 #####\n", + "POS : verb.communication\n", + "Definition: bring forward and present to the mind\n", + "Lemmas: ['present', 'represent', 'lay_out']\n", + "##### Synset name : stage.v.01 #####\n", + "POS : verb.creation\n", + "Definition: perform (a play), especially on a stage\n", + "Lemmas: ['stage', 'present', 'represent']\n", + "##### Synset name : present.v.04 #####\n", + "POS : verb.possession\n", + "Definition: hand over formally\n", + "Lemmas: ['present', 'submit']\n", + "##### Synset name : present.v.05 #####\n", + "POS : verb.stative\n", + "Definition: introduce\n", + "Lemmas: ['present', 'pose']\n", + "##### Synset name : award.v.01 #####\n", + "POS : verb.possession\n", + "Definition: give, especially as an honor or reward\n", + "Lemmas: ['award', 'present']\n", + "##### Synset name : give.v.08 #####\n", + "POS : verb.possession\n", + "Definition: give as a present; make a gift of\n", + "Lemmas: ['give', 'gift', 'present']\n", + "##### Synset name : deliver.v.01 #####\n", + "POS : verb.communication\n", + "Definition: deliver (a speech, oration, or idea)\n", + "Lemmas: ['deliver', 'present']\n", + "##### Synset name : introduce.v.01 #####\n", + "POS : verb.communication\n", + "Definition: cause to come to know personally\n", + "Lemmas: ['introduce', 'present', 'acquaint']\n", + "##### Synset name : portray.v.04 #####\n", + "POS : verb.creation\n", + "Definition: represent abstractly, for example in a painting, drawing, or sculpture\n", + "Lemmas: ['portray', 'present']\n", + "##### Synset name : confront.v.03 #####\n", + "POS : verb.communication\n", + "Definition: present somebody with something, usually to accuse or criticize\n", + "Lemmas: ['confront', 'face', 'present']\n", + "##### Synset name : present.v.12 #####\n", + "POS : verb.communication\n", + "Definition: formally present a debutante, a representative of a country, etc.\n", + "Lemmas: ['present']\n", + "##### Synset name : salute.v.06 #####\n", + "POS : verb.communication\n", + "Definition: recognize with a gesture prescribed by a military regulation; assume a prescribed position\n", + "Lemmas: ['salute', 'present']\n", + "##### Synset name : present.a.01 #####\n", + "POS : adj.all\n", + "Definition: temporal sense; intermediate between past and future; now existing or happening or in consideration\n", + "Lemmas: ['present']\n", + "##### Synset name : present.a.02 #####\n", + "POS : adj.all\n", + "Definition: being or existing in a specified place\n", + "Lemmas: ['present']\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 9. WordNet 시셋(Synset) 간의 경로 유사도(Path Similarity) 측정 및 데이터프레임 매핑\n", + "# 개별 단어의 시셋 객체를 생성하고, 상호 간의 의미론적 경로 유사도를 계산하여 행렬 구조의 데이터프레임으로 시각화합니다.\n", + "\n", + "import pandas as pd\n", + "from nltk.corpus import wordnet as wn\n", + "\n", + "# 비교 분석할 주요 단어별 시셋(Synset) 객체 생성\n", + "tree = wn.synset('tree.n.01')\n", + "lion = wn.synset('lion.n.01')\n", + "tiger = wn.synset('tiger.n.02')\n", + "cat = wn.synset('cat.n.01')\n", + "dog = wn.synset('dog.n.01')\n", + "\n", + "# 시셋 객체 리스트 및 유사도 측정값 저장용 리스트 정의\n", + "entities = [tree, lion, tiger, cat, dog]\n", + "similarities = []\n", + "\n", + "# 각 시셋의 고유 식별 명칭에서 순수 단어명(Entity Name)만 추출하여 리스트 구성\n", + "entity_names = [entity.name().split('.')[0] for entity in entities]\n", + "\n", + "# 단어별 시셋 리스트를 순회하며 다른 단어의 시셋과의 경로 유사도(Path Similarity) 반복 측정\n", + "for entity in entities:\n", + " # 소수점 둘째 자리까지 반올림하여 상호 간의 유사도 행렬 계산\n", + " similarity = [round(entity.path_similarity(compared_entity), 2)\n", + " for compared_entity in entities]\n", + " similarities.append(similarity)\n", + "\n", + "# 계산된 단어별 유사도 리스트 데이터를 판다스 데이터프레임(DataFrame) 구조로 변환 및 컬럼/인덱스 명명\n", + "similarity_df = pd.DataFrame(similarities, columns=entity_names, index=entity_names)\n", + "\n", + "# 생성된 유사도 행렬 데이터프레임 전체를 출력하여 구조 확인\n", + "similarity_df" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "W4iRtpX3dXXZ", + "outputId": "97597558-31c9-4b68-d844-e43386879b78" + }, + "execution_count": 24, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " tree lion tiger cat dog\n", + "tree 1.00 0.07 0.07 0.08 0.12\n", + "lion 0.07 1.00 0.33 0.25 0.17\n", + "tiger 0.07 0.33 1.00 0.25 0.17\n", + "cat 0.08 0.25 0.25 1.00 0.20\n", + "dog 0.12 0.17 0.17 0.20 1.00" + ], + "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", + " \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", + " \n", + " \n", + " \n", + "
treeliontigercatdog
tree1.000.070.070.080.12
lion0.071.000.330.250.17
tiger0.070.331.000.250.17
cat0.080.250.251.000.20
dog0.120.170.170.201.00
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "similarity_df", + "summary": "{\n \"name\": \"similarity_df\",\n \"rows\": 5,\n \"fields\": [\n {\n \"column\": \"tree\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.40971941618624813,\n \"min\": 0.07,\n \"max\": 1.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 0.07,\n 0.12,\n 1.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"lion\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.3683476618630828,\n \"min\": 0.07,\n \"max\": 1.0,\n \"num_unique_values\": 5,\n \"samples\": [\n 1.0,\n 0.17,\n 0.33\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"tiger\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.3683476618630828,\n \"min\": 0.07,\n \"max\": 1.0,\n \"num_unique_values\": 5,\n \"samples\": [\n 0.33,\n 0.17,\n 1.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"cat\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.36664696916789047,\n \"min\": 0.08,\n \"max\": 1.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 0.25,\n 0.2,\n 0.08\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"dog\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.3745263675630862,\n \"min\": 0.12,\n \"max\": 1.0,\n \"num_unique_values\": 4,\n \"samples\": [\n 0.17,\n 1.0,\n 0.12\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 24 + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 10. SentiWordNet 기반 감성 시셋(SentiSynset) 추출 및 어휘 감성 구조 확인\n", + "# 단어가 가진 문맥별 감성 지수(긍정/부정/객관성)를 분석하기 위해 특정 단어의 감성 시셋 리스트를 생성하고 구조를 파악합니다.\n", + "\n", + "import nltk\n", + "from nltk.corpus import sentiwordnet as swn\n", + "\n", + "# 'slow'라는 단어를 기반으로 SentiWordNet에 등록된 감성 시셋(SentiSynsets) 목록을 리스트로 변환\n", + "senti_synsets = list(swn.senti_synsets('slow'))\n", + "\n", + "# 반환된 감성 시셋 리스트의 자료형(Type) 출력\n", + "print('senti_synsets() 반환 type :', type(senti_synsets))\n", + "\n", + "# 해당 단어가 가지고 있는 고유한 감성 의미 집합의 개수(Length) 출력\n", + "print('senti_synsets() 반환 값 갯수:', len(senti_synsets))\n", + "\n", + "# 어휘별 감성 주석이 포함된 감성 시셋 데이터 전체를 출력하여 구조 확인\n", + "print('senti_synsets() 반환 값 :', senti_synsets)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "BR9Z8f7Nd3Hl", + "outputId": "5728a943-4f48-456d-c690-cbbe23f642d1" + }, + "execution_count": 25, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "senti_synsets() 반환 type : \n", + "senti_synsets() 반환 값 갯수: 11\n", + "senti_synsets() 반환 값 : [SentiSynset('decelerate.v.01'), SentiSynset('slow.v.02'), SentiSynset('slow.v.03'), SentiSynset('slow.a.01'), SentiSynset('slow.a.02'), SentiSynset('dense.s.04'), SentiSynset('slow.a.04'), SentiSynset('boring.s.01'), SentiSynset('dull.s.08'), SentiSynset('slowly.r.01'), SentiSynset('behind.r.03')]\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 11. SentiSynset 객체의 감성 지수(Sentiment Score) 추출 및 수치 분석\n", + "# 특정 어휘 시셋의 긍정 지수(Positive Score), 부정 지수(Negative Score), 객관성 지수(Objective Score)를 조회하여 감정 상태를 정량화합니다.\n", + "\n", + "import nltk\n", + "from nltk.corpus import sentiwordnet as swn\n", + "\n", + "# 명사('n') 품사 정보를 가진 'father'의 첫 번째 감성 시셋 객체 생성\n", + "father = swn.senti_synset('father.n.01')\n", + "\n", + "# 'father' 시셋의 감성 지수(긍정, 부정, 객관성)를 각각 추출하여 출력\n", + "print('father 긍정감성 지수:', father.pos_score())\n", + "print('father 부정감성 지수:', father.neg_score())\n", + "print('father 객관성 지수:', father.obj_score())\n", + "\n", + "print('\\n')\n", + "\n", + "# 형용사('a') 품사 정보를 가진 'fabulous'의 첫 번째 감성 시셋 객체 생성\n", + "fabulous = swn.senti_synset('fabulous.a.01')\n", + "\n", + "# 'fabulous' 시셋의 감성 지수(긍정, 부정)를 각각 출력하여 구조 확인\n", + "print('fabulous 긍정감성 지수:', fabulous.pos_score())\n", + "print('fabulous 부정감성 지수:', fabulous.neg_score())" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JDb3tmP-d6eN", + "outputId": "0200af87-6f9c-47e4-be64-9785bcd4e901" + }, + "execution_count": 26, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "father 긍정감성 지수: 0.0\n", + "father 부정감성 지수: 0.0\n", + "father 객관성 지수: 1.0\n", + "\n", + "\n", + "fabulous 긍정감성 지수: 0.875\n", + "fabulous 부정감성 지수: 0.125\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 12. Penn Treebank 품사 태그의 WordNet 품사 식별자 변환 함수 구현\n", + "# NLTK의 pos_tag()가 반환하는 Penn Treebank 형식의 접두사를 판별하여 WordNet 언어 모델 호환 품사(POS) 태그로 매핑합니다.\n", + "\n", + "from nltk.corpus import wordnet as wn\n", + "\n", + "# Penn Treebank 품사 Tag를 기반으로 WordNet 기반의 품사 Tag로 변환하는 함수 생성\n", + "def penn_to_wn(tag):\n", + "\n", + " # 접두사가 'J'로 시작하는 경우 형용사(Adjective) 식별자 반환\n", + " if tag.startswith('J'):\n", + " return wn.ADJ\n", + "\n", + " # 접두사가 'N'으로 시작하는 경우 명사(Noun) 식별자 반환\n", + " elif tag.startswith('N'):\n", + " return wn.NOUN\n", + "\n", + " # 접두사가 'R'로 시작하는 경우 부사(Adverb) 식별자 반환\n", + " elif tag.startswith('R'):\n", + " return wn.ADV\n", + "\n", + " # 접두사가 'V'로 시작하는 경우 동사(Verb) 식별자 반환 구조 정의\n", + " elif tag.startswith('V'):\n", + " return wn.VERB" + ], + "metadata": { + "id": "n9yFiyoxeUuB" + }, + "execution_count": 27, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 13. SentiWordNet 기반 문서 감성 극성(Polarity) 예측 함수 구현\n", + "# 문장을 토큰화하고 품사 태깅과 어간 추출을 거쳐 단어별 긍정/부정 지수를 합산한 뒤, 최종 감성 스코어를 판별하는 함수를 정의합니다.\n", + "\n", + "from nltk.stem import WordNetLemmatizer\n", + "from nltk.corpus import sentiwordnet as swn\n", + "from nltk.corpus import wordnet as wn\n", + "from nltk import sent_tokenize, word_tokenize, pos_tag\n", + "\n", + "# 텍스트 데이터를 입력받아 감성 극성을 반환하는 사용자 정의 함수 생성\n", + "def swn_polarity(text):\n", + " # 감성 지수 및 연산에 사용된 토큰 개수(Count) 초기화\n", + " sentiment = 0.0\n", + " tokens_count = 0\n", + "\n", + " lemmatizer = WordNetLemmatizer()\n", + " raw_sentences = sent_tokenize(text)\n", + "\n", + " # 분해된 문장별로 단어 토큰화 후 품사 태깅, SentiSynset 생성 및 감성 지수 합산 루프 수행\n", + " for raw_sentence in raw_sentences:\n", + " # NLTK 기반의 품사 태깅(POS Tagging) 수행\n", + " tagged_sentence = pos_tag(word_tokenize(raw_sentence))\n", + " for word, tag in tagged_sentence:\n", + "\n", + " # 이전에 정의한 penn_to_wn 함수를 활용해 WordNet 기반 품사 태그로 변환\n", + " wn_tag = penn_to_wn(tag)\n", + " if wn_tag not in (wn.NOUN, wn.ADJ, wn.ADV):\n", + " continue\n", + "\n", + " # 변환된 품사 정보('pos')를 지정하여 단어 어근 추출(Lemmatization) 수행\n", + " lemma = lemmatizer.lemmatize(word, pos=wn_tag)\n", + " if not lemma:\n", + " continue\n", + "\n", + " # 어근을 추출한 단어와 WordNet 기반 품사 태깅을 입력해 시셋(Synset) 객체 생성\n", + " synsets = wn.synsets(lemma, pos=wn_tag)\n", + " if not synsets:\n", + " continue\n", + "\n", + " # SentiWordNet의 감성 단어 분석을 위해 매칭되는 첫 번째 감성 시셋(SentiSynset) 추출\n", + " synset = synsets[0]\n", + " swn_synset = swn.senti_synset(synset.name())\n", + "\n", + " # 모든 단어에 대해 긍정 감성 지수는 더하고(+) 부정 감성 지수는 빼서(-) 감성 총합 계산\n", + " sentiment += (swn_synset.pos_score() - swn_synset.neg_score())\n", + " tokens_count += 1\n", + "\n", + " # 분석에 유효한 감성 토큰이 전혀 없을 경우 0 반환\n", + " if not tokens_count:\n", + " return 0\n", + "\n", + " # 총 스코어(Score)가 0 이상일 경우 긍정(Positive)인 1, 그렇지 않을 경우 부정(Negative)인 0 반환 구조 정의\n", + " if sentiment >= 0:\n", + " return 1\n", + "\n", + " return 0" + ], + "metadata": { + "id": "uusU5PKvepE0" + }, + "execution_count": 28, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 14. 전체 데이터 세트 대상 감성 극성 예측 수행 및 결과 배열 추출\n", + "# 정의된 감성 분석 함수를 데이터프레임의 모든 리뷰에 적용(Apply)하여 예측 평점(Prediction)을 도출하고 최종 분류용 타깃/예측 배열을 생성합니다.\n", + "\n", + "# 데이터프레임의 'review' 컬럼 전체 텍스트에 감성 분석 람다(Lambda) 함수를 적용하여 'preds' 컬럼에 결과 저장\n", + "review_df['preds'] = review_df['review'].apply(lambda x : swn_polarity(x))\n", + "\n", + "# 성능 평가 비교를 위해 실제 정답 레이블인 감성(Sentiment) 데이터를 넘파이 배열(Values) 형태로 추출\n", + "y_target = review_df['sentiment'].values\n", + "\n", + "# 모델을 통해 예측된 감성 극성 결과(Predictions) 데이터를 넘파이 배열 형태로 추출하여 구조 확인\n", + "preds = review_df['preds'].values" + ], + "metadata": { + "id": "Wb06Szi2f9eV" + }, + "execution_count": 29, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# 15. 오차 행렬(Confusion Matrix) 출력 및 분류 모델 핵심 성능 지표 평가\n", + "# 예측된 결과 배열을 바탕으로 오차 행렬을 생성하고 정확도, 정밀도, 재현율 등의 다각적 분류 지표를 연산하여 최종 모델 성능을 검증합니다.\n", + "\n", + "from sklearn.metrics import accuracy_score, confusion_matrix, precision_score\n", + "from sklearn.metrics import recall_score, f1_score, roc_auc_score\n", + "import numpy as np\n", + "\n", + "# 실제 정답과 예측값을 비교하여 분류 결과의 오차 행렬(Confusion Matrix) 구조 출력\n", + "print(confusion_matrix(y_target, preds))\n", + "\n", + "# 평가 지표 수치들을 소수점 넷째 자리까지 반올림(Round)하여 최종 출력 및 확인\n", + "print(\"정확도:\", np.round(accuracy_score(y_target, preds), 4))\n", + "print(\"정밀도:\", np.round(precision_score(y_target, preds), 4))\n", + "print(\"재현율:\", np.round(recall_score(y_target, preds), 4))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "mESgwNQ0gaMY", + "outputId": "4ed51620-28b0-4a73-a521-cdcaa5bd841b" + }, + "execution_count": 30, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[[4244 2686]\n", + " [2056 4937]]\n", + "정확도: 0.6594\n", + "정밀도: 0.6476\n", + "재현율: 0.706\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 16. VADER 감성 분석기(Sentiment Intensity Analyzer)를 활용한 리뷰 감성 지수 산출\n", + "# 소셜 미디어 및 텍스트 문맥 분석에 특화된 VADER 알고리즘을 사용하여 단어의 극성 점수를 구하고 다각적 감성 구조를 측정합니다.\n", + "\n", + "from nltk.sentiment.vader import SentimentIntensityAnalyzer\n", + "\n", + "# VADER 감성 분석기(SentimentIntensityAnalyzer) 객체 생성 및 인스턴스화\n", + "senti_analyzer = SentimentIntensityAnalyzer()\n", + "\n", + "# 첫 번째 영화 리뷰 텍스트 원문을 입력하여 감성 극성 점수(Polarity Scores) 계산\n", + "senti_scores = senti_analyzer.polarity_scores(review_df['review'][0])\n", + "\n", + "# 계산된 세부 감성 지수(긍정/부정/중립/복합 스코어) 딕셔너리 결과를 출력하여 구조 확인\n", + "print(senti_scores)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "k4Lonht9hqCJ", + "outputId": "a6c9351f-7e56-4db5-f97d-be7668a9d4fb" + }, + "execution_count": 31, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "{'neg': 0.13, 'neu': 0.743, 'pos': 0.127, 'compound': -0.7943}\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# 17. VADER 기반 문서 감성 극성(Polarity) 분류 함수 구현 및 최종 성능 검증\n", + "# 임계값(Threshold) 설정을 통해 복합 감성 지수인 compound 스코어를 0(부정) 또는 1(긍정)로 이진 분류하고 최종 평가지표를 연산합니다.\n", + "\n", + "from sklearn.metrics import accuracy_score, confusion_matrix, precision_score\n", + "from sklearn.metrics import recall_score, f1_score, roc_auc_score\n", + "import numpy as np\n", + "\n", + "# 리뷰 텍스트와 임계값을 입력받아 VADER 감성 극성을 반환하는 사용자 정의 함수 생성\n", + "def vader_polarity(review, threshold=0.1):\n", + " analyzer = SentimentIntensityAnalyzer()\n", + " scores = analyzer.polarity_scores(review)\n", + "\n", + " # 복합 감성 지수인 compound 값에 기반해 threshold 입력값보다 크거나 같으면 1, 그렇지 않으면 0 반환\n", + " agg_score = scores['compound']\n", + " final_sentiment = 1 if agg_score >= threshold else 0\n", + " return final_sentiment\n", + "\n", + "# apply lambda 식을 이용하여 레코드별로 vader_polarity()를 수행하고 결과를 'vader_preds' 컬럼에 저장\n", + "review_df['vader_preds'] = review_df['review'].apply(lambda x : vader_polarity(x, 0.1))\n", + "\n", + "# 성능 평가 비교를 위해 실제 정답 레이블과 VADER 예측값 배열을 각각 추출\n", + "y_target = review_df['sentiment'].values\n", + "vader_preds = review_df['vader_preds'].values\n", + "\n", + "# VADER 모델의 오차 행렬(Confusion Matrix) 구조 출력\n", + "print(confusion_matrix(y_target, vader_preds))\n", + "\n", + "# 최종 분류 모델 핵심 성능 지표(정확도, 정밀도, 재현율)를 반올림하여 출력 및 확인\n", + "print(\"정확도:\", np.round(accuracy_score(y_target, vader_preds), 4))\n", + "print(\"정밀도:\", np.round(precision_score(y_target, vader_preds), 4))\n", + "print(\"재현율:\", np.round(recall_score(y_target, vader_preds), 4))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "OOYKJNjeh8ad", + "outputId": "489e42ac-34c3-454a-e5f2-8c5111ebc519" + }, + "execution_count": 32, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[[3742 3188]\n", + " [ 993 6000]]\n", + "정확도: 0.6997\n", + "정밀도: 0.653\n", + "재현율: 0.858\n" + ] + } + ] + } + ] +} \ No newline at end of file