{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:08.453724Z", "iopub.status.busy": "2021-10-08T10:32:08.453019Z", "iopub.status.idle": "2021-10-08T10:32:08.853872Z", "shell.execute_reply": "2021-10-08T10:32:08.853141Z" } }, "outputs": [], "source": [ "import konlpy\n", "import pandas as pd\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "최신 `tweepy`를 설치할 경우 `StreamListener`가 없다는 에러가 발생(https://github.com/tweepy/tweepy/issues/1531) 하므로 3.10버전을 설치해 주세요.\n", "\n", "`pip install tweepy==3.10`" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:08.863731Z", "iopub.status.busy": "2021-10-08T10:32:08.863002Z", "iopub.status.idle": "2021-10-08T10:32:08.867959Z", "shell.execute_reply": "2021-10-08T10:32:08.868405Z" } }, "outputs": [ { "data": { "text/plain": [ "'0.5.2'" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "konlpy.__version__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "데이터 파일을 읽어 리뷰 텍스트와 점수를 text_train, y_train 변수에 저장합니다. 데이터 파일의 내용은 번호, 텍스트, 레이블이 탭으로 구분되어 한 라인에 한개의 데이터 샘플이 들어 있습니다." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:08.873456Z", "iopub.status.busy": "2021-10-08T10:32:08.872857Z", "iopub.status.idle": "2021-10-08T10:32:09.230697Z", "shell.execute_reply": "2021-10-08T10:32:09.231143Z" } }, "outputs": [], "source": [ "df_train = pd.read_csv('data/ratings_train.txt', delimiter='\\t', keep_default_na=False)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:09.237497Z", "iopub.status.busy": "2021-10-08T10:32:09.235262Z", "iopub.status.idle": "2021-10-08T10:32:09.241693Z", "shell.execute_reply": "2021-10-08T10:32:09.242122Z" }, "scrolled": true }, "outputs": [ { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
iddocumentlabel
09976970아 더빙.. 진짜 짜증나네요 목소리0
13819312흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나1
210265843너무재밓었다그래서보는것을추천한다0
39045019교도소 이야기구먼 ..솔직히 재미는 없다..평점 조정0
46483659사이몬페그의 익살스런 연기가 돋보였던 영화!스파이더맨에서 늙어보이기만 했던 커스틴 ...1
\n", "
" ], "text/plain": [ " id document label\n", "0 9976970 아 더빙.. 진짜 짜증나네요 목소리 0\n", "1 3819312 흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나 1\n", "2 10265843 너무재밓었다그래서보는것을추천한다 0\n", "3 9045019 교도소 이야기구먼 ..솔직히 재미는 없다..평점 조정 0\n", "4 6483659 사이몬페그의 익살스런 연기가 돋보였던 영화!스파이더맨에서 늙어보이기만 했던 커스틴 ... 1" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_train.head()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:09.246541Z", "iopub.status.busy": "2021-10-08T10:32:09.245860Z", "iopub.status.idle": "2021-10-08T10:32:09.247974Z", "shell.execute_reply": "2021-10-08T10:32:09.247434Z" } }, "outputs": [], "source": [ "text_train, y_train = df_train['document'].values, df_train['label'].values" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "같은 방식으로 테스트 데이터를 읽습니다." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:09.254864Z", "iopub.status.busy": "2021-10-08T10:32:09.252477Z", "iopub.status.idle": "2021-10-08T10:32:09.364211Z", "shell.execute_reply": "2021-10-08T10:32:09.363509Z" } }, "outputs": [], "source": [ "df_test = pd.read_csv('data/ratings_test.txt', delimiter='\\t', keep_default_na=False)\n", "text_test = df_test['document'].values\n", "y_test = df_test['label'].values" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "훈련 데이터와 테스트 데이터의 크기를 확인합니다." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:09.368652Z", "iopub.status.busy": "2021-10-08T10:32:09.367819Z", "iopub.status.idle": "2021-10-08T10:32:09.372199Z", "shell.execute_reply": "2021-10-08T10:32:09.371373Z" } }, "outputs": [ { "data": { "text/plain": [ "(150000, array([75173, 74827]))" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(text_train), np.bincount(y_train)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:09.376830Z", "iopub.status.busy": "2021-10-08T10:32:09.376262Z", "iopub.status.idle": "2021-10-08T10:32:09.378739Z", "shell.execute_reply": "2021-10-08T10:32:09.379143Z" } }, "outputs": [ { "data": { "text/plain": [ "(50000, array([24827, 25173]))" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(text_test), np.bincount(y_test)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "KoNLPy 0.4.5 버전부터 `Twitter` 클래스가 `Okt` 클래스로 바뀌었습니다. [open-korean-text](https://github.com/open-korean-text/open-korean-text) 프로젝트는 [twitter-korean-text](https://github.com/twitter/twitter-korean-text) 프로젝트의 공식 포크입니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "병렬 처리를 위해 `Mecab`을 사용하여 전체 데이터로 학습시킵니다. `Mecab`으로 토큰을 분할하는 함수를 만듭니다.\n", "\n", "MeCab을 설치하려면 다음 명령을 실행하세요.\n", "\n", "$ bash <(curl -s https://raw.githubusercontent.com/konlpy/konlpy/master/scripts/mecab.sh)\n", "\n", "파이썬 가상 환경에서 MeCab을 설치하려면 이 깃허브에 포함된 `mecab.sh` 파일을 실행하세요.\n", "\n", "최신 macOS Mojave에서는 `Mecab`에 필요한 jpype 라이브러리가 컴파일 오류가 발생할 수 있습니다. 이런 경우 다음 명령으로 konlpy를 설치해 주세요.\n", "\n", "`$ export MACOSX_DEPLOYMENT_TARGET=10.10 CFLAGS='-stdlib=libc++' pip install konlpy`\n", "\n", "Mecab 클래스(SwigPyObject)를 피클링(pickling)하지 못해 `n_jobs=-1`로 설정하면 오류가 발생합니다." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:09.383825Z", "iopub.status.busy": "2021-10-08T10:32:09.383202Z", "iopub.status.idle": "2021-10-08T10:32:09.754773Z", "shell.execute_reply": "2021-10-08T10:32:09.754010Z" } }, "outputs": [], "source": [ "from sklearn.pipeline import make_pipeline\n", "from sklearn.model_selection import GridSearchCV\n", "from sklearn.feature_extraction.text import TfidfVectorizer\n", "from sklearn.linear_model import LogisticRegression" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:09.760342Z", "iopub.status.busy": "2021-10-08T10:32:09.759452Z", "iopub.status.idle": "2021-10-08T10:32:09.762082Z", "shell.execute_reply": "2021-10-08T10:32:09.761284Z" }, "scrolled": true }, "outputs": [], "source": [ "from konlpy.tag import Mecab\n", "mecab = Mecab()\n", "def mecab_tokenizer(text):\n", " return mecab.morphs(text)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:32:09.768006Z", "iopub.status.busy": "2021-10-08T10:32:09.767352Z", "iopub.status.idle": "2021-10-08T10:33:15.100008Z", "shell.execute_reply": "2021-10-08T10:33:15.101404Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "최상의 크로스 밸리데이션 점수: 0.830\n", "최적의 크로스 밸리데이션 파라미터: {'logisticregression__C': 0.1, 'tfidfvectorizer__min_df': 3, 'tfidfvectorizer__ngram_range': (1, 1)}\n" ] } ], "source": [ "mecab_param_grid = {'tfidfvectorizer__min_df': [3],\n", " 'tfidfvectorizer__ngram_range': [(1, 1)],\n", " 'logisticregression__C': [0.1]}\n", "mecab_pipe = make_pipeline(TfidfVectorizer(tokenizer=mecab_tokenizer), LogisticRegression(solver='liblinear'))\n", "mecab_grid = GridSearchCV(mecab_pipe, mecab_param_grid, n_jobs=1, cv=3)\n", "\n", "# 그리드 서치를 수행합니다\n", "mecab_grid.fit(text_train, y_train)\n", "print(\"최상의 크로스 밸리데이션 점수: {:.3f}\".format(mecab_grid.best_score_))\n", "print(\"최적의 크로스 밸리데이션 파라미터: \", mecab_grid.best_params_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "SwigPyObject의 피클링을 위해 `__setstate__`, `__getstate__` 메서드를 추가하여 Mecab 클래스를 감쌉니다." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:33:15.108082Z", "iopub.status.busy": "2021-10-08T10:33:15.106133Z", "iopub.status.idle": "2021-10-08T10:33:15.115494Z", "shell.execute_reply": "2021-10-08T10:33:15.116759Z" } }, "outputs": [], "source": [ "class PicklableMecab(Mecab):\n", "\n", " def __init__(self, *args):\n", " self.args = args\n", " Mecab.__init__(self, *args)\n", " \n", " def __setstate__(self, state):\n", " self.__init__(*state['args'])\n", "\n", " def __getstate__(self):\n", " return {'args': self.args}" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:33:15.123161Z", "iopub.status.busy": "2021-10-08T10:33:15.121212Z", "iopub.status.idle": "2021-10-08T10:33:15.132209Z", "shell.execute_reply": "2021-10-08T10:33:15.133387Z" }, "scrolled": true }, "outputs": [], "source": [ "mecab = PicklableMecab()\n", "def mecab_tokenizer(text):\n", " return mecab.morphs(text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "규제 파라미터의 범위를 확대하여 그리드 서치를 수행합니다." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:33:15.139760Z", "iopub.status.busy": "2021-10-08T10:33:15.137766Z", "iopub.status.idle": "2021-10-08T10:41:44.090265Z", "shell.execute_reply": "2021-10-08T10:41:44.090785Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "최상의 크로스 밸리데이션 점수: 0.870\n", "최적의 크로스 밸리데이션 파라미터: {'logisticregression__C': 10, 'tfidfvectorizer__min_df': 3, 'tfidfvectorizer__ngram_range': (1, 3)}\n" ] } ], "source": [ "mecab_param_grid = {'tfidfvectorizer__min_df': [3, 5 ,7],\n", " 'tfidfvectorizer__ngram_range': [(1, 1), (1, 2), (1, 3)],\n", " 'logisticregression__C': [0.1, 1, 10, 100]}\n", "mecab_pipe = make_pipeline(TfidfVectorizer(tokenizer=mecab_tokenizer), LogisticRegression(solver='liblinear'))\n", "mecab_grid = GridSearchCV(mecab_pipe, mecab_param_grid, n_jobs=-1, cv=3)\n", "\n", "# 그리드 서치를 수행합니다\n", "mecab_grid.fit(text_train, y_train)\n", "print(\"최상의 크로스 밸리데이션 점수: {:.3f}\".format(mecab_grid.best_score_))\n", "print(\"최적의 크로스 밸리데이션 파라미터: \", mecab_grid.best_params_)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2021-10-08T10:41:44.104864Z", "iopub.status.busy": "2021-10-08T10:41:44.104216Z", "iopub.status.idle": "2021-10-08T10:41:51.300416Z", "shell.execute_reply": "2021-10-08T10:41:51.299750Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "테스트 세트 점수: 0.875\n" ] } ], "source": [ "X_test_mecab = mecab_grid.best_estimator_.named_steps[\"tfidfvectorizer\"].transform(text_test)\n", "score = mecab_grid.best_estimator_.named_steps[\"logisticregression\"].score(X_test_mecab, y_test)\n", "print(\"테스트 세트 점수: {:.3f}\".format(score))" ] } ], "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.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }