{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# **머신러닝을 활용한 전처리**\n", "규격화된 일정량의 데이터를 활용하여 많은 데이터 처리용 알고리즘\n", "- https://github.com/lovit/soynlp " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# **1 WPM (Word Piece Model)**\n", "- **[BPE(Byte Pair Encoding)](https://wikidocs.net/22592)** 알고리즘 (1994) Philip Gage 논문이 배경\n", "- **WPM** 모델링 기법 : 2016 년 **Pre Processing 모델링을** 활용한 Stemming 기법\n", "\n", "## **01 defaultDict 을 활용한 단어조합기**\n", "**[defaultDict()](https://itholic.github.io/python-defaultdict/)** 을 활용한 **N-Gram** 생성 후 **단어 조합하기** 연\n", "습\n", "1. 식별이 가능한 Token 단위로 학습데이터 만들기" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'l o w '" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 단어 Token 을 음절단위로 구분하기\n", "\" \".join(list(\"low\")+[\"\"]) " ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "defaultdict(int,\n", " {('l', 'o'): 7,\n", " ('o', 'w'): 7,\n", " ('w', ''): 5,\n", " ('w', 'e'): 8,\n", " ('e', 's'): 2,\n", " ('s', 't'): 2,\n", " ('t', ''): 2,\n", " ('n', 'e'): 6,\n", " ('e', 'w'): 6,\n", " ('e', 'r'): 9,\n", " ('r', ''): 9,\n", " ('w', 'i'): 3,\n", " ('i', 'd'): 3,\n", " ('d', 'e'): 3})" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Token 과 빈도수를 활용한 \n", "data = {\n", " \" l o w \":5,\n", " \" l o w e s t \":2,\n", " \" n e w e r \":6,\n", " \" w i d e r \":3,\n", "}\n", "\n", "from collections import defaultdict\n", "pair = defaultdict(int)\n", "candidate = {}\n", "n_gram = 2\n", "\n", "for k, v in data.items():\n", " token = k.split()\n", " for i in range(len(token)-1):\n", " pair[tuple(token[ i : i+n_gram ])] += v\n", "pair" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('e', 'r')" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# .get : Tuple 의 객체들을 따로 따로 묶어서 판단 합니다.\n", "maxKey = max(pair, key=pair.get) # pair.get : \n", "maxKey" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{' l o w ': 5,\n", " ' l o w e s t ': 2,\n", " ' n e w er ': 6,\n", " ' w i d er ': 3}" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 함께 출현하는 빈도가 높을수록 단어로 묶일 확률이 높다\n", "# 작업결과 \"er\" 이 묶인걸 볼 수 있습니다.\n", "newData = {}\n", "import re\n", "for k, v in data.items():\n", " newKey = re.sub(\" \".join(maxKey), \"\".join(maxKey), k)\n", " newData[newKey] = v\n", "newData" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **2 Word Piece Model 한글실습**\n", "- defaultDict 단어 token 을 만든 뒤,\n", "- Bi-Gram 빈도를 기준으로 단어 Token 을 찾기" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# Ngram defaultDict 만들기\n", "def findNgram(data):\n", " pair = defaultdict(int)\n", " candidate = {}\n", " for k, v in data.items():\n", " token = k.split()\n", " for i in range(len(token)-1):\n", " pair[tuple(token[ i : i+2 ])] += v\n", " return pair\n", "\n", "# MaxKey 빈도값을 활용하여 단어 생성하기\n", "def mergeNgram(maxKey, data):\n", " newData = {}\n", " for k, v in data.items():\n", " newKey = re.sub(\" \".join(maxKey), \"\".join(maxKey), k)\n", " newData[newKey] = v\n", " return newData" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{' 아버지 께 ': 5, ' 아버지 를 ': 2, ' 아버지 에 게 ': 6, ' 아버지 와 ': 3}" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 어절 Token 목록을 활용한 단어 찾기\n", "data = {\n", " \" 아 버 지 께 \":5,\n", " \" 아 버 지 를 \":2,\n", " \" 아 버 지 에 게 \":6,\n", " \" 아 버 지 와 \":3,\n", "}\n", "\n", "for _ in range(2):\n", " pairList = findNgram(data)\n", " maxKey = max(pairList, key=pairList.get)\n", " data = mergeNgram(maxKey, data)\n", "data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **3 Word Piece Model 한글실습 2**\n", "- 반복 횟수인 MaxKey 값을 자동으로 찾기" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_values([5, 2, 6, 3])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data = {\n", " \"아 버 지 께 \":5,\n", " \"아 버 지 를 \":2,\n", " \"아 버 지 에 게 \":6,\n", " \"아 버 지 와 \":3,\n", "}\n", "data.values()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from collections import defaultdict\n", "def findNagram(data):\n", " pair = defaultdict(int)\n", " for k, v in data.items():\n", " tokens = k.split()\n", " for i in range(len(tokens)-1):\n", " pair[tuple(tokens[i:i+2])] += v\n", " return pair\n", "\n", "# maxValue 변수를 추가해 반복 횟수를 제한 합니다\n", "def mergeNgram(maxKey, data):\n", " newData = dict()\n", " for k, v in data.items():\n", " newKey = re.sub(\" \".join(maxKey),\n", " \"\".join(maxKey), k)\n", " newData[newKey] = v\n", " return newData\n", "\n", "maxValue = max(data.values())\n", "maxValue" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "('아', '버') 16\n", "('아버', '지') 16\n", "('아버지', '에') 6\n" ] }, { "data": { "text/plain": [ "{'아버지 께 ': 5, '아버지 를 ': 2, '아버지 에 게 ': 6, '아버지 와 ': 3}" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for _ in range(1000):\n", " pairList = findNagram(data)\n", " maxKey = max(pairList, key=pairList.get)\n", " print(maxKey, pairList[maxKey])\n", " \n", " if pairList[maxKey] > maxValue:\n", " data = mergeNgram(maxKey, data)\n", " else: \n", " break\n", "data" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "defaultdict(int,\n", " {('아버지', '께'): 5,\n", " ('께', ''): 5,\n", " ('아버지', '를'): 2,\n", " ('를', ''): 2,\n", " ('아버지', '에'): 6,\n", " ('에', '게'): 6,\n", " ('게', ''): 6,\n", " ('아버지', '와'): 3,\n", " ('와', ''): 3})" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pairList" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "# **2 레시피 데이터 적용하기**\n", "- **[BPE(Byte Pair Encoding)](https://wikidocs.net/22592)** 알고리즘 (1994) Philip Gage 논문이 배경\n", "- **WPM** 모델링 기법 : 2016 년 **Pre Processing 모델링을** 활용한 Stemming 기법\n", "\n", "## **01 defaultDict 을 활용한 단어조합기**\n", "**[defaultDict()](https://itholic.github.io/python-defaultdict/)** 을 활용한 **N-Gram** 생성 후 **단어 조합하기** 연\n", "습\n", "1. [f-string 사용법](https://bluese05.tistory.com/70\n", "1. 식별이 가능한 Token 단위로 학습데이터 만들기" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"tuple: ('Hi, I am', 'song', 123)\"" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 출처: https://bluese05.tistory.com/70 [ㅍㅍㅋㄷ]\n", "tuple = ('Hi, I am', 'song', 123)\n", "f'tuple: {tuple}' #>>> \"tuple: ('Hi, I am', 'song', 123)\"" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# r'' 은 백슬래시를 함수처리서 제외 함\n", "print(r\"머신러닝 \\n 알고리즘\")\n", "print(\"머신러닝 \\n 알고리즘\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "key = '' " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'a' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34mf'{a} Python {b} tensorflow'\u001b[0m\u001b[0;31m#.(a=3.6, b=2)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'a' is not defined" ] } ], "source": [ "f'{a} Python {b} tensorflow'#.(a=3.6, b=2)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "def greet(k,v):\n", " return f\"hello {k} in work {v}\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "units = {\n", " \"15ml\":[\"1큰술\",\"1T\",\"1Ts\",\"3t\"],\n", " \"5ml\":[\"1작은술\",\"1t\",\"1ts\"], \n", " \"200ml\":[\"1컵\",\"1Cup\",\"1C\"],\n", " \"250ml\":[\"16T\", \"1C\"],\n", " \"180ml\":[\"1종이컵\"],\n", " \"28.3g\":[\"1oz\"],\n", " \"453g\":[\"1파운드\",\"lb\"],\n", " \"3780ml\":[\"1갤런\",\"gallon\"],\n", " \"2g\":[\"1꼬집\",'약간'],\n", " \"4g\":[\"조금\"],\n", " \"6g\":[\"조금\"],\n", " \"10g\":[\"적당량\"],\n", " \"50g\":[\"1줌\"], # 나물\n", " \"100g\":[\"1큰줌\"], # 나물\n", " \"13마리\":[\"1줌\"], # 멸치\n", " \"26마리\":[\"1큰줌\"], # 멸치\n", " \"100g\":[\"1주먹\"], # 여자 어른의 주먹크기\n", " \"3cm\":[\"1토막\"],\n", " \"1알\":[\"1톨\",\"1쪽\"], # 마늘, 생강 등\n", " \"600g\":[\"1근\"], # 고기\n", " \"400g\":[\"1근\"], # 채소\n", " \"200g\":[\"1봉지\"],\n", "}\n", "\n", "unit_tokens = []\n", "for _ in [v for k,v in units.items()]:\n", " unit_tokens += _\n", "\", \".join(sorted(set(unit_tokens)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# **식약처 레시피로 이름구분 및 단위 기준 전처리**\n", "레시피 데이터 전처리 및 단위기준 일치사전 만들기\n", "```\n", "계량법 안내\n", "1큰술(1T, 1Ts) = 1숟가락 \t15ml = 3t (밥숟가락 뜨면 1큰술)\n", "1작은술(1t, 1ts) 5ml (티스푼으로는 2스푼이 1작은술)\n", "1컵(1Cup, 1C) \t200ml = 16T (한국,중국,일본) (서양(미국)은 1C가 240~250ml)\n", "1종이컵 \t180ml; 1oz \t28.3g\n", "1파운드(lb) \t약 0.453 킬로그램(kg)\n", "1갤런(gallon) \t약 3.78 리터(ℓ)\n", "1꼬집 \t약 2g 정도이며 '약간'이라고 표현하기도 함\n", "조금 \t약간의 2~3배\n", "적당량 \t기호에 따라 마음대로 조절해서 넣으란 표현\n", "1줌 \t 한손 가득 (예시 : 멸치 1줌 = 국멸치인 경우 12~15마리, 나물 1줌은 50g) 크게 1줌 = 2줌 [1줌의 두배]\n", "1주먹 \t여자 어른의 주먹크기, 고기로는 100g\n", "1토막 \t2~3cm두께 정도의 분량\n", "마늘 1톨 \t깐 마늘 한쪽\n", "생강 1쪽 \t마늘 1톨의 크기와 비슷\n", "생강 1톨 \t아기 손바닥만한 크기의 통생강 1개\n", "고기 1근 \t600g\n", "채소 1근 \t400g\n", "채소 1봉지 \t200g 정도\n", "```" ] } ], "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.9" } }, "nbformat": 4, "nbformat_minor": 4 }